aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorLukas Czerner <lczerner@redhat.com>2013-05-27 23:32:35 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-05-27 23:32:35 -0400
commitd863dc3614e489e11808f940a612b520ce1dff91 (patch)
tree05a5c67d53e3ce4e2f53cddc3966c0361c1579a9 /fs/ext4
parent5a7203947a1d9b6f3a00a39fda08c2466489555f (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.h4
-rw-r--r--fs/ext4/inode.c120
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);
2096extern void ext4_set_aops(struct inode *inode); 2096extern void ext4_set_aops(struct inode *inode);
2097extern int ext4_writepage_trans_blocks(struct inode *); 2097extern int ext4_writepage_trans_blocks(struct inode *);
2098extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks); 2098extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks);
2099extern int ext4_block_truncate_page(handle_t *handle,
2100 struct address_space *mapping, loff_t from);
2101extern int ext4_block_zero_page_range(handle_t *handle,
2102 struct address_space *mapping, loff_t from, loff_t length);
2099extern int ext4_discard_partial_page_buffers(handle_t *handle, 2103extern 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 */
3579int 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 */
3600int 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
3687unlock:
3688 unlock_page(page);
3689 page_cache_release(page);
3690 return err;
3691}
3692
3573int ext4_can_truncate(struct inode *inode) 3693int ext4_can_truncate(struct inode *inode)
3574{ 3694{
3575 if (S_ISREG(inode->i_mode)) 3695 if (S_ISREG(inode->i_mode))