diff options
author | Lukas Czerner <lczerner@redhat.com> | 2013-05-27 23:32:35 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2013-05-27 23:32:35 -0400 |
commit | d863dc3614e489e11808f940a612b520ce1dff91 (patch) | |
tree | 05a5c67d53e3ce4e2f53cddc3966c0361c1579a9 /fs/ext4 | |
parent | 5a7203947a1d9b6f3a00a39fda08c2466489555f (diff) |
Revert "ext4: remove no longer used functions in inode.c"
This reverts commit ccb4d7af914e0fe9b2f1022f8ea6c300463fd5e6.
This commit reintroduces functions ext4_block_truncate_page() and
ext4_block_zero_page_range() which has been previously removed in favour
of ext4_discard_partial_page_buffers().
In future commits we want to reintroduce those function and remove
ext4_discard_partial_page_buffers() since it is duplicating some code
and also partially duplicating work of truncate_pagecache_range(),
moreover the old implementation was much clearer.
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/ext4.h | 4 | ||||
-rw-r--r-- | fs/ext4/inode.c | 120 |
2 files changed, 124 insertions, 0 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 5aae3d12d400..9f9719f08490 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -2096,6 +2096,10 @@ extern int ext4_alloc_da_blocks(struct inode *inode); | |||
2096 | extern void ext4_set_aops(struct inode *inode); | 2096 | extern void ext4_set_aops(struct inode *inode); |
2097 | extern int ext4_writepage_trans_blocks(struct inode *); | 2097 | extern int ext4_writepage_trans_blocks(struct inode *); |
2098 | extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks); | 2098 | extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks); |
2099 | extern int ext4_block_truncate_page(handle_t *handle, | ||
2100 | struct address_space *mapping, loff_t from); | ||
2101 | extern int ext4_block_zero_page_range(handle_t *handle, | ||
2102 | struct address_space *mapping, loff_t from, loff_t length); | ||
2099 | extern int ext4_discard_partial_page_buffers(handle_t *handle, | 2103 | extern int ext4_discard_partial_page_buffers(handle_t *handle, |
2100 | struct address_space *mapping, loff_t from, | 2104 | struct address_space *mapping, loff_t from, |
2101 | loff_t length, int flags); | 2105 | loff_t length, int flags); |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 11638d7982c9..9b3380327ae2 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -3570,6 +3570,126 @@ next: | |||
3570 | return err; | 3570 | return err; |
3571 | } | 3571 | } |
3572 | 3572 | ||
3573 | /* | ||
3574 | * ext4_block_truncate_page() zeroes out a mapping from file offset `from' | ||
3575 | * up to the end of the block which corresponds to `from'. | ||
3576 | * This required during truncate. We need to physically zero the tail end | ||
3577 | * of that block so it doesn't yield old data if the file is later grown. | ||
3578 | */ | ||
3579 | int ext4_block_truncate_page(handle_t *handle, | ||
3580 | struct address_space *mapping, loff_t from) | ||
3581 | { | ||
3582 | unsigned offset = from & (PAGE_CACHE_SIZE-1); | ||
3583 | unsigned length; | ||
3584 | unsigned blocksize; | ||
3585 | struct inode *inode = mapping->host; | ||
3586 | |||
3587 | blocksize = inode->i_sb->s_blocksize; | ||
3588 | length = blocksize - (offset & (blocksize - 1)); | ||
3589 | |||
3590 | return ext4_block_zero_page_range(handle, mapping, from, length); | ||
3591 | } | ||
3592 | |||
3593 | /* | ||
3594 | * ext4_block_zero_page_range() zeros out a mapping of length 'length' | ||
3595 | * starting from file offset 'from'. The range to be zero'd must | ||
3596 | * be contained with in one block. If the specified range exceeds | ||
3597 | * the end of the block it will be shortened to end of the block | ||
3598 | * that cooresponds to 'from' | ||
3599 | */ | ||
3600 | int ext4_block_zero_page_range(handle_t *handle, | ||
3601 | struct address_space *mapping, loff_t from, loff_t length) | ||
3602 | { | ||
3603 | ext4_fsblk_t index = from >> PAGE_CACHE_SHIFT; | ||
3604 | unsigned offset = from & (PAGE_CACHE_SIZE-1); | ||
3605 | unsigned blocksize, max, pos; | ||
3606 | ext4_lblk_t iblock; | ||
3607 | struct inode *inode = mapping->host; | ||
3608 | struct buffer_head *bh; | ||
3609 | struct page *page; | ||
3610 | int err = 0; | ||
3611 | |||
3612 | page = find_or_create_page(mapping, from >> PAGE_CACHE_SHIFT, | ||
3613 | mapping_gfp_mask(mapping) & ~__GFP_FS); | ||
3614 | if (!page) | ||
3615 | return -ENOMEM; | ||
3616 | |||
3617 | blocksize = inode->i_sb->s_blocksize; | ||
3618 | max = blocksize - (offset & (blocksize - 1)); | ||
3619 | |||
3620 | /* | ||
3621 | * correct length if it does not fall between | ||
3622 | * 'from' and the end of the block | ||
3623 | */ | ||
3624 | if (length > max || length < 0) | ||
3625 | length = max; | ||
3626 | |||
3627 | iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); | ||
3628 | |||
3629 | if (!page_has_buffers(page)) | ||
3630 | create_empty_buffers(page, blocksize, 0); | ||
3631 | |||
3632 | /* Find the buffer that contains "offset" */ | ||
3633 | bh = page_buffers(page); | ||
3634 | pos = blocksize; | ||
3635 | while (offset >= pos) { | ||
3636 | bh = bh->b_this_page; | ||
3637 | iblock++; | ||
3638 | pos += blocksize; | ||
3639 | } | ||
3640 | |||
3641 | err = 0; | ||
3642 | if (buffer_freed(bh)) { | ||
3643 | BUFFER_TRACE(bh, "freed: skip"); | ||
3644 | goto unlock; | ||
3645 | } | ||
3646 | |||
3647 | if (!buffer_mapped(bh)) { | ||
3648 | BUFFER_TRACE(bh, "unmapped"); | ||
3649 | ext4_get_block(inode, iblock, bh, 0); | ||
3650 | /* unmapped? It's a hole - nothing to do */ | ||
3651 | if (!buffer_mapped(bh)) { | ||
3652 | BUFFER_TRACE(bh, "still unmapped"); | ||
3653 | goto unlock; | ||
3654 | } | ||
3655 | } | ||
3656 | |||
3657 | /* Ok, it's mapped. Make sure it's up-to-date */ | ||
3658 | if (PageUptodate(page)) | ||
3659 | set_buffer_uptodate(bh); | ||
3660 | |||
3661 | if (!buffer_uptodate(bh)) { | ||
3662 | err = -EIO; | ||
3663 | ll_rw_block(READ, 1, &bh); | ||
3664 | wait_on_buffer(bh); | ||
3665 | /* Uhhuh. Read error. Complain and punt. */ | ||
3666 | if (!buffer_uptodate(bh)) | ||
3667 | goto unlock; | ||
3668 | } | ||
3669 | |||
3670 | if (ext4_should_journal_data(inode)) { | ||
3671 | BUFFER_TRACE(bh, "get write access"); | ||
3672 | err = ext4_journal_get_write_access(handle, bh); | ||
3673 | if (err) | ||
3674 | goto unlock; | ||
3675 | } | ||
3676 | |||
3677 | zero_user(page, offset, length); | ||
3678 | |||
3679 | BUFFER_TRACE(bh, "zeroed end of block"); | ||
3680 | |||
3681 | err = 0; | ||
3682 | if (ext4_should_journal_data(inode)) { | ||
3683 | err = ext4_handle_dirty_metadata(handle, inode, bh); | ||
3684 | } else | ||
3685 | mark_buffer_dirty(bh); | ||
3686 | |||
3687 | unlock: | ||
3688 | unlock_page(page); | ||
3689 | page_cache_release(page); | ||
3690 | return err; | ||
3691 | } | ||
3692 | |||
3573 | int ext4_can_truncate(struct inode *inode) | 3693 | int ext4_can_truncate(struct inode *inode) |
3574 | { | 3694 | { |
3575 | if (S_ISREG(inode->i_mode)) | 3695 | if (S_ISREG(inode->i_mode)) |