| From a93cd4cf86466caa49cfe64607bea7f0bde3f916 Mon Sep 17 00:00:00 2001 |
| From: Jan Kara <jack@suse.cz> |
| Date: Thu, 26 Jun 2014 12:30:54 -0400 |
| Subject: ext4: Fix hole punching for files with indirect blocks |
| |
| From: Jan Kara <jack@suse.cz> |
| |
| 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> |
| |
| --- |
| fs/ext4/indirect.c | 12 ++++++++++-- |
| 1 file changed, 10 insertions(+), 2 deletions(-) |
| |
| --- a/fs/ext4/indirect.c |
| +++ b/fs/ext4/indirect.c |
| @@ -1318,16 +1318,24 @@ static int free_hole_blocks(handle_t *ha |
| 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); |