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