add patch prevent-online-resize-with-backup-superblock
[ext4-patch-queue.git] / fix-partial-cluster-initialization
bloba490bafb1ad0805e43865831fd61d601ef34de93
1 ext4: fix partial cluster initialization
3 From: Eric Whitney <enwlinux@gmail.com>
5 The partial_cluster variable is not always initialized correctly when
6 hole punching on bigalloc file systems.  Although commit c06344939422
7 ("ext4: fix partial cluster handling for bigalloc file systems")
8 addressed the case where the right edge of the punched region and the
9 next extent to its right were within the same leaf, it didn't handle
10 the case where the next extent to its right is in the next leaf.  This
11 causes xfstest generic/300 to fail.
13 Fix this by replacing the code in c0634493922 with a more general
14 solution that can continue the search for the first cluster to the
15 right of the punched region into the next leaf if present.  If found,
16 partial_cluster is initialized to this cluster's negative value.
17 There's no need to determine if that cluster is actually shared;  we
18 simply record it so its blocks won't be freed in the event it does
19 happen to be shared.
21 Also, minimize the burden on non-bigalloc file systems with some minor
22 code simplification.
24 Signed-off-by: Eric Whitney <enwlinux@gmail.com>
25 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
26 ---
27  fs/ext4/extents.c | 80 ++++++++++++++++++++++++++++++++-----------------------
28  1 file changed, 46 insertions(+), 34 deletions(-)
30 diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
31 index 0b16fb4..57794a7 100644
32 --- a/fs/ext4/extents.c
33 +++ b/fs/ext4/extents.c
34 @@ -2621,27 +2621,6 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
35         ex_ee_block = le32_to_cpu(ex->ee_block);
36         ex_ee_len = ext4_ext_get_actual_len(ex);
38 -       /*
39 -        * If we're starting with an extent other than the last one in the
40 -        * node, we need to see if it shares a cluster with the extent to
41 -        * the right (towards the end of the file). If its leftmost cluster
42 -        * is this extent's rightmost cluster and it is not cluster aligned,
43 -        * we'll mark it as a partial that is not to be deallocated.
44 -        */
46 -       if (ex != EXT_LAST_EXTENT(eh)) {
47 -               ext4_fsblk_t current_pblk, right_pblk;
48 -               long long current_cluster, right_cluster;
50 -               current_pblk = ext4_ext_pblock(ex) + ex_ee_len - 1;
51 -               current_cluster = (long long)EXT4_B2C(sbi, current_pblk);
52 -               right_pblk = ext4_ext_pblock(ex + 1);
53 -               right_cluster = (long long)EXT4_B2C(sbi, right_pblk);
54 -               if (current_cluster == right_cluster &&
55 -                       EXT4_PBLK_COFF(sbi, right_pblk))
56 -                       *partial_cluster = -right_cluster;
57 -       }
59         trace_ext4_ext_rm_leaf(inode, start, ex, *partial_cluster);
61         while (ex >= EXT_FIRST_EXTENT(eh) &&
62 @@ -2666,14 +2645,16 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
63                 if (end < ex_ee_block) {
64                         /*
65                          * We're going to skip this extent and move to another,
66 -                        * so if this extent is not cluster aligned we have
67 -                        * to mark the current cluster as used to avoid
68 -                        * accidentally freeing it later on
69 +                        * so note that its first cluster is in use to avoid
70 +                        * freeing it when removing blocks.  Eventually, the
71 +                        * right edge of the truncated/punched region will
72 +                        * be just to the left.
73                          */
74 -                       pblk = ext4_ext_pblock(ex);
75 -                       if (EXT4_PBLK_COFF(sbi, pblk))
76 +                       if (sbi->s_cluster_ratio > 1) {
77 +                               pblk = ext4_ext_pblock(ex);
78                                 *partial_cluster =
79 -                                       -((long long)EXT4_B2C(sbi, pblk));
80 +                                       -(long long) EXT4_B2C(sbi, pblk);
81 +                       }
82                         ex--;
83                         ex_ee_block = le32_to_cpu(ex->ee_block);
84                         ex_ee_len = ext4_ext_get_actual_len(ex);
85 @@ -2819,7 +2800,7 @@ ext4_ext_more_to_rm(struct ext4_ext_path *path)
86  int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
87                           ext4_lblk_t end)
88  {
89 -       struct super_block *sb = inode->i_sb;
90 +       struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
91         int depth = ext_depth(inode);
92         struct ext4_ext_path *path = NULL;
93         long long partial_cluster = 0;
94 @@ -2845,9 +2826,10 @@ again:
95          */
96         if (end < EXT_MAX_BLOCKS - 1) {
97                 struct ext4_extent *ex;
98 -               ext4_lblk_t ee_block;
99 +               ext4_lblk_t ee_block, ex_end, lblk;
100 +               ext4_fsblk_t pblk;
102 -               /* find extent for this block */
103 +               /* find extent for or closest extent to this block */
104                 path = ext4_find_extent(inode, end, NULL, EXT4_EX_NOCACHE);
105                 if (IS_ERR(path)) {
106                         ext4_journal_stop(handle);
107 @@ -2867,6 +2849,7 @@ again:
108                 }
110                 ee_block = le32_to_cpu(ex->ee_block);
111 +               ex_end = ee_block + ext4_ext_get_actual_len(ex) - 1;
113                 /*
114                  * See if the last block is inside the extent, if so split
115 @@ -2874,8 +2857,19 @@ again:
116                  * tail of the first part of the split extent in
117                  * ext4_ext_rm_leaf().
118                  */
119 -               if (end >= ee_block &&
120 -                   end < ee_block + ext4_ext_get_actual_len(ex) - 1) {
121 +               if (end >= ee_block && end < ex_end) {
123 +                       /*
124 +                        * If we're going to split the extent, note that
125 +                        * the cluster containing the block after 'end' is
126 +                        * in use to avoid freeing it when removing blocks.
127 +                        */
128 +                       if (sbi->s_cluster_ratio > 1) {
129 +                               pblk = ext4_ext_pblock(ex) + end - ee_block + 2;
130 +                               partial_cluster =
131 +                                       -(long long) EXT4_B2C(sbi, pblk);
132 +                       }
134                         /*
135                          * Split the extent in two so that 'end' is the last
136                          * block in the first new extent. Also we should not
137 @@ -2886,6 +2880,24 @@ again:
138                                                          end + 1, 1);
139                         if (err < 0)
140                                 goto out;
142 +               } else if (sbi->s_cluster_ratio > 1 && end >= ex_end) {
143 +                       /*
144 +                        * If there's an extent to the right its first cluster
145 +                        * contains the immediate right boundary of the
146 +                        * truncated/punched region.  Set partial_cluster to
147 +                        * its negative value so it won't be freed if shared
148 +                        * with the current extent.  The end < ee_block case
149 +                        * is handled in ext4_ext_rm_leaf().
150 +                        */
151 +                       lblk = ex_end + 1;
152 +                       err = ext4_ext_search_right(inode, path, &lblk, &pblk,
153 +                                                   &ex);
154 +                       if (err)
155 +                               goto out;
156 +                       if (pblk)
157 +                               partial_cluster =
158 +                                       -(long long) EXT4_B2C(sbi, pblk);
159                 }
160         }
161         /*
162 @@ -3003,8 +3015,8 @@ again:
163                 int flags = get_default_free_blocks_flags(inode);
165                 ext4_free_blocks(handle, inode, NULL,
166 -                                EXT4_C2B(EXT4_SB(sb), partial_cluster),
167 -                                EXT4_SB(sb)->s_cluster_ratio, flags);
168 +                                EXT4_C2B(sbi, partial_cluster),
169 +                                sbi->s_cluster_ratio, flags);
170                 partial_cluster = 0;
171         }
173 -- 
174 1.9.1