Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/fs/ufs/truncate.c | |
3 | * | |
4 | * Copyright (C) 1998 | |
5 | * Daniel Pirkl <daniel.pirkl@email.cz> | |
6 | * Charles University, Faculty of Mathematics and Physics | |
7 | * | |
8 | * from | |
9 | * | |
10 | * linux/fs/ext2/truncate.c | |
11 | * | |
12 | * Copyright (C) 1992, 1993, 1994, 1995 | |
13 | * Remy Card (card@masi.ibp.fr) | |
14 | * Laboratoire MASI - Institut Blaise Pascal | |
15 | * Universite Pierre et Marie Curie (Paris VI) | |
16 | * | |
17 | * from | |
18 | * | |
19 | * linux/fs/minix/truncate.c | |
20 | * | |
21 | * Copyright (C) 1991, 1992 Linus Torvalds | |
22 | * | |
23 | * Big-endian to little-endian byte-swapping/bitmaps by | |
24 | * David S. Miller (davem@caip.rutgers.edu), 1995 | |
25 | */ | |
26 | ||
27 | /* | |
28 | * Real random numbers for secure rm added 94/02/18 | |
29 | * Idea from Pierre del Perugia <delperug@gla.ecoledoc.ibp.fr> | |
30 | */ | |
31 | ||
09114eb8 ED |
32 | /* |
33 | * Modified to avoid infinite loop on 2006 by | |
34 | * Evgeniy Dushistov <dushistov@mail.ru> | |
35 | */ | |
36 | ||
1da177e4 LT |
37 | #include <linux/errno.h> |
38 | #include <linux/fs.h> | |
39 | #include <linux/ufs_fs.h> | |
40 | #include <linux/fcntl.h> | |
41 | #include <linux/time.h> | |
42 | #include <linux/stat.h> | |
43 | #include <linux/string.h> | |
44 | #include <linux/smp_lock.h> | |
45 | #include <linux/buffer_head.h> | |
46 | #include <linux/blkdev.h> | |
47 | #include <linux/sched.h> | |
48 | ||
49 | #include "swab.h" | |
50 | #include "util.h" | |
51 | ||
1da177e4 LT |
52 | /* |
53 | * Secure deletion currently doesn't work. It interacts very badly | |
54 | * with buffers shared with memory mappings, and for that reason | |
55 | * can't be done in the truncate() routines. It should instead be | |
56 | * done separately in "release()" before calling the truncate routines | |
57 | * that will release the actual file blocks. | |
58 | * | |
59 | * Linus | |
60 | */ | |
61 | ||
62 | #define DIRECT_BLOCK ((inode->i_size + uspi->s_bsize - 1) >> uspi->s_bshift) | |
63 | #define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift) | |
64 | ||
1da177e4 LT |
65 | |
66 | static int ufs_trunc_direct (struct inode * inode) | |
67 | { | |
68 | struct ufs_inode_info *ufsi = UFS_I(inode); | |
69 | struct super_block * sb; | |
70 | struct ufs_sb_private_info * uspi; | |
1da177e4 LT |
71 | __fs32 * p; |
72 | unsigned frag1, frag2, frag3, frag4, block1, block2; | |
73 | unsigned frag_to_free, free_count; | |
09114eb8 | 74 | unsigned i, tmp; |
1da177e4 LT |
75 | int retry; |
76 | ||
abf5d15f | 77 | UFSD("ENTER\n"); |
1da177e4 LT |
78 | |
79 | sb = inode->i_sb; | |
80 | uspi = UFS_SB(sb)->s_uspi; | |
81 | ||
82 | frag_to_free = 0; | |
83 | free_count = 0; | |
84 | retry = 0; | |
85 | ||
86 | frag1 = DIRECT_FRAGMENT; | |
87 | frag4 = min_t(u32, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag); | |
88 | frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1); | |
89 | frag3 = frag4 & ~uspi->s_fpbmask; | |
90 | block1 = block2 = 0; | |
91 | if (frag2 > frag3) { | |
92 | frag2 = frag4; | |
93 | frag3 = frag4 = 0; | |
94 | } | |
95 | else if (frag2 < frag3) { | |
96 | block1 = ufs_fragstoblks (frag2); | |
97 | block2 = ufs_fragstoblks (frag3); | |
98 | } | |
99 | ||
abf5d15f | 100 | UFSD("frag1 %u, frag2 %u, block1 %u, block2 %u, frag3 %u, frag4 %u\n", frag1, frag2, block1, block2, frag3, frag4); |
1da177e4 LT |
101 | |
102 | if (frag1 >= frag2) | |
103 | goto next1; | |
104 | ||
105 | /* | |
106 | * Free first free fragments | |
107 | */ | |
108 | p = ufsi->i_u1.i_data + ufs_fragstoblks (frag1); | |
109 | tmp = fs32_to_cpu(sb, *p); | |
110 | if (!tmp ) | |
111 | ufs_panic (sb, "ufs_trunc_direct", "internal error"); | |
112 | frag1 = ufs_fragnum (frag1); | |
113 | frag2 = ufs_fragnum (frag2); | |
09114eb8 | 114 | |
1da177e4 | 115 | ufs_free_fragments (inode, tmp + frag1, frag2 - frag1); |
50aa4eb0 | 116 | mark_inode_dirty(inode); |
1da177e4 LT |
117 | frag_to_free = tmp + frag1; |
118 | ||
119 | next1: | |
120 | /* | |
121 | * Free whole blocks | |
122 | */ | |
123 | for (i = block1 ; i < block2; i++) { | |
124 | p = ufsi->i_u1.i_data + i; | |
125 | tmp = fs32_to_cpu(sb, *p); | |
126 | if (!tmp) | |
127 | continue; | |
09114eb8 | 128 | |
1da177e4 | 129 | *p = 0; |
50aa4eb0 | 130 | |
1da177e4 LT |
131 | if (free_count == 0) { |
132 | frag_to_free = tmp; | |
133 | free_count = uspi->s_fpb; | |
134 | } else if (free_count > 0 && frag_to_free == tmp - free_count) | |
135 | free_count += uspi->s_fpb; | |
136 | else { | |
137 | ufs_free_blocks (inode, frag_to_free, free_count); | |
138 | frag_to_free = tmp; | |
139 | free_count = uspi->s_fpb; | |
140 | } | |
50aa4eb0 | 141 | mark_inode_dirty(inode); |
1da177e4 LT |
142 | } |
143 | ||
144 | if (free_count > 0) | |
145 | ufs_free_blocks (inode, frag_to_free, free_count); | |
146 | ||
147 | if (frag3 >= frag4) | |
148 | goto next3; | |
149 | ||
150 | /* | |
151 | * Free last free fragments | |
152 | */ | |
153 | p = ufsi->i_u1.i_data + ufs_fragstoblks (frag3); | |
154 | tmp = fs32_to_cpu(sb, *p); | |
155 | if (!tmp ) | |
156 | ufs_panic(sb, "ufs_truncate_direct", "internal error"); | |
157 | frag4 = ufs_fragnum (frag4); | |
09114eb8 | 158 | |
1da177e4 | 159 | *p = 0; |
50aa4eb0 | 160 | |
1da177e4 | 161 | ufs_free_fragments (inode, tmp, frag4); |
50aa4eb0 | 162 | mark_inode_dirty(inode); |
1da177e4 LT |
163 | next3: |
164 | ||
abf5d15f | 165 | UFSD("EXIT\n"); |
1da177e4 LT |
166 | return retry; |
167 | } | |
168 | ||
169 | ||
170 | static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p) | |
171 | { | |
172 | struct super_block * sb; | |
173 | struct ufs_sb_private_info * uspi; | |
174 | struct ufs_buffer_head * ind_ubh; | |
1da177e4 | 175 | __fs32 * ind; |
09114eb8 | 176 | unsigned indirect_block, i, tmp; |
1da177e4 LT |
177 | unsigned frag_to_free, free_count; |
178 | int retry; | |
179 | ||
abf5d15f | 180 | UFSD("ENTER\n"); |
1da177e4 LT |
181 | |
182 | sb = inode->i_sb; | |
183 | uspi = UFS_SB(sb)->s_uspi; | |
184 | ||
185 | frag_to_free = 0; | |
186 | free_count = 0; | |
187 | retry = 0; | |
188 | ||
189 | tmp = fs32_to_cpu(sb, *p); | |
190 | if (!tmp) | |
191 | return 0; | |
192 | ind_ubh = ubh_bread(sb, tmp, uspi->s_bsize); | |
193 | if (tmp != fs32_to_cpu(sb, *p)) { | |
194 | ubh_brelse (ind_ubh); | |
195 | return 1; | |
196 | } | |
197 | if (!ind_ubh) { | |
198 | *p = 0; | |
199 | return 0; | |
200 | } | |
201 | ||
202 | indirect_block = (DIRECT_BLOCK > offset) ? (DIRECT_BLOCK - offset) : 0; | |
203 | for (i = indirect_block; i < uspi->s_apb; i++) { | |
204 | ind = ubh_get_addr32 (ind_ubh, i); | |
205 | tmp = fs32_to_cpu(sb, *ind); | |
206 | if (!tmp) | |
207 | continue; | |
09114eb8 | 208 | |
1da177e4 LT |
209 | *ind = 0; |
210 | ubh_mark_buffer_dirty(ind_ubh); | |
211 | if (free_count == 0) { | |
212 | frag_to_free = tmp; | |
213 | free_count = uspi->s_fpb; | |
214 | } else if (free_count > 0 && frag_to_free == tmp - free_count) | |
215 | free_count += uspi->s_fpb; | |
216 | else { | |
217 | ufs_free_blocks (inode, frag_to_free, free_count); | |
218 | frag_to_free = tmp; | |
219 | free_count = uspi->s_fpb; | |
220 | } | |
50aa4eb0 | 221 | |
1da177e4 | 222 | mark_inode_dirty(inode); |
1da177e4 LT |
223 | } |
224 | ||
225 | if (free_count > 0) { | |
226 | ufs_free_blocks (inode, frag_to_free, free_count); | |
227 | } | |
228 | for (i = 0; i < uspi->s_apb; i++) | |
229 | if (*ubh_get_addr32(ind_ubh,i)) | |
230 | break; | |
231 | if (i >= uspi->s_apb) { | |
2061df0f ED |
232 | tmp = fs32_to_cpu(sb, *p); |
233 | *p = 0; | |
50aa4eb0 | 234 | |
2061df0f | 235 | ufs_free_blocks (inode, tmp, uspi->s_fpb); |
50aa4eb0 | 236 | mark_inode_dirty(inode); |
2061df0f ED |
237 | ubh_bforget(ind_ubh); |
238 | ind_ubh = NULL; | |
1da177e4 LT |
239 | } |
240 | if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) { | |
098d5af7 | 241 | ubh_ll_rw_block(SWRITE, ind_ubh); |
1da177e4 LT |
242 | ubh_wait_on_buffer (ind_ubh); |
243 | } | |
244 | ubh_brelse (ind_ubh); | |
245 | ||
abf5d15f | 246 | UFSD("EXIT\n"); |
1da177e4 LT |
247 | |
248 | return retry; | |
249 | } | |
250 | ||
251 | static int ufs_trunc_dindirect (struct inode *inode, unsigned offset, __fs32 *p) | |
252 | { | |
253 | struct super_block * sb; | |
254 | struct ufs_sb_private_info * uspi; | |
255 | struct ufs_buffer_head * dind_bh; | |
256 | unsigned i, tmp, dindirect_block; | |
257 | __fs32 * dind; | |
258 | int retry = 0; | |
259 | ||
abf5d15f | 260 | UFSD("ENTER\n"); |
1da177e4 LT |
261 | |
262 | sb = inode->i_sb; | |
263 | uspi = UFS_SB(sb)->s_uspi; | |
264 | ||
265 | dindirect_block = (DIRECT_BLOCK > offset) | |
266 | ? ((DIRECT_BLOCK - offset) >> uspi->s_apbshift) : 0; | |
267 | retry = 0; | |
268 | ||
269 | tmp = fs32_to_cpu(sb, *p); | |
270 | if (!tmp) | |
271 | return 0; | |
272 | dind_bh = ubh_bread(sb, tmp, uspi->s_bsize); | |
273 | if (tmp != fs32_to_cpu(sb, *p)) { | |
274 | ubh_brelse (dind_bh); | |
275 | return 1; | |
276 | } | |
277 | if (!dind_bh) { | |
278 | *p = 0; | |
279 | return 0; | |
280 | } | |
281 | ||
282 | for (i = dindirect_block ; i < uspi->s_apb ; i++) { | |
283 | dind = ubh_get_addr32 (dind_bh, i); | |
284 | tmp = fs32_to_cpu(sb, *dind); | |
285 | if (!tmp) | |
286 | continue; | |
287 | retry |= ufs_trunc_indirect (inode, offset + (i << uspi->s_apbshift), dind); | |
288 | ubh_mark_buffer_dirty(dind_bh); | |
289 | } | |
290 | ||
291 | for (i = 0; i < uspi->s_apb; i++) | |
292 | if (*ubh_get_addr32 (dind_bh, i)) | |
293 | break; | |
294 | if (i >= uspi->s_apb) { | |
2061df0f ED |
295 | tmp = fs32_to_cpu(sb, *p); |
296 | *p = 0; | |
50aa4eb0 ED |
297 | |
298 | ufs_free_blocks(inode, tmp, uspi->s_fpb); | |
2061df0f | 299 | mark_inode_dirty(inode); |
2061df0f ED |
300 | ubh_bforget(dind_bh); |
301 | dind_bh = NULL; | |
1da177e4 LT |
302 | } |
303 | if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) { | |
098d5af7 | 304 | ubh_ll_rw_block(SWRITE, dind_bh); |
1da177e4 LT |
305 | ubh_wait_on_buffer (dind_bh); |
306 | } | |
307 | ubh_brelse (dind_bh); | |
308 | ||
abf5d15f | 309 | UFSD("EXIT\n"); |
1da177e4 LT |
310 | |
311 | return retry; | |
312 | } | |
313 | ||
314 | static int ufs_trunc_tindirect (struct inode * inode) | |
315 | { | |
316 | struct ufs_inode_info *ufsi = UFS_I(inode); | |
317 | struct super_block * sb; | |
318 | struct ufs_sb_private_info * uspi; | |
319 | struct ufs_buffer_head * tind_bh; | |
320 | unsigned tindirect_block, tmp, i; | |
321 | __fs32 * tind, * p; | |
322 | int retry; | |
323 | ||
abf5d15f | 324 | UFSD("ENTER\n"); |
1da177e4 LT |
325 | |
326 | sb = inode->i_sb; | |
327 | uspi = UFS_SB(sb)->s_uspi; | |
328 | retry = 0; | |
329 | ||
330 | tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb)) | |
331 | ? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) >> uspi->s_2apbshift) : 0; | |
332 | p = ufsi->i_u1.i_data + UFS_TIND_BLOCK; | |
333 | if (!(tmp = fs32_to_cpu(sb, *p))) | |
334 | return 0; | |
335 | tind_bh = ubh_bread (sb, tmp, uspi->s_bsize); | |
336 | if (tmp != fs32_to_cpu(sb, *p)) { | |
337 | ubh_brelse (tind_bh); | |
338 | return 1; | |
339 | } | |
340 | if (!tind_bh) { | |
341 | *p = 0; | |
342 | return 0; | |
343 | } | |
344 | ||
345 | for (i = tindirect_block ; i < uspi->s_apb ; i++) { | |
346 | tind = ubh_get_addr32 (tind_bh, i); | |
347 | retry |= ufs_trunc_dindirect(inode, UFS_NDADDR + | |
348 | uspi->s_apb + ((i + 1) << uspi->s_2apbshift), tind); | |
349 | ubh_mark_buffer_dirty(tind_bh); | |
350 | } | |
351 | for (i = 0; i < uspi->s_apb; i++) | |
352 | if (*ubh_get_addr32 (tind_bh, i)) | |
353 | break; | |
354 | if (i >= uspi->s_apb) { | |
2061df0f ED |
355 | tmp = fs32_to_cpu(sb, *p); |
356 | *p = 0; | |
50aa4eb0 ED |
357 | |
358 | ufs_free_blocks(inode, tmp, uspi->s_fpb); | |
2061df0f | 359 | mark_inode_dirty(inode); |
2061df0f ED |
360 | ubh_bforget(tind_bh); |
361 | tind_bh = NULL; | |
1da177e4 LT |
362 | } |
363 | if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) { | |
098d5af7 | 364 | ubh_ll_rw_block(SWRITE, tind_bh); |
1da177e4 LT |
365 | ubh_wait_on_buffer (tind_bh); |
366 | } | |
367 | ubh_brelse (tind_bh); | |
368 | ||
abf5d15f | 369 | UFSD("EXIT\n"); |
1da177e4 LT |
370 | return retry; |
371 | } | |
372 | ||
373 | void ufs_truncate (struct inode * inode) | |
374 | { | |
375 | struct ufs_inode_info *ufsi = UFS_I(inode); | |
376 | struct super_block * sb; | |
377 | struct ufs_sb_private_info * uspi; | |
09114eb8 | 378 | int retry; |
1da177e4 | 379 | |
abf5d15f | 380 | UFSD("ENTER\n"); |
1da177e4 LT |
381 | sb = inode->i_sb; |
382 | uspi = UFS_SB(sb)->s_uspi; | |
383 | ||
384 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) | |
385 | return; | |
386 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) | |
387 | return; | |
09114eb8 ED |
388 | |
389 | block_truncate_page(inode->i_mapping, inode->i_size, ufs_getfrag_block); | |
390 | ||
1da177e4 LT |
391 | lock_kernel(); |
392 | while (1) { | |
393 | retry = ufs_trunc_direct(inode); | |
394 | retry |= ufs_trunc_indirect (inode, UFS_IND_BLOCK, | |
395 | (__fs32 *) &ufsi->i_u1.i_data[UFS_IND_BLOCK]); | |
396 | retry |= ufs_trunc_dindirect (inode, UFS_IND_BLOCK + uspi->s_apb, | |
397 | (__fs32 *) &ufsi->i_u1.i_data[UFS_DIND_BLOCK]); | |
398 | retry |= ufs_trunc_tindirect (inode); | |
399 | if (!retry) | |
400 | break; | |
401 | if (IS_SYNC(inode) && (inode->i_state & I_DIRTY)) | |
402 | ufs_sync_inode (inode); | |
403 | blk_run_address_space(inode->i_mapping); | |
404 | yield(); | |
405 | } | |
09114eb8 | 406 | |
1da177e4 LT |
407 | inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; |
408 | ufsi->i_lastfrag = DIRECT_FRAGMENT; | |
409 | unlock_kernel(); | |
410 | mark_inode_dirty(inode); | |
abf5d15f | 411 | UFSD("EXIT\n"); |
1da177e4 | 412 | } |