aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2014-06-26 12:30:54 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-07-09 11:18:27 -0700
commit7c9db4927e4713d0fb071619d2997e2f5a209583 (patch)
treefd80f77c332f41830af1cdb79b2451081aa43aef
parentcbbe137036cec32f997d9dc945b45412a92bad61 (diff)
ext4: Fix hole punching for files with indirect blocks
commit a93cd4cf86466caa49cfe64607bea7f0bde3f916 upstream. Hole punching code for files with indirect blocks wrongly computed number of blocks which need to be cleared when traversing the indirect block tree. That could result in punching more blocks than actually requested and thus effectively cause a data loss. For example: fallocate -n -p 10240000 4096 will punch the range 10240000 - 12632064 instead of the range 1024000 - 10244096. Fix the calculation. Fixes: 8bad6fc813a3a5300f51369c39d315679fd88c72 Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--fs/ext4/indirect.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c
index 3b91d240da4..e6574d7b664 100644
--- a/fs/ext4/indirect.c
+++ b/fs/ext4/indirect.c
@@ -1318,16 +1318,24 @@ static int free_hole_blocks(handle_t *handle, struct inode *inode,
blk = *i_data;
if (level > 0) {
ext4_lblk_t first2;
+ ext4_lblk_t count2;
+
bh = sb_bread(inode->i_sb, le32_to_cpu(blk));
if (!bh) {
EXT4_ERROR_INODE_BLOCK(inode, le32_to_cpu(blk),
"Read failure");
return -EIO;
}
- first2 = (first > offset) ? first - offset : 0;
+ if (first > offset) {
+ first2 = first - offset;
+ count2 = count;
+ } else {
+ first2 = 0;
+ count2 = count - (offset - first);
+ }
ret = free_hole_blocks(handle, inode, bh,
(__le32 *)bh->b_data, level - 1,
- first2, count - offset,
+ first2, count2,
inode->i_sb->s_blocksize >> 2);
if (ret) {
brelse(bh);