Skip to content

Commit c063449

Browse files
Eric Whitneytytso
authored andcommitted
ext4: fix partial cluster handling for bigalloc file systems
Commit 9cb0041, which enables hole punching for bigalloc file systems, exposed a bug introduced by commit 6ae06ff in an earlier release. When run on a bigalloc file system, xfstests generic/013, 068, 075, 083, 091, 100, 112, 127, 263, 269, and 270 fail with e2fsck errors or cause kernel error messages indicating that previously freed blocks are being freed again. The latter commit optimizes the selection of the starting extent in ext4_ext_rm_leaf() when hole punching by beginning with the extent supplied in the path argument rather than with the last extent in the leaf node (as is still done when truncating). However, the code in rm_leaf that initially sets partial_cluster to track cluster sharing on extent boundaries is only guaranteed to run if rm_leaf starts with the last node in the leaf. Consequently, partial_cluster is not correctly initialized when hole punching, and a cluster on the boundary of a punched region that should be retained may instead be deallocated. Signed-off-by: Eric Whitney <enwlinux@gmail.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Cc: stable@vger.kernel.org
1 parent 31cf0f2 commit c063449

File tree

1 file changed

+21
-0
lines changed

1 file changed

+21
-0
lines changed

fs/ext4/extents.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2597,6 +2597,27 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
25972597
ex_ee_block = le32_to_cpu(ex->ee_block);
25982598
ex_ee_len = ext4_ext_get_actual_len(ex);
25992599

2600+
/*
2601+
* If we're starting with an extent other than the last one in the
2602+
* node, we need to see if it shares a cluster with the extent to
2603+
* the right (towards the end of the file). If its leftmost cluster
2604+
* is this extent's rightmost cluster and it is not cluster aligned,
2605+
* we'll mark it as a partial that is not to be deallocated.
2606+
*/
2607+
2608+
if (ex != EXT_LAST_EXTENT(eh)) {
2609+
ext4_fsblk_t current_pblk, right_pblk;
2610+
long long current_cluster, right_cluster;
2611+
2612+
current_pblk = ext4_ext_pblock(ex) + ex_ee_len - 1;
2613+
current_cluster = (long long)EXT4_B2C(sbi, current_pblk);
2614+
right_pblk = ext4_ext_pblock(ex + 1);
2615+
right_cluster = (long long)EXT4_B2C(sbi, right_pblk);
2616+
if (current_cluster == right_cluster &&
2617+
EXT4_PBLK_COFF(sbi, right_pblk))
2618+
*partial_cluster = -right_cluster;
2619+
}
2620+
26002621
trace_ext4_ext_rm_leaf(inode, start, ex, *partial_cluster);
26012622

26022623
while (ex >= EXT_FIRST_EXTENT(eh) &&

0 commit comments

Comments
 (0)