diff options
author | Eric Whitney <enwlinux@gmail.com> | 2014-11-23 00:59:39 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2014-11-23 00:59:39 -0500 |
commit | 0756b908a364c217bc2d8063783992ffe338b143 (patch) | |
tree | d5c5effc3d6364c00ed9389c4299a4bf1890a834 /fs/ext4 | |
parent | 345ee947482f1c787b31014008586b8f512af1bd (diff) | |
download | linux-riscv-0756b908a364c217bc2d8063783992ffe338b143.tar.gz linux-riscv-0756b908a364c217bc2d8063783992ffe338b143.tar.bz2 linux-riscv-0756b908a364c217bc2d8063783992ffe338b143.zip |
ext4: fix end of region partial cluster handling
ext4_ext_remove_space() can incorrectly free a partial_cluster if
EAGAIN is encountered while truncating or punching. Extent removal
should be retried in this case.
It also fails to free a partial cluster when the punched region begins
at the start of a file on that unaligned cluster and where the entire
file has not been punched. Remove the requirement that all blocks in
the file must have been freed in order to free the partial cluster.
Signed-off-by: Eric Whitney <enwlinux@gmail.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/extents.c | 16 |
1 files changed, 9 insertions, 7 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 841adf05e287..9eae2f4916ce 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3009,16 +3009,18 @@ again: trace_ext4_ext_remove_space_done(inode, start, end, depth, partial_cluster, path->p_hdr->eh_entries); - /* If we still have something in the partial cluster and we have removed + /* + * If we still have something in the partial cluster and we have removed * even the first extent, then we should free the blocks in the partial - * cluster as well. */ - if (partial_cluster > 0 && path->p_hdr->eh_entries == 0) { - int flags = get_default_free_blocks_flags(inode); - + * cluster as well. (This code will only run when there are no leaves + * to the immediate left of the truncated/punched region.) + */ + if (partial_cluster > 0 && err == 0) { + /* don't zero partial_cluster since it's not used afterwards */ ext4_free_blocks(handle, inode, NULL, EXT4_C2B(sbi, partial_cluster), - sbi->s_cluster_ratio, flags); - partial_cluster = 0; + sbi->s_cluster_ratio, + get_default_free_blocks_flags(inode)); } /* TODO: flexible tree reduction should be here */ |