aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/indirect.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2014-06-26 12:30:54 -0400
committerTheodore Ts'o <tytso@mit.edu>2014-06-26 12:30:54 -0400
commita93cd4cf86466caa49cfe64607bea7f0bde3f916 (patch)
tree947b96edff05559043b83190cca8a4cc5ed859c6 /fs/ext4/indirect.c
parent77ea2a4ba657a1ad4fb7c64bc5cdce84b8a132b6 (diff)
ext4: Fix hole punching for files with indirect blocks
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. CC: stable@vger.kernel.org Fixes: 8bad6fc813a3a5300f51369c39d315679fd88c72 Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/indirect.c')
-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 6f3bb55567b6..fd69da194826 100644
--- a/fs/ext4/indirect.c
+++ b/fs/ext4/indirect.c
@@ -1316,16 +1316,24 @@ static int free_hole_blocks(handle_t *handle, struct inode *inode,
1316 blk = *i_data; 1316 blk = *i_data;
1317 if (level > 0) { 1317 if (level > 0) {
1318 ext4_lblk_t first2; 1318 ext4_lblk_t first2;
1319 ext4_lblk_t count2;
1320
1319 bh = sb_bread(inode->i_sb, le32_to_cpu(blk)); 1321 bh = sb_bread(inode->i_sb, le32_to_cpu(blk));
1320 if (!bh) { 1322 if (!bh) {
1321 EXT4_ERROR_INODE_BLOCK(inode, le32_to_cpu(blk), 1323 EXT4_ERROR_INODE_BLOCK(inode, le32_to_cpu(blk),
1322 "Read failure"); 1324 "Read failure");
1323 return -EIO; 1325 return -EIO;
1324 } 1326 }
1325 first2 = (first > offset) ? first - offset : 0; 1327 if (first > offset) {
1328 first2 = first - offset;
1329 count2 = count;
1330 } else {
1331 first2 = 0;
1332 count2 = count - (offset - first);
1333 }
1326 ret = free_hole_blocks(handle, inode, bh, 1334 ret = free_hole_blocks(handle, inode, bh,
1327 (__le32 *)bh->b_data, level - 1, 1335 (__le32 *)bh->b_data, level - 1,
1328 first2, count - offset, 1336 first2, count2,
1329 inode->i_sb->s_blocksize >> 2); 1337 inode->i_sb->s_blocksize >> 2);
1330 if (ret) { 1338 if (ret) {
1331 brelse(bh); 1339 brelse(bh);