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 | 32 | /* |
54fb996a ED |
33 | * Adoptation to use page cache and UFS2 write support by |
34 | * Evgeniy Dushistov <dushistov@mail.ru>, 2006-2007 | |
09114eb8 ED |
35 | */ |
36 | ||
1da177e4 LT |
37 | #include <linux/errno.h> |
38 | #include <linux/fs.h> | |
1da177e4 LT |
39 | #include <linux/fcntl.h> |
40 | #include <linux/time.h> | |
41 | #include <linux/stat.h> | |
42 | #include <linux/string.h> | |
43 | #include <linux/smp_lock.h> | |
44 | #include <linux/buffer_head.h> | |
45 | #include <linux/blkdev.h> | |
46 | #include <linux/sched.h> | |
759bfee6 | 47 | #include <linux/quotaops.h> |
1da177e4 | 48 | |
e5420598 | 49 | #include "ufs_fs.h" |
bcd6d4ec | 50 | #include "ufs.h" |
1da177e4 LT |
51 | #include "swab.h" |
52 | #include "util.h" | |
53 | ||
1da177e4 LT |
54 | /* |
55 | * Secure deletion currently doesn't work. It interacts very badly | |
56 | * with buffers shared with memory mappings, and for that reason | |
57 | * can't be done in the truncate() routines. It should instead be | |
58 | * done separately in "release()" before calling the truncate routines | |
59 | * that will release the actual file blocks. | |
60 | * | |
61 | * Linus | |
62 | */ | |
63 | ||
64 | #define DIRECT_BLOCK ((inode->i_size + uspi->s_bsize - 1) >> uspi->s_bshift) | |
65 | #define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift) | |
66 | ||
1da177e4 | 67 | |
54fb996a | 68 | static int ufs_trunc_direct(struct inode *inode) |
1da177e4 LT |
69 | { |
70 | struct ufs_inode_info *ufsi = UFS_I(inode); | |
71 | struct super_block * sb; | |
72 | struct ufs_sb_private_info * uspi; | |
54fb996a ED |
73 | void *p; |
74 | u64 frag1, frag2, frag3, frag4, block1, block2; | |
1da177e4 | 75 | unsigned frag_to_free, free_count; |
09114eb8 | 76 | unsigned i, tmp; |
1da177e4 LT |
77 | int retry; |
78 | ||
4b25a37e | 79 | UFSD("ENTER: ino %lu\n", inode->i_ino); |
1da177e4 LT |
80 | |
81 | sb = inode->i_sb; | |
82 | uspi = UFS_SB(sb)->s_uspi; | |
83 | ||
84 | frag_to_free = 0; | |
85 | free_count = 0; | |
86 | retry = 0; | |
87 | ||
88 | frag1 = DIRECT_FRAGMENT; | |
89 | frag4 = min_t(u32, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag); | |
90 | frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1); | |
91 | frag3 = frag4 & ~uspi->s_fpbmask; | |
92 | block1 = block2 = 0; | |
93 | if (frag2 > frag3) { | |
94 | frag2 = frag4; | |
95 | frag3 = frag4 = 0; | |
54fb996a | 96 | } else if (frag2 < frag3) { |
1da177e4 LT |
97 | block1 = ufs_fragstoblks (frag2); |
98 | block2 = ufs_fragstoblks (frag3); | |
99 | } | |
100 | ||
4b25a37e ED |
101 | UFSD("ino %lu, frag1 %llu, frag2 %llu, block1 %llu, block2 %llu," |
102 | " frag3 %llu, frag4 %llu\n", inode->i_ino, | |
54fb996a ED |
103 | (unsigned long long)frag1, (unsigned long long)frag2, |
104 | (unsigned long long)block1, (unsigned long long)block2, | |
105 | (unsigned long long)frag3, (unsigned long long)frag4); | |
1da177e4 LT |
106 | |
107 | if (frag1 >= frag2) | |
108 | goto next1; | |
109 | ||
110 | /* | |
111 | * Free first free fragments | |
112 | */ | |
54fb996a ED |
113 | p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag1)); |
114 | tmp = ufs_data_ptr_to_cpu(sb, p); | |
1da177e4 LT |
115 | if (!tmp ) |
116 | ufs_panic (sb, "ufs_trunc_direct", "internal error"); | |
8682164a | 117 | frag2 -= frag1; |
1da177e4 | 118 | frag1 = ufs_fragnum (frag1); |
09114eb8 | 119 | |
8682164a | 120 | ufs_free_fragments(inode, tmp + frag1, frag2); |
50aa4eb0 | 121 | mark_inode_dirty(inode); |
1da177e4 LT |
122 | frag_to_free = tmp + frag1; |
123 | ||
124 | next1: | |
125 | /* | |
126 | * Free whole blocks | |
127 | */ | |
128 | for (i = block1 ; i < block2; i++) { | |
54fb996a ED |
129 | p = ufs_get_direct_data_ptr(uspi, ufsi, i); |
130 | tmp = ufs_data_ptr_to_cpu(sb, p); | |
1da177e4 LT |
131 | if (!tmp) |
132 | continue; | |
54fb996a | 133 | ufs_data_ptr_clear(uspi, p); |
50aa4eb0 | 134 | |
1da177e4 LT |
135 | if (free_count == 0) { |
136 | frag_to_free = tmp; | |
137 | free_count = uspi->s_fpb; | |
138 | } else if (free_count > 0 && frag_to_free == tmp - free_count) | |
139 | free_count += uspi->s_fpb; | |
140 | else { | |
141 | ufs_free_blocks (inode, frag_to_free, free_count); | |
142 | frag_to_free = tmp; | |
143 | free_count = uspi->s_fpb; | |
144 | } | |
50aa4eb0 | 145 | mark_inode_dirty(inode); |
1da177e4 LT |
146 | } |
147 | ||
148 | if (free_count > 0) | |
149 | ufs_free_blocks (inode, frag_to_free, free_count); | |
150 | ||
151 | if (frag3 >= frag4) | |
152 | goto next3; | |
153 | ||
154 | /* | |
155 | * Free last free fragments | |
156 | */ | |
54fb996a ED |
157 | p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag3)); |
158 | tmp = ufs_data_ptr_to_cpu(sb, p); | |
1da177e4 LT |
159 | if (!tmp ) |
160 | ufs_panic(sb, "ufs_truncate_direct", "internal error"); | |
161 | frag4 = ufs_fragnum (frag4); | |
54fb996a | 162 | ufs_data_ptr_clear(uspi, p); |
50aa4eb0 | 163 | |
1da177e4 | 164 | ufs_free_fragments (inode, tmp, frag4); |
50aa4eb0 | 165 | mark_inode_dirty(inode); |
1da177e4 LT |
166 | next3: |
167 | ||
4b25a37e | 168 | UFSD("EXIT: ino %lu\n", inode->i_ino); |
1da177e4 LT |
169 | return retry; |
170 | } | |
171 | ||
172 | ||
54fb996a | 173 | static int ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) |
1da177e4 LT |
174 | { |
175 | struct super_block * sb; | |
176 | struct ufs_sb_private_info * uspi; | |
177 | struct ufs_buffer_head * ind_ubh; | |
54fb996a ED |
178 | void *ind; |
179 | u64 tmp, indirect_block, i, frag_to_free; | |
180 | unsigned free_count; | |
1da177e4 LT |
181 | int retry; |
182 | ||
54fb996a ED |
183 | UFSD("ENTER: ino %lu, offset %llu, p: %p\n", |
184 | inode->i_ino, (unsigned long long)offset, p); | |
185 | ||
186 | BUG_ON(!p); | |
1da177e4 LT |
187 | |
188 | sb = inode->i_sb; | |
189 | uspi = UFS_SB(sb)->s_uspi; | |
190 | ||
191 | frag_to_free = 0; | |
192 | free_count = 0; | |
193 | retry = 0; | |
194 | ||
54fb996a | 195 | tmp = ufs_data_ptr_to_cpu(sb, p); |
1da177e4 LT |
196 | if (!tmp) |
197 | return 0; | |
198 | ind_ubh = ubh_bread(sb, tmp, uspi->s_bsize); | |
54fb996a | 199 | if (tmp != ufs_data_ptr_to_cpu(sb, p)) { |
1da177e4 LT |
200 | ubh_brelse (ind_ubh); |
201 | return 1; | |
202 | } | |
203 | if (!ind_ubh) { | |
54fb996a | 204 | ufs_data_ptr_clear(uspi, p); |
1da177e4 LT |
205 | return 0; |
206 | } | |
207 | ||
208 | indirect_block = (DIRECT_BLOCK > offset) ? (DIRECT_BLOCK - offset) : 0; | |
209 | for (i = indirect_block; i < uspi->s_apb; i++) { | |
54fb996a ED |
210 | ind = ubh_get_data_ptr(uspi, ind_ubh, i); |
211 | tmp = ufs_data_ptr_to_cpu(sb, ind); | |
1da177e4 LT |
212 | if (!tmp) |
213 | continue; | |
09114eb8 | 214 | |
54fb996a | 215 | ufs_data_ptr_clear(uspi, ind); |
1da177e4 LT |
216 | ubh_mark_buffer_dirty(ind_ubh); |
217 | if (free_count == 0) { | |
218 | frag_to_free = tmp; | |
219 | free_count = uspi->s_fpb; | |
220 | } else if (free_count > 0 && frag_to_free == tmp - free_count) | |
221 | free_count += uspi->s_fpb; | |
222 | else { | |
223 | ufs_free_blocks (inode, frag_to_free, free_count); | |
224 | frag_to_free = tmp; | |
225 | free_count = uspi->s_fpb; | |
226 | } | |
50aa4eb0 | 227 | |
1da177e4 | 228 | mark_inode_dirty(inode); |
1da177e4 LT |
229 | } |
230 | ||
231 | if (free_count > 0) { | |
232 | ufs_free_blocks (inode, frag_to_free, free_count); | |
233 | } | |
234 | for (i = 0; i < uspi->s_apb; i++) | |
54fb996a ED |
235 | if (!ufs_is_data_ptr_zero(uspi, |
236 | ubh_get_data_ptr(uspi, ind_ubh, i))) | |
1da177e4 LT |
237 | break; |
238 | if (i >= uspi->s_apb) { | |
54fb996a ED |
239 | tmp = ufs_data_ptr_to_cpu(sb, p); |
240 | ufs_data_ptr_clear(uspi, p); | |
50aa4eb0 | 241 | |
2061df0f | 242 | ufs_free_blocks (inode, tmp, uspi->s_fpb); |
50aa4eb0 | 243 | mark_inode_dirty(inode); |
2061df0f ED |
244 | ubh_bforget(ind_ubh); |
245 | ind_ubh = NULL; | |
1da177e4 LT |
246 | } |
247 | if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) { | |
098d5af7 | 248 | ubh_ll_rw_block(SWRITE, ind_ubh); |
1da177e4 LT |
249 | ubh_wait_on_buffer (ind_ubh); |
250 | } | |
251 | ubh_brelse (ind_ubh); | |
252 | ||
4b25a37e | 253 | UFSD("EXIT: ino %lu\n", inode->i_ino); |
1da177e4 LT |
254 | |
255 | return retry; | |
256 | } | |
257 | ||
54fb996a | 258 | static int ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) |
1da177e4 LT |
259 | { |
260 | struct super_block * sb; | |
261 | struct ufs_sb_private_info * uspi; | |
54fb996a ED |
262 | struct ufs_buffer_head *dind_bh; |
263 | u64 i, tmp, dindirect_block; | |
264 | void *dind; | |
1da177e4 LT |
265 | int retry = 0; |
266 | ||
4b25a37e | 267 | UFSD("ENTER: ino %lu\n", inode->i_ino); |
1da177e4 LT |
268 | |
269 | sb = inode->i_sb; | |
270 | uspi = UFS_SB(sb)->s_uspi; | |
271 | ||
272 | dindirect_block = (DIRECT_BLOCK > offset) | |
273 | ? ((DIRECT_BLOCK - offset) >> uspi->s_apbshift) : 0; | |
274 | retry = 0; | |
275 | ||
54fb996a | 276 | tmp = ufs_data_ptr_to_cpu(sb, p); |
1da177e4 LT |
277 | if (!tmp) |
278 | return 0; | |
279 | dind_bh = ubh_bread(sb, tmp, uspi->s_bsize); | |
54fb996a | 280 | if (tmp != ufs_data_ptr_to_cpu(sb, p)) { |
1da177e4 LT |
281 | ubh_brelse (dind_bh); |
282 | return 1; | |
283 | } | |
284 | if (!dind_bh) { | |
54fb996a | 285 | ufs_data_ptr_clear(uspi, p); |
1da177e4 LT |
286 | return 0; |
287 | } | |
288 | ||
289 | for (i = dindirect_block ; i < uspi->s_apb ; i++) { | |
54fb996a ED |
290 | dind = ubh_get_data_ptr(uspi, dind_bh, i); |
291 | tmp = ufs_data_ptr_to_cpu(sb, dind); | |
1da177e4 LT |
292 | if (!tmp) |
293 | continue; | |
294 | retry |= ufs_trunc_indirect (inode, offset + (i << uspi->s_apbshift), dind); | |
295 | ubh_mark_buffer_dirty(dind_bh); | |
296 | } | |
297 | ||
298 | for (i = 0; i < uspi->s_apb; i++) | |
54fb996a ED |
299 | if (!ufs_is_data_ptr_zero(uspi, |
300 | ubh_get_data_ptr(uspi, dind_bh, i))) | |
1da177e4 LT |
301 | break; |
302 | if (i >= uspi->s_apb) { | |
54fb996a ED |
303 | tmp = ufs_data_ptr_to_cpu(sb, p); |
304 | ufs_data_ptr_clear(uspi, p); | |
50aa4eb0 ED |
305 | |
306 | ufs_free_blocks(inode, tmp, uspi->s_fpb); | |
2061df0f | 307 | mark_inode_dirty(inode); |
2061df0f ED |
308 | ubh_bforget(dind_bh); |
309 | dind_bh = NULL; | |
1da177e4 LT |
310 | } |
311 | if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) { | |
098d5af7 | 312 | ubh_ll_rw_block(SWRITE, dind_bh); |
1da177e4 LT |
313 | ubh_wait_on_buffer (dind_bh); |
314 | } | |
315 | ubh_brelse (dind_bh); | |
316 | ||
4b25a37e | 317 | UFSD("EXIT: ino %lu\n", inode->i_ino); |
1da177e4 LT |
318 | |
319 | return retry; | |
320 | } | |
321 | ||
54fb996a | 322 | static int ufs_trunc_tindirect(struct inode *inode) |
1da177e4 | 323 | { |
54fb996a ED |
324 | struct super_block *sb = inode->i_sb; |
325 | struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; | |
1da177e4 | 326 | struct ufs_inode_info *ufsi = UFS_I(inode); |
1da177e4 | 327 | struct ufs_buffer_head * tind_bh; |
54fb996a ED |
328 | u64 tindirect_block, tmp, i; |
329 | void *tind, *p; | |
1da177e4 LT |
330 | int retry; |
331 | ||
4b25a37e | 332 | UFSD("ENTER: ino %lu\n", inode->i_ino); |
1da177e4 | 333 | |
1da177e4 LT |
334 | retry = 0; |
335 | ||
336 | tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb)) | |
337 | ? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) >> uspi->s_2apbshift) : 0; | |
54fb996a ED |
338 | |
339 | p = ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK); | |
340 | if (!(tmp = ufs_data_ptr_to_cpu(sb, p))) | |
1da177e4 LT |
341 | return 0; |
342 | tind_bh = ubh_bread (sb, tmp, uspi->s_bsize); | |
54fb996a | 343 | if (tmp != ufs_data_ptr_to_cpu(sb, p)) { |
1da177e4 LT |
344 | ubh_brelse (tind_bh); |
345 | return 1; | |
346 | } | |
347 | if (!tind_bh) { | |
54fb996a | 348 | ufs_data_ptr_clear(uspi, p); |
1da177e4 LT |
349 | return 0; |
350 | } | |
351 | ||
352 | for (i = tindirect_block ; i < uspi->s_apb ; i++) { | |
0465fc0a | 353 | tind = ubh_get_data_ptr(uspi, tind_bh, i); |
1da177e4 LT |
354 | retry |= ufs_trunc_dindirect(inode, UFS_NDADDR + |
355 | uspi->s_apb + ((i + 1) << uspi->s_2apbshift), tind); | |
356 | ubh_mark_buffer_dirty(tind_bh); | |
357 | } | |
358 | for (i = 0; i < uspi->s_apb; i++) | |
54fb996a ED |
359 | if (!ufs_is_data_ptr_zero(uspi, |
360 | ubh_get_data_ptr(uspi, tind_bh, i))) | |
1da177e4 LT |
361 | break; |
362 | if (i >= uspi->s_apb) { | |
54fb996a ED |
363 | tmp = ufs_data_ptr_to_cpu(sb, p); |
364 | ufs_data_ptr_clear(uspi, p); | |
50aa4eb0 ED |
365 | |
366 | ufs_free_blocks(inode, tmp, uspi->s_fpb); | |
2061df0f | 367 | mark_inode_dirty(inode); |
2061df0f ED |
368 | ubh_bforget(tind_bh); |
369 | tind_bh = NULL; | |
1da177e4 LT |
370 | } |
371 | if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) { | |
098d5af7 | 372 | ubh_ll_rw_block(SWRITE, tind_bh); |
1da177e4 LT |
373 | ubh_wait_on_buffer (tind_bh); |
374 | } | |
375 | ubh_brelse (tind_bh); | |
376 | ||
4b25a37e | 377 | UFSD("EXIT: ino %lu\n", inode->i_ino); |
1da177e4 LT |
378 | return retry; |
379 | } | |
10e5dce0 ED |
380 | |
381 | static int ufs_alloc_lastblock(struct inode *inode) | |
1da177e4 | 382 | { |
10e5dce0 | 383 | int err = 0; |
4b25a37e | 384 | struct super_block *sb = inode->i_sb; |
10e5dce0 | 385 | struct address_space *mapping = inode->i_mapping; |
4b25a37e | 386 | struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; |
54fb996a ED |
387 | unsigned i, end; |
388 | sector_t lastfrag; | |
10e5dce0 ED |
389 | struct page *lastpage; |
390 | struct buffer_head *bh; | |
4b25a37e | 391 | u64 phys64; |
10e5dce0 ED |
392 | |
393 | lastfrag = (i_size_read(inode) + uspi->s_fsize - 1) >> uspi->s_fshift; | |
394 | ||
ecdc6394 | 395 | if (!lastfrag) |
10e5dce0 | 396 | goto out; |
ecdc6394 | 397 | |
10e5dce0 ED |
398 | lastfrag--; |
399 | ||
400 | lastpage = ufs_get_locked_page(mapping, lastfrag >> | |
401 | (PAGE_CACHE_SHIFT - inode->i_blkbits)); | |
402 | if (IS_ERR(lastpage)) { | |
403 | err = -EIO; | |
404 | goto out; | |
405 | } | |
406 | ||
407 | end = lastfrag & ((1 << (PAGE_CACHE_SHIFT - inode->i_blkbits)) - 1); | |
408 | bh = page_buffers(lastpage); | |
409 | for (i = 0; i < end; ++i) | |
410 | bh = bh->b_this_page; | |
411 | ||
ecdc6394 ED |
412 | |
413 | err = ufs_getfrag_block(inode, lastfrag, bh, 1); | |
414 | ||
415 | if (unlikely(err)) | |
416 | goto out_unlock; | |
417 | ||
418 | if (buffer_new(bh)) { | |
419 | clear_buffer_new(bh); | |
420 | unmap_underlying_metadata(bh->b_bdev, | |
421 | bh->b_blocknr); | |
422 | /* | |
423 | * we do not zeroize fragment, because of | |
424 | * if it maped to hole, it already contains zeroes | |
425 | */ | |
426 | set_buffer_uptodate(bh); | |
427 | mark_buffer_dirty(bh); | |
428 | set_page_dirty(lastpage); | |
10e5dce0 | 429 | } |
ecdc6394 | 430 | |
4b25a37e ED |
431 | if (lastfrag >= UFS_IND_FRAGMENT) { |
432 | end = uspi->s_fpb - ufs_fragnum(lastfrag) - 1; | |
433 | phys64 = bh->b_blocknr + 1; | |
434 | for (i = 0; i < end; ++i) { | |
435 | bh = sb_getblk(sb, i + phys64); | |
436 | lock_buffer(bh); | |
437 | memset(bh->b_data, 0, sb->s_blocksize); | |
438 | set_buffer_uptodate(bh); | |
439 | mark_buffer_dirty(bh); | |
440 | unlock_buffer(bh); | |
441 | sync_dirty_buffer(bh); | |
442 | brelse(bh); | |
443 | } | |
444 | } | |
10e5dce0 ED |
445 | out_unlock: |
446 | ufs_put_locked_page(lastpage); | |
447 | out: | |
448 | return err; | |
449 | } | |
450 | ||
451 | int ufs_truncate(struct inode *inode, loff_t old_i_size) | |
452 | { | |
453 | struct ufs_inode_info *ufsi = UFS_I(inode); | |
454 | struct super_block *sb = inode->i_sb; | |
455 | struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; | |
456 | int retry, err = 0; | |
1da177e4 | 457 | |
54fb996a ED |
458 | UFSD("ENTER: ino %lu, i_size: %llu, old_i_size: %llu\n", |
459 | inode->i_ino, (unsigned long long)i_size_read(inode), | |
460 | (unsigned long long)old_i_size); | |
1da177e4 | 461 | |
10e5dce0 ED |
462 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || |
463 | S_ISLNK(inode->i_mode))) | |
464 | return -EINVAL; | |
1da177e4 | 465 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) |
10e5dce0 ED |
466 | return -EPERM; |
467 | ||
ecdc6394 | 468 | err = ufs_alloc_lastblock(inode); |
10e5dce0 | 469 | |
ecdc6394 ED |
470 | if (err) { |
471 | i_size_write(inode, old_i_size); | |
472 | goto out; | |
10e5dce0 | 473 | } |
09114eb8 | 474 | |
10e5dce0 | 475 | block_truncate_page(inode->i_mapping, inode->i_size, ufs_getfrag_block); |
09114eb8 | 476 | |
1da177e4 LT |
477 | lock_kernel(); |
478 | while (1) { | |
479 | retry = ufs_trunc_direct(inode); | |
54fb996a ED |
480 | retry |= ufs_trunc_indirect(inode, UFS_IND_BLOCK, |
481 | ufs_get_direct_data_ptr(uspi, ufsi, | |
482 | UFS_IND_BLOCK)); | |
483 | retry |= ufs_trunc_dindirect(inode, UFS_IND_BLOCK + uspi->s_apb, | |
484 | ufs_get_direct_data_ptr(uspi, ufsi, | |
485 | UFS_DIND_BLOCK)); | |
1da177e4 LT |
486 | retry |= ufs_trunc_tindirect (inode); |
487 | if (!retry) | |
488 | break; | |
489 | if (IS_SYNC(inode) && (inode->i_state & I_DIRTY)) | |
490 | ufs_sync_inode (inode); | |
491 | blk_run_address_space(inode->i_mapping); | |
492 | yield(); | |
493 | } | |
09114eb8 | 494 | |
1da177e4 | 495 | inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; |
ecdc6394 | 496 | ufsi->i_lastfrag = DIRECT_FRAGMENT; |
1da177e4 LT |
497 | unlock_kernel(); |
498 | mark_inode_dirty(inode); | |
10e5dce0 ED |
499 | out: |
500 | UFSD("EXIT: err %d\n", err); | |
501 | return err; | |
1da177e4 | 502 | } |
10e5dce0 ED |
503 | |
504 | ||
505 | /* | |
506 | * We don't define our `inode->i_op->truncate', and call it here, | |
507 | * because of: | |
508 | * - there is no way to know old size | |
509 | * - there is no way inform user about error, if it happens in `truncate' | |
510 | */ | |
511 | static int ufs_setattr(struct dentry *dentry, struct iattr *attr) | |
512 | { | |
513 | struct inode *inode = dentry->d_inode; | |
514 | unsigned int ia_valid = attr->ia_valid; | |
515 | int error; | |
516 | ||
517 | error = inode_change_ok(inode, attr); | |
518 | if (error) | |
519 | return error; | |
520 | ||
759bfee6 CH |
521 | if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || |
522 | (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { | |
b43fa828 | 523 | error = dquot_transfer(inode, attr); |
759bfee6 CH |
524 | if (error) |
525 | return error; | |
526 | } | |
10e5dce0 ED |
527 | if (ia_valid & ATTR_SIZE && |
528 | attr->ia_size != i_size_read(inode)) { | |
529 | loff_t old_i_size = inode->i_size; | |
907f4554 CH |
530 | |
531 | vfs_dq_init(inode); | |
532 | ||
10e5dce0 ED |
533 | error = vmtruncate(inode, attr->ia_size); |
534 | if (error) | |
535 | return error; | |
536 | error = ufs_truncate(inode, old_i_size); | |
537 | if (error) | |
538 | return error; | |
539 | } | |
540 | return inode_setattr(inode, attr); | |
541 | } | |
542 | ||
c5ef1c42 | 543 | const struct inode_operations ufs_file_inode_operations = { |
10e5dce0 ED |
544 | .setattr = ufs_setattr, |
545 | }; |