fix bug in add-support-collapse-range
[ext4-patch-queue.git] / fix-premature-freeing-of-partial-clusters
blob665187534b82774d66bf361540ce2403b5589ff8
1 ext4: fix premature freeing of partial clusters split across leaf blocks
3 From: Eric Whitney <enwlinux@gmail.com>
5 Xfstests generic/311 and shared/298 fail when run on a bigalloc file
6 system.  Kernel error messages produced during the tests report that
7 blocks to be freed are already on the to-be-freed list.  When e2fsck
8 is run at the end of the tests, it typically reports bad i_blocks and
9 bad free blocks counts.
11 The bug that causes these failures is located in ext4_ext_rm_leaf().
12 Code at the end of the function frees a partial cluster if it's not
13 shared with an extent remaining in the leaf.  However, if all the
14 extents in the leaf have been removed, the code dereferences an
15 invalid extent pointer (off the front of the leaf) when the check for
16 sharing is made.  This generally has the effect of unconditionally
17 freeing the partial cluster, which leads to the observed failures
18 when the partial cluster is shared with the last extent in the next
19 leaf.
21 Fix this by attempting to free the cluster only if extents remain in
22 the leaf.  Any remaining partial cluster will be freed if possible
23 when the next leaf is processed or when leaf removal is complete.
25 Signed-off-by: Eric Whitney <enwlinux@gmail.com>
26 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
27 Cc: stable@vger.kernel.org
28 ---
29  fs/ext4/extents.c | 11 ++++++++---
30  1 file changed, 8 insertions(+), 3 deletions(-)
32 diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
33 index 243a02e..340fadd 100644
34 --- a/fs/ext4/extents.c
35 +++ b/fs/ext4/extents.c
36 @@ -2743,10 +2743,15 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
37                 err = ext4_ext_correct_indexes(handle, inode, path);
39         /*
40 -        * Free the partial cluster only if the current extent does not
41 -        * reference it. Otherwise we might free used cluster.
42 +        * If there's a partial cluster and at least one extent remains in
43 +        * the leaf, free the partial cluster if it isn't shared with the
44 +        * current extent.  If there's a partial cluster and no extents
45 +        * remain in the leaf, it can't be freed here.  It can only be
46 +        * freed when it's possible to determine if it's not shared with
47 +        * any other extent - when the next leaf is processed or when space
48 +        * removal is complete.
49          */
50 -       if (*partial_cluster > 0 &&
51 +       if (*partial_cluster > 0 && eh->eh_entries &&
52             (EXT4_B2C(sbi, ext4_ext_pblock(ex) + ex_ee_len - 1) !=
53              *partial_cluster)) {
54                 int flags = get_default_free_blocks_flags(inode);
55 -- 
56 1.8.3.2