[PATCH] ufs: truncate correction

1) When we allocated last fragment in ufs_truncate, we read page, check
if block mapped to address, and if not trying to allocate it. This is
wrong behaviour, fragment may be NOT allocated, but mapped, this
happened because of "block map" function not checked allocated fragment
or not, it just take address of the first fragment in the block, add
offset of fragment and return result, this is correct behaviour in
almost all situation except call from ufs_truncate.

2) Almost all implementation of UFS, which I can investigate have such
"defect": if you have full disk, and try truncate file, for example 3GB
to 2MB, and have hole in this region, truncate return -ENOSPC. I tried
evade from this problem, but "block allocation" algorithm is tied to
right value of i_lastfrag, and fix of this corner case may slow down of
ordinaries scenarios, so this patch makes behavior of "truncate"
operations similar to what other UFS implementations do.

Signed-off-by: Evgeniy Dushistov <dushistov@mail.ru>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by Evgeniy Dushistov and committed by Linus Torvalds ecdc6394 c37336b0

+23 -50
+23 -50
fs/ufs/truncate.c
··· 375 int err = 0; 376 struct address_space *mapping = inode->i_mapping; 377 struct ufs_sb_private_info *uspi = UFS_SB(inode->i_sb)->s_uspi; 378 - struct ufs_inode_info *ufsi = UFS_I(inode); 379 unsigned lastfrag, i, end; 380 struct page *lastpage; 381 struct buffer_head *bh; 382 383 lastfrag = (i_size_read(inode) + uspi->s_fsize - 1) >> uspi->s_fshift; 384 385 - if (!lastfrag) { 386 - ufsi->i_lastfrag = 0; 387 goto out; 388 - } 389 lastfrag--; 390 391 lastpage = ufs_get_locked_page(mapping, lastfrag >> ··· 398 for (i = 0; i < end; ++i) 399 bh = bh->b_this_page; 400 401 - if (!buffer_mapped(bh)) { 402 - err = ufs_getfrag_block(inode, lastfrag, bh, 1); 403 404 - if (unlikely(err)) 405 - goto out_unlock; 406 407 - if (buffer_new(bh)) { 408 - clear_buffer_new(bh); 409 - unmap_underlying_metadata(bh->b_bdev, 410 - bh->b_blocknr); 411 - /* 412 - * we do not zeroize fragment, because of 413 - * if it maped to hole, it already contains zeroes 414 - */ 415 - set_buffer_uptodate(bh); 416 - mark_buffer_dirty(bh); 417 - set_page_dirty(lastpage); 418 - } 419 } 420 out_unlock: 421 ufs_put_locked_page(lastpage); 422 out: ··· 438 if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) 439 return -EPERM; 440 441 - if (inode->i_size > old_i_size) { 442 - /* 443 - * if we expand file we should care about 444 - * allocation of block for last byte first of all 445 - */ 446 - err = ufs_alloc_lastblock(inode); 447 448 - if (err) { 449 - i_size_write(inode, old_i_size); 450 - goto out; 451 - } 452 - /* 453 - * go away, because of we expand file, and we do not 454 - * need free blocks, and zeroizes page 455 - */ 456 - lock_kernel(); 457 - goto almost_end; 458 } 459 460 block_truncate_page(inode->i_mapping, inode->i_size, ufs_getfrag_block); ··· 463 yield(); 464 } 465 466 - if (inode->i_size < old_i_size) { 467 - /* 468 - * now we should have enough space 469 - * to allocate block for last byte 470 - */ 471 - err = ufs_alloc_lastblock(inode); 472 - if (err) 473 - /* 474 - * looks like all the same - we have no space, 475 - * but we truncate file already 476 - */ 477 - inode->i_size = (ufsi->i_lastfrag - 1) * uspi->s_fsize; 478 - } 479 - almost_end: 480 inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; 481 unlock_kernel(); 482 mark_inode_dirty(inode); 483 out:
··· 375 int err = 0; 376 struct address_space *mapping = inode->i_mapping; 377 struct ufs_sb_private_info *uspi = UFS_SB(inode->i_sb)->s_uspi; 378 unsigned lastfrag, i, end; 379 struct page *lastpage; 380 struct buffer_head *bh; 381 382 lastfrag = (i_size_read(inode) + uspi->s_fsize - 1) >> uspi->s_fshift; 383 384 + if (!lastfrag) 385 goto out; 386 + 387 lastfrag--; 388 389 lastpage = ufs_get_locked_page(mapping, lastfrag >> ··· 400 for (i = 0; i < end; ++i) 401 bh = bh->b_this_page; 402 403 404 + err = ufs_getfrag_block(inode, lastfrag, bh, 1); 405 406 + if (unlikely(err)) 407 + goto out_unlock; 408 + 409 + if (buffer_new(bh)) { 410 + clear_buffer_new(bh); 411 + unmap_underlying_metadata(bh->b_bdev, 412 + bh->b_blocknr); 413 + /* 414 + * we do not zeroize fragment, because of 415 + * if it maped to hole, it already contains zeroes 416 + */ 417 + set_buffer_uptodate(bh); 418 + mark_buffer_dirty(bh); 419 + set_page_dirty(lastpage); 420 } 421 + 422 out_unlock: 423 ufs_put_locked_page(lastpage); 424 out: ··· 440 if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) 441 return -EPERM; 442 443 + err = ufs_alloc_lastblock(inode); 444 445 + if (err) { 446 + i_size_write(inode, old_i_size); 447 + goto out; 448 } 449 450 block_truncate_page(inode->i_mapping, inode->i_size, ufs_getfrag_block); ··· 477 yield(); 478 } 479 480 inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; 481 + ufsi->i_lastfrag = DIRECT_FRAGMENT; 482 unlock_kernel(); 483 mark_inode_dirty(inode); 484 out: