Skip to content

Commit d863dc3

Browse files
Lukas Czernertytso
authored andcommitted
Revert "ext4: remove no longer used functions in inode.c"
This reverts commit ccb4d7a. 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 <[email protected]> Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 5a72039 commit d863dc3

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

fs/ext4/ext4.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2096,6 +2096,10 @@ extern int ext4_alloc_da_blocks(struct inode *inode);
20962096
extern void ext4_set_aops(struct inode *inode);
20972097
extern int ext4_writepage_trans_blocks(struct inode *);
20982098
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);
20992103
extern int ext4_discard_partial_page_buffers(handle_t *handle,
21002104
struct address_space *mapping, loff_t from,
21012105
loff_t length, int flags);

fs/ext4/inode.c

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3570,6 +3570,126 @@ static int ext4_discard_partial_page_buffers_no_lock(handle_t *handle,
35703570
return err;
35713571
}
35723572

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+
35733693
int ext4_can_truncate(struct inode *inode)
35743694
{
35753695
if (S_ISREG(inode->i_mode))

0 commit comments

Comments
 (0)