Skip to content

Commit

Permalink
ext4: fix fsx truncate failure
Browse files Browse the repository at this point in the history
While running extended fsx tests to verify the first
two patches, a similar bug was also found in the
truncate operation.

This bug happens because the truncate routine only zeros
the unblock aligned portion of the last page.  This means
that the block aligned portions of the page appearing after
i_size are left unzeroed, and the buffer heads still mapped.

This bug is corrected by using ext4_discard_partial_page_buffers
in the truncate routine to zero the partial page and unmap
the buffer headers.

Signed-off-by: Allison Henderson <achender@linux.vnet.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
  • Loading branch information
Allison Henderson authored and Theodore Ts'o committed Sep 7, 2011
1 parent decbd91 commit 189e868
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 4 deletions.
13 changes: 11 additions & 2 deletions fs/ext4/extents.c
Original file line number Diff line number Diff line change
Expand Up @@ -3653,6 +3653,7 @@ void ext4_ext_truncate(struct inode *inode)
struct super_block *sb = inode->i_sb;
ext4_lblk_t last_block;
handle_t *handle;
loff_t page_len;
int err = 0;

/*
Expand All @@ -3669,8 +3670,16 @@ void ext4_ext_truncate(struct inode *inode)
if (IS_ERR(handle))
return;

if (inode->i_size & (sb->s_blocksize - 1))
ext4_block_truncate_page(handle, mapping, inode->i_size);
if (inode->i_size % PAGE_CACHE_SIZE != 0) {
page_len = PAGE_CACHE_SIZE -
(inode->i_size & (PAGE_CACHE_SIZE - 1));

err = ext4_discard_partial_page_buffers(handle,
mapping, inode->i_size, page_len, 0);

if (err)
goto out_stop;
}

if (ext4_orphan_add(handle, inode))
goto out_stop;
Expand Down
13 changes: 11 additions & 2 deletions fs/ext4/indirect.c
Original file line number Diff line number Diff line change
Expand Up @@ -1343,7 +1343,9 @@ void ext4_ind_truncate(struct inode *inode)
__le32 nr = 0;
int n = 0;
ext4_lblk_t last_block, max_block;
loff_t page_len;
unsigned blocksize = inode->i_sb->s_blocksize;
int err;

handle = start_transaction(inode);
if (IS_ERR(handle))
Expand All @@ -1354,9 +1356,16 @@ void ext4_ind_truncate(struct inode *inode)
max_block = (EXT4_SB(inode->i_sb)->s_bitmap_maxbytes + blocksize-1)
>> EXT4_BLOCK_SIZE_BITS(inode->i_sb);

if (inode->i_size & (blocksize - 1))
if (ext4_block_truncate_page(handle, mapping, inode->i_size))
if (inode->i_size % PAGE_CACHE_SIZE != 0) {
page_len = PAGE_CACHE_SIZE -
(inode->i_size & (PAGE_CACHE_SIZE - 1));

err = ext4_discard_partial_page_buffers(handle,
mapping, inode->i_size, page_len, 0);

if (err)
goto out_stop;
}

if (last_block != max_block) {
n = ext4_block_to_path(inode, last_block, offsets, NULL);
Expand Down

0 comments on commit 189e868

Please sign in to comment.