update atomically-set-inode-flags
[ext4-patch-queue.git] / fix-partial-cluster-handling-for-bigalloc-filesystems
blob4ac3cc4a5b4b2ce325b7c512355bc6ba4a91885b
1 ext4: fix partial cluster handling for bigalloc file systems
3 From: Eric Whitney <enwlinux@gmail.com>
5 Commit 9cb00419fa, which enables hole punching for bigalloc file
6 systems, exposed a bug introduced by commit 6ae06ff51e in an earlier
7 release.  When run on a bigalloc file system, xfstests generic/013, 068,
8 075, 083, 091, 100, 112, 127, 263, 269, and 270 fail with e2fsck errors
9 or cause kernel error messages indicating that previously freed blocks
10 are being freed again.
12 The latter commit optimizes the selection of the starting extent in
13 ext4_ext_rm_leaf() when hole punching by beginning with the extent
14 supplied in the path argument rather than with the last extent in the
15 leaf node (as is still done when truncating).  However, the code in
16 rm_leaf that initially sets partial_cluster to track cluster sharing on
17 extent boundaries is only guaranteed to run if rm_leaf starts with the
18 last node in the leaf.  Consequently, partial_cluster is not correctly
19 initialized when hole punching, and a cluster on the boundary of a
20 punched region that should be retained may instead be deallocated.
22 Signed-off-by: Eric Whitney <enwlinux@gmail.com>
23 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
24 Cc: stable@vger.kernel.org
25 ---
26  fs/ext4/extents.c | 21 +++++++++++++++++++++
27  1 file changed, 21 insertions(+)
29 diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
30 index f5def95..12bf3cc 100644
31 --- a/fs/ext4/extents.c
32 +++ b/fs/ext4/extents.c
33 @@ -2602,6 +2602,27 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
34         ex_ee_block = le32_to_cpu(ex->ee_block);
35         ex_ee_len = ext4_ext_get_actual_len(ex);
37 +       /*
38 +        * If we're starting with an extent other than the last one in the
39 +        * node, we need to see if it shares a cluster with the extent to
40 +        * the right (towards the end of the file). If its leftmost cluster
41 +        * is this extent's rightmost cluster and it is not cluster aligned,
42 +        * we'll mark it as a partial that is not to be deallocated.
43 +        */
45 +       if (ex != EXT_LAST_EXTENT(eh)) {
46 +               ext4_fsblk_t current_pblk, right_pblk;
47 +               long long current_cluster, right_cluster;
49 +               current_pblk = ext4_ext_pblock(ex) + ex_ee_len - 1;
50 +               current_cluster = (long long)EXT4_B2C(sbi, current_pblk);
51 +               right_pblk = ext4_ext_pblock(ex + 1);
52 +               right_cluster = (long long)EXT4_B2C(sbi, right_pblk);
53 +               if (current_cluster == right_cluster &&
54 +                       EXT4_PBLK_COFF(sbi, right_pblk))
55 +                       *partial_cluster = -right_cluster;
56 +       }
58         trace_ext4_ext_rm_leaf(inode, start, ex, *partial_cluster);
60         while (ex >= EXT_FIRST_EXTENT(eh) &&