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 #include <linux/string.h>
28
29 static int ext2_secrm_seed = 152;
30
31 #define RANDOM_INT (ext2_secrm_seed = ext2_secrm_seed * 69069l +1)
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 static int trunc_direct (struct inode * inode)
47 {
48 int i, tmp;
49 unsigned long * p;
50 struct buffer_head * bh;
51 unsigned long block_to_free = 0;
52 unsigned long free_count = 0;
53 int retry = 0;
54 int blocks = inode->i_sb->s_blocksize / 512;
55 #define DIRECT_BLOCK ((inode->i_size + inode->i_sb->s_blocksize - 1) / \
56 inode->i_sb->s_blocksize)
57 int direct_block = DIRECT_BLOCK;
58
59 repeat:
60 for (i = direct_block ; i < EXT2_NDIR_BLOCKS ; i++) {
61 p = inode->u.ext2_i.i_data + i;
62 tmp = *p;
63 if (!tmp)
64 continue;
65 if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL)
66 bh = getblk (inode->i_dev, tmp,
67 inode->i_sb->s_blocksize);
68 else
69 bh = get_hash_table (inode->i_dev, tmp,
70 inode->i_sb->s_blocksize);
71 if (i < direct_block) {
72 brelse (bh);
73 goto repeat;
74 }
75 if ((bh && bh->b_count != 1) || tmp != *p) {
76 retry = 1;
77 brelse (bh);
78 continue;
79 }
80 *p = 0;
81 inode->i_blocks -= blocks;
82 inode->i_dirt = 1;
83 if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
84 memset(bh->b_data, RANDOM_INT, inode->i_sb->s_blocksize);
85 mark_buffer_dirty(bh, 1);
86 }
87 brelse (bh);
88 if (free_count == 0) {
89 block_to_free = tmp;
90 free_count++;
91 } else if (free_count > 0 && block_to_free == tmp - free_count)
92 free_count++;
93 else {
94 ext2_free_blocks (inode->i_sb, block_to_free, free_count);
95 block_to_free = tmp;
96 free_count = 1;
97 }
98
99 }
100 if (free_count > 0)
101 ext2_free_blocks (inode->i_sb, block_to_free, free_count);
102 return retry;
103 }
104
105 static int trunc_indirect (struct inode * inode, int offset, unsigned long * p)
106 {
107 int i, tmp;
108 struct buffer_head * bh;
109 struct buffer_head * ind_bh;
110 unsigned long * ind;
111 unsigned long block_to_free = 0;
112 unsigned long free_count = 0;
113 int retry = 0;
114 int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
115 int blocks = inode->i_sb->s_blocksize / 512;
116 #define INDIRECT_BLOCK ((int)DIRECT_BLOCK - offset)
117 int indirect_block = INDIRECT_BLOCK;
118
119 tmp = *p;
120 if (!tmp)
121 return 0;
122 ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
123 if (tmp != *p) {
124 brelse (ind_bh);
125 return 1;
126 }
127 if (!ind_bh) {
128 *p = 0;
129 return 0;
130 }
131 repeat:
132 for (i = indirect_block ; i < addr_per_block ; i++) {
133 if (i < 0)
134 i = 0;
135 if (i < indirect_block)
136 goto repeat;
137 ind = i + (unsigned long *) ind_bh->b_data;
138 tmp = *ind;
139 if (!tmp)
140 continue;
141 if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL)
142 bh = getblk (inode->i_dev, tmp,
143 inode->i_sb->s_blocksize);
144 else
145 bh = get_hash_table (inode->i_dev, tmp,
146 inode->i_sb->s_blocksize);
147 if (i < indirect_block) {
148 brelse (bh);
149 goto repeat;
150 }
151 if ((bh && bh->b_count != 1) || tmp != *ind) {
152 retry = 1;
153 brelse (bh);
154 continue;
155 }
156 *ind = 0;
157 mark_buffer_dirty(ind_bh, 1);
158 if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
159 memset(bh->b_data, RANDOM_INT, inode->i_sb->s_blocksize);
160 mark_buffer_dirty(bh, 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 mark_buffer_dirty(dind_bh, 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 mark_buffer_dirty(tind_bh, 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 if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
328 return;
329 ext2_discard_prealloc(inode);
330 while (1) {
331 down(&inode->i_sem);
332 retry = trunc_direct(inode);
333 retry |= trunc_indirect (inode, EXT2_IND_BLOCK,
334 (unsigned long *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK]);
335 retry |= trunc_dindirect (inode, EXT2_IND_BLOCK +
336 EXT2_ADDR_PER_BLOCK(inode->i_sb),
337 (unsigned long *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK]);
338 retry |= trunc_tindirect (inode);
339 up(&inode->i_sem);
340 if (!retry)
341 break;
342 if (IS_SYNC(inode) && inode->i_dirt)
343 ext2_sync_inode (inode);
344 current->counter = 0;
345 schedule ();
346 }
347 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
348 inode->i_dirt = 1;
349 }