This source file includes following definitions.
- trunc_direct
- trunc_indirect
- trunc_dindirect
- trunc_tindirect
- ext2_truncate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 #include <linux/errno.h>
16 #include <linux/fs.h>
17 #include <linux/ext2_fs.h>
18 #include <linux/fcntl.h>
19 #include <linux/sched.h>
20 #include <linux/stat.h>
21 #include <linux/locks.h>
22
23 #define clear_block(addr,size,value) \
24 __asm__("cld\n\t" \
25 "rep\n\t" \
26 "stosl" \
27 : \
28 :"a" (value), "c" (size / 4), "D" ((long) (addr)) \
29 :"cx", "di")
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 static int trunc_direct (struct inode * inode)
45 {
46 int i, tmp;
47 unsigned long * p;
48 struct buffer_head * bh;
49 unsigned long block_to_free = 0;
50 unsigned long free_count = 0;
51 int retry = 0;
52 int blocks = inode->i_sb->s_blocksize / 512;
53 #define DIRECT_BLOCK ((inode->i_size + inode->i_sb->s_blocksize - 1) / \
54 inode->i_sb->s_blocksize)
55 int direct_block = DIRECT_BLOCK;
56
57 repeat:
58 for (i = direct_block ; i < EXT2_NDIR_BLOCKS ; i++) {
59 p = inode->u.ext2_i.i_data + i;
60 tmp = *p;
61 if (!tmp)
62 continue;
63 if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL)
64 bh = getblk (inode->i_dev, tmp,
65 inode->i_sb->s_blocksize);
66 else
67 bh = get_hash_table (inode->i_dev, tmp,
68 inode->i_sb->s_blocksize);
69 if (i < direct_block) {
70 brelse (bh);
71 goto repeat;
72 }
73 if ((bh && bh->b_count != 1) || tmp != *p) {
74 retry = 1;
75 brelse (bh);
76 continue;
77 }
78 *p = 0;
79 inode->i_blocks -= blocks;
80 inode->i_dirt = 1;
81 if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
82 clear_block (bh->b_data, inode->i_sb->s_blocksize,
83 CURRENT_TIME);
84 bh->b_dirt = 1;
85 }
86 brelse (bh);
87 if (free_count == 0) {
88 block_to_free = tmp;
89 free_count++;
90 } else if (free_count > 0 && block_to_free == tmp - free_count)
91 free_count++;
92 else {
93 ext2_free_blocks (inode->i_sb, block_to_free, free_count);
94 block_to_free = tmp;
95 free_count = 1;
96 }
97
98 }
99 if (free_count > 0)
100 ext2_free_blocks (inode->i_sb, block_to_free, free_count);
101 return retry;
102 }
103
104 static int trunc_indirect (struct inode * inode, int offset, unsigned long * p)
105 {
106 int i, tmp;
107 struct buffer_head * bh;
108 struct buffer_head * ind_bh;
109 unsigned long * ind;
110 unsigned long block_to_free = 0;
111 unsigned long free_count = 0;
112 int retry = 0;
113 int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
114 int blocks = inode->i_sb->s_blocksize / 512;
115 #define INDIRECT_BLOCK ((int)DIRECT_BLOCK - offset)
116 int indirect_block = INDIRECT_BLOCK;
117
118 tmp = *p;
119 if (!tmp)
120 return 0;
121 ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
122 if (tmp != *p) {
123 brelse (ind_bh);
124 return 1;
125 }
126 if (!ind_bh) {
127 *p = 0;
128 return 0;
129 }
130 repeat:
131 for (i = indirect_block ; i < addr_per_block ; i++) {
132 if (i < 0)
133 i = 0;
134 if (i < indirect_block)
135 goto repeat;
136 ind = i + (unsigned long *) ind_bh->b_data;
137 tmp = *ind;
138 if (!tmp)
139 continue;
140 if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL)
141 bh = getblk (inode->i_dev, tmp,
142 inode->i_sb->s_blocksize);
143 else
144 bh = get_hash_table (inode->i_dev, tmp,
145 inode->i_sb->s_blocksize);
146 if (i < indirect_block) {
147 brelse (bh);
148 goto repeat;
149 }
150 if ((bh && bh->b_count != 1) || tmp != *ind) {
151 retry = 1;
152 brelse (bh);
153 continue;
154 }
155 *ind = 0;
156 ind_bh->b_dirt = 1;
157 if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
158 clear_block (bh->b_data, inode->i_sb->s_blocksize,
159 CURRENT_TIME);
160 bh->b_dirt = 1;
161 }
162 brelse (bh);
163 if (free_count == 0) {
164 block_to_free = tmp;
165 free_count++;
166 } else if (free_count > 0 && block_to_free == tmp - free_count)
167 free_count++;
168 else {
169 ext2_free_blocks (inode->i_sb, block_to_free, free_count);
170 block_to_free = tmp;
171 free_count = 1;
172 }
173
174 inode->i_blocks -= blocks;
175 inode->i_dirt = 1;
176 }
177 if (free_count > 0)
178 ext2_free_blocks (inode->i_sb, block_to_free, free_count);
179 ind = (unsigned long *) ind_bh->b_data;
180 for (i = 0; i < addr_per_block; i++)
181 if (*(ind++))
182 break;
183 if (i >= addr_per_block)
184 if (ind_bh->b_count != 1)
185 retry = 1;
186 else {
187 tmp = *p;
188 *p = 0;
189 inode->i_blocks -= blocks;
190 inode->i_dirt = 1;
191 ext2_free_blocks (inode->i_sb, tmp, 1);
192 }
193 if (IS_SYNC(inode) && ind_bh->b_dirt) {
194 ll_rw_block (WRITE, 1, &ind_bh);
195 wait_on_buffer (ind_bh);
196 }
197 brelse (ind_bh);
198 return retry;
199 }
200
201 static int trunc_dindirect (struct inode * inode, int offset,
202 unsigned long * p)
203 {
204 int i, tmp;
205 struct buffer_head * dind_bh;
206 unsigned long * dind;
207 int retry = 0;
208 int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
209 int blocks = inode->i_sb->s_blocksize / 512;
210 #define DINDIRECT_BLOCK (((int)DIRECT_BLOCK - offset) / addr_per_block)
211 int dindirect_block = DINDIRECT_BLOCK;
212
213 tmp = *p;
214 if (!tmp)
215 return 0;
216 dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
217 if (tmp != *p) {
218 brelse (dind_bh);
219 return 1;
220 }
221 if (!dind_bh) {
222 *p = 0;
223 return 0;
224 }
225 repeat:
226 for (i = dindirect_block ; i < addr_per_block ; i++) {
227 if (i < 0)
228 i = 0;
229 if (i < dindirect_block)
230 goto repeat;
231 dind = i + (unsigned long *) dind_bh->b_data;
232 tmp = *dind;
233 if (!tmp)
234 continue;
235 retry |= trunc_indirect (inode, offset + (i * addr_per_block),
236 dind);
237 dind_bh->b_dirt = 1;
238 }
239 dind = (unsigned long *) dind_bh->b_data;
240 for (i = 0; i < addr_per_block; i++)
241 if (*(dind++))
242 break;
243 if (i >= addr_per_block)
244 if (dind_bh->b_count != 1)
245 retry = 1;
246 else {
247 tmp = *p;
248 *p = 0;
249 inode->i_blocks -= blocks;
250 inode->i_dirt = 1;
251 ext2_free_blocks (inode->i_sb, tmp, 1);
252 }
253 if (IS_SYNC(inode) && dind_bh->b_dirt) {
254 ll_rw_block (WRITE, 1, &dind_bh);
255 wait_on_buffer (dind_bh);
256 }
257 brelse (dind_bh);
258 return retry;
259 }
260
261 static int trunc_tindirect (struct inode * inode)
262 {
263 int i, tmp;
264 struct buffer_head * tind_bh;
265 unsigned long * tind, * p;
266 int retry = 0;
267 int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
268 int blocks = inode->i_sb->s_blocksize / 512;
269 #define TINDIRECT_BLOCK (((int)DIRECT_BLOCK - (addr_per_block * addr_per_block + \
270 addr_per_block + EXT2_NDIR_BLOCKS)) / \
271 (addr_per_block * addr_per_block))
272 int tindirect_block = TINDIRECT_BLOCK;
273
274 p = inode->u.ext2_i.i_data + EXT2_TIND_BLOCK;
275 if (!(tmp = *p))
276 return 0;
277 tind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
278 if (tmp != *p) {
279 brelse (tind_bh);
280 return 1;
281 }
282 if (!tind_bh) {
283 *p = 0;
284 return 0;
285 }
286 repeat:
287 for (i = tindirect_block ; i < addr_per_block ; i++) {
288 if (i < 0)
289 i = 0;
290 if (i < tindirect_block)
291 goto repeat;
292 tind = i + (unsigned long *) tind_bh->b_data;
293 retry |= trunc_dindirect(inode, EXT2_NDIR_BLOCKS +
294 addr_per_block + (i + 1) * addr_per_block * addr_per_block,
295 tind);
296 tind_bh->b_dirt = 1;
297 }
298 tind = (unsigned long *) tind_bh->b_data;
299 for (i = 0; i < addr_per_block; i++)
300 if (*(tind++))
301 break;
302 if (i >= addr_per_block)
303 if (tind_bh->b_count != 1)
304 retry = 1;
305 else {
306 tmp = *p;
307 *p = 0;
308 inode->i_blocks -= blocks;
309 inode->i_dirt = 1;
310 ext2_free_blocks (inode->i_sb, tmp, 1);
311 }
312 if (IS_SYNC(inode) && tind_bh->b_dirt) {
313 ll_rw_block (WRITE, 1, &tind_bh);
314 wait_on_buffer (tind_bh);
315 }
316 brelse (tind_bh);
317 return retry;
318 }
319
320 void ext2_truncate (struct inode * inode)
321 {
322 int retry;
323
324 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
325 S_ISLNK(inode->i_mode)))
326 return;
327 ext2_discard_prealloc(inode);
328 while (1) {
329 retry = trunc_direct(inode);
330 retry |= trunc_indirect (inode, EXT2_IND_BLOCK,
331 (unsigned long *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK]);
332 retry |= trunc_dindirect (inode, EXT2_IND_BLOCK +
333 EXT2_ADDR_PER_BLOCK(inode->i_sb),
334 (unsigned long *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK]);
335 retry |= trunc_tindirect (inode);
336 if (!retry)
337 break;
338 if (IS_SYNC(inode) && inode->i_dirt)
339 ext2_sync_inode (inode);
340 current->counter = 0;
341 schedule ();
342 }
343 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
344 inode->i_dirt = 1;
345 }