Whamcloud - gitweb
LU-17599 ldiskfs: restore ldiskfs patch attribution
[fs/lustre-release.git] / ldiskfs / kernel_patches / patches / linux-5.18 / ext4-mballoc-extra-checks.patch
1 commit f2f28f1d09c0a00b3fc569422f881931d857fac9
2 Author:     Alex Zhuravlev <alex.zhuravlev@sun.com>
3 AuthorDate: Tue Oct 28 17:59:09 2008 +0000
4 Subject: ext4: detect on-disk corruption of block bitmap
5
6 Detect on-disk corruption of block bitmap and better checking of
7 preallocated blocks.
8
9 Bugzilla-ID: b=16680
10 Signed-off-by: Alex Zhuravlev <alex.zhuravlev@sun.com>
11 Reviewed-by: Kalpak Shah <kalpak.shah@sun.com>
12 Signed-off-by: Andreas Dilger <andreas.dilger@sun.com>
13 ---
14  fs/ext4/ext4.h    |   1 +
15  fs/ext4/mballoc.c | 103 ++++++++++++++++++++++++++++++++++++++++------
16  fs/ext4/mballoc.h |   2 +-
17  3 files changed, 93 insertions(+), 13 deletions(-)
18
19 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
20 index d7ae1b1..f4a1557 100644
21 --- a/fs/ext4/ext4.h
22 +++ b/fs/ext4/ext4.h
23 @@ -3480,6 +3480,7 @@ struct ext4_group_info {
24         ext4_grpblk_t   bb_largest_free_order;/* order of largest frag in BG */
25         ext4_group_t    bb_group;       /* Group number */
26         struct          list_head bb_prealloc_list;
27 +       unsigned long   bb_prealloc_nr;
28  #ifdef DOUBLE_CHECK
29         void            *bb_bitmap;
30  #endif
31 diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
32 index 9952908..5dbd7e7 100644
33 --- a/fs/ext4/mballoc.c
34 +++ b/fs/ext4/mballoc.c
35 @@ -399,7 +399,7 @@ static const char * const ext4_groupinfo_slab_names[NR_GRPINFO_CACHES] = {
36         "ext4_groupinfo_64k", "ext4_groupinfo_128k"
37  };
38  
39 -static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
40 +static int ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
41                                         ext4_group_t group);
42  static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
43                                                 ext4_group_t group);
44 @@ -1105,7 +1105,7 @@ mb_set_largest_free_order(struct super_block *sb, struct ext4_group_info *grp)
45  }
46  
47  static noinline_for_stack
48 -void ext4_mb_generate_buddy(struct super_block *sb,
49 +int ext4_mb_generate_buddy(struct super_block *sb,
50                                 void *buddy, void *bitmap, ext4_group_t group)
51  {
52         struct ext4_group_info *grp = ext4_get_group_info(sb, group);
53 @@ -1149,6 +1149,7 @@ void ext4_mb_generate_buddy(struct super_block *sb,
54                 grp->bb_free = free;
55                 ext4_mark_group_bitmap_corrupted(sb, group,
56                                         EXT4_GROUP_INFO_BBITMAP_CORRUPT);
57 +               return -EIO;
58         }
59         mb_set_largest_free_order(sb, grp);
60  
61 @@ -1158,6 +1159,8 @@ void ext4_mb_generate_buddy(struct super_block *sb,
62         atomic_inc(&sbi->s_mb_buddies_generated);
63         atomic64_add(period, &sbi->s_mb_generation_time);
64         mb_update_avg_fragment_size(sb, grp);
65 +
66 +       return 0;
67  }
68  
69  /* The buddy information is attached the buddy cache inode
70 @@ -1260,7 +1263,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore, gfp_t gfp)
71         }
72  
73         first_block = page->index * blocks_per_page;
74 -       for (i = 0; i < blocks_per_page; i++) {
75 +       for (i = 0; i < blocks_per_page && err == 0; i++) {
76                 group = (first_block + i) >> 1;
77                 if (group >= ngroups)
78                         break;
79 @@ -1304,7 +1307,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore, gfp_t gfp)
80                         ext4_lock_group(sb, group);
81                         /* init the buddy */
82                         memset(data, 0xff, blocksize);
83 -                       ext4_mb_generate_buddy(sb, data, incore, group);
84 +                       err = ext4_mb_generate_buddy(sb, data, incore, group);
85                         ext4_unlock_group(sb, group);
86                         incore = NULL;
87                 } else {
88 @@ -1319,7 +1322,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore, gfp_t gfp)
89                         memcpy(data, bitmap, blocksize);
90  
91                         /* mark all preallocated blks used in in-core bitmap */
92 -                       ext4_mb_generate_from_pa(sb, data, group);
93 +                       err = ext4_mb_generate_from_pa(sb, data, group);
94                         ext4_mb_generate_from_freelist(sb, data, group);
95                         ext4_unlock_group(sb, group);
96  
97 @@ -1329,7 +1332,8 @@ static int ext4_mb_init_cache(struct page *page, char *incore, gfp_t gfp)
98                         incore = data;
99                 }
100         }
101 -       SetPageUptodate(page);
102 +       if (likely(err == 0))
103 +               SetPageUptodate(page);
104  
105  out:
106         if (bh) {
107 @@ -2858,9 +2862,11 @@ static void *ext4_mb_seq_groups_next(struct seq_file *seq, void *v, loff_t *pos)
108  static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
109  {
110         struct super_block *sb = pde_data(file_inode(seq->file));
111 +       struct ext4_group_desc *gdp;
112         ext4_group_t group = (ext4_group_t) ((unsigned long) v);
113         int i;
114         int err, buddy_loaded = 0;
115 +       int free = 0;
116         struct ext4_buddy e4b;
117         struct ext4_group_info *grinfo;
118         unsigned char blocksize_bits = min_t(unsigned char,
119 @@ -2873,7 +2879,7 @@ static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
120  
121         group--;
122         if (group == 0)
123 -               seq_puts(seq, "#group: free  frags first ["
124 +               seq_puts(seq, "#group: bfree gfree frags first pa    ["
125                               " 2^0   2^1   2^2   2^3   2^4   2^5   2^6  "
126                               " 2^7   2^8   2^9   2^10  2^11  2^12  2^13  ]\n");
127  
128 @@ -2891,13 +2897,19 @@ static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
129                 buddy_loaded = 1;
130         }
131  
132 +       gdp = ext4_get_group_desc(sb, group, NULL);
133 +       if (gdp != NULL)
134 +               free = ext4_free_group_clusters(sb, gdp);
135 +
136         memcpy(&sg, ext4_get_group_info(sb, group), i);
137  
138         if (buddy_loaded)
139                 ext4_mb_unload_buddy(&e4b);
140  
141 -       seq_printf(seq, "#%-5u: %-5u %-5u %-5u [", group, sg.info.bb_free,
142 -                       sg.info.bb_fragments, sg.info.bb_first_free);
143 +       seq_printf(seq, "#%-5lu: %-5u %-5u %-5u %-5u %-5lu [",
144 +                       (long unsigned int)group, sg.info.bb_free, free,
145 +                       sg.info.bb_fragments, sg.info.bb_first_free,
146 +                       sg.info.bb_prealloc_nr);
147         for (i = 0; i <= 13; i++)
148                 seq_printf(seq, " %-5u", i <= blocksize_bits + 1 ?
149                                 sg.info.bb_counters[i] : 0);
150 @@ -4589,23 +4601,72 @@ static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
151         return;
152  }
153  
154 +/*
155 + * check free blocks in bitmap match free block in group descriptor
156 + * do this before taking preallocated blocks into account to be able
157 + * to detect on-disk corruptions. The group lock should be hold by the
158 + * caller.
159 + */
160 +int ext4_mb_check_ondisk_bitmap(struct super_block *sb, void *bitmap,
161 +                               struct ext4_group_desc *gdp, int group)
162 +{
163 +       unsigned short max = EXT4_CLUSTERS_PER_GROUP(sb);
164 +       unsigned short i, first, free = 0;
165 +       unsigned short free_in_gdp = ext4_free_group_clusters(sb, gdp);
166 +
167 +       if (free_in_gdp == 0 && gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))
168 +               return 0;
169 +
170 +       i = mb_find_next_zero_bit(bitmap, max, 0);
171 +
172 +       while (i < max) {
173 +               first = i;
174 +               i = mb_find_next_bit(bitmap, max, i);
175 +               if (i > max)
176 +                       i = max;
177 +               free += i - first;
178 +               if (i < max)
179 +                       i = mb_find_next_zero_bit(bitmap, max, i);
180 +       }
181 +
182 +       if (free != free_in_gdp) {
183 +               ext4_error(sb, "on-disk bitmap for group %d"
184 +                       "corrupted: %u blocks free in bitmap, %u - in gd\n",
185 +                       group, free, free_in_gdp);
186 +               return -EIO;
187 +       }
188 +       return 0;
189 +}
190 +
191  /*
192   * the function goes through all preallocation in this group and marks them
193   * used in in-core bitmap. buddy must be generated from this bitmap
194   * Need to be called with ext4 group lock held
195   */
196  static noinline_for_stack
197 -void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
198 +int ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
199                                         ext4_group_t group)
200  {
201         struct ext4_group_info *grp = ext4_get_group_info(sb, group);
202         struct ext4_prealloc_space *pa;
203 +       struct ext4_group_desc *gdp;
204         struct list_head *cur;
205         ext4_group_t groupnr;
206         ext4_grpblk_t start;
207         int preallocated = 0;
208 +       int skip = 0, count = 0;
209 +       int err;
210         int len;
211  
212 +       gdp = ext4_get_group_desc(sb, group, NULL);
213 +       if (gdp == NULL)
214 +               return -EIO;
215 +
216 +       /* before applying preallocations, check bitmap consistency */
217 +       err = ext4_mb_check_ondisk_bitmap(sb, bitmap, gdp, group);
218 +       if (err)
219 +               return err;
220 +
221         /* all form of preallocation discards first load group,
222          * so the only competing code is preallocation use.
223          * we don't need any locking here
224 @@ -4621,13 +4682,23 @@ void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
225                                              &groupnr, &start);
226                 len = pa->pa_len;
227                 spin_unlock(&pa->pa_lock);
228 -               if (unlikely(len == 0))
229 +               if (unlikely(len == 0)) {
230 +                       skip++;
231                         continue;
232 +               }
233                 BUG_ON(groupnr != group);
234                 mb_set_bits(bitmap, start, len);
235                 preallocated += len;
236 +               count++;
237 +       }
238 +       if (count + skip != grp->bb_prealloc_nr) {
239 +               ext4_error(sb, "lost preallocations: "
240 +                          "count %d, bb_prealloc_nr %lu, skip %d\n",
241 +                          count, grp->bb_prealloc_nr, skip);
242 +               return -EIO;
243         }
244         mb_debug(sb, "preallocated %d for group %u\n", preallocated, group);
245 +       return 0;
246  }
247  
248  static void ext4_mb_mark_pa_deleted(struct super_block *sb,
249 @@ -4711,6 +4782,7 @@ static void ext4_mb_put_pa(struct ext4_allocation_context *ac,
250          */
251         ext4_lock_group(sb, grp);
252         list_del(&pa->pa_group_list);
253 +       ext4_get_group_info(sb, grp)->bb_prealloc_nr--;
254         ext4_unlock_group(sb, grp);
255  
256         spin_lock(pa->pa_obj_lock);
257 @@ -4802,6 +4874,7 @@ ext4_mb_new_inode_pa(struct ext4_allocation_context *ac)
258         pa->pa_inode = ac->ac_inode;
259  
260         list_add(&pa->pa_group_list, &grp->bb_prealloc_list);
261 +       grp->bb_prealloc_nr++;
262  
263         spin_lock(pa->pa_obj_lock);
264         list_add_rcu(&pa->pa_inode_list, &ei->i_prealloc_list);
265 @@ -4857,6 +4930,7 @@ ext4_mb_new_group_pa(struct ext4_allocation_context *ac)
266         pa->pa_inode = NULL;
267  
268         list_add(&pa->pa_group_list, &grp->bb_prealloc_list);
269 +       grp->bb_prealloc_nr++;
270  
271         /*
272          * We will later add the new pa to the right bucket
273 @@ -5021,6 +5095,8 @@ ext4_mb_discard_group_preallocations(struct super_block *sb,
274  
275                 spin_unlock(&pa->pa_lock);
276  
277 +               BUG_ON(grp->bb_prealloc_nr == 0);
278 +               grp->bb_prealloc_nr--;
279                 list_del(&pa->pa_group_list);
280                 list_add(&pa->u.pa_tmp_list, &list);
281         }
282 @@ -5148,7 +5224,7 @@ repeat:
283                 if (err) {
284                         ext4_error_err(sb, -err, "Error %d loading buddy information for %u",
285                                        err, group);
286 -                       continue;
287 +                       return;
288                 }
289  
290                 bitmap_bh = ext4_read_block_bitmap(sb, group);
291 @@ -5161,6 +5237,8 @@ repeat:
292                 }
293  
294                 ext4_lock_group(sb, group);
295 +               BUG_ON(e4b.bd_info->bb_prealloc_nr == 0);
296 +               e4b.bd_info->bb_prealloc_nr--;
297                 list_del(&pa->pa_group_list);
298                 ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa);
299                 ext4_unlock_group(sb, group);
300 @@ -5455,6 +5533,7 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb,
301                 }
302                 ext4_lock_group(sb, group);
303                 list_del(&pa->pa_group_list);
304 +               ext4_get_group_info(sb, group)->bb_prealloc_nr--;
305                 ext4_mb_release_group_pa(&e4b, pa);
306                 ext4_unlock_group(sb, group);
307  
308 diff --git a/fs/ext4/mballoc.h b/fs/ext4/mballoc.h
309 index 39da92c..b6c4a30 100644
310 --- a/fs/ext4/mballoc.h
311 +++ b/fs/ext4/mballoc.h
312 @@ -66,7 +66,7 @@
313  /*
314   * for which requests use 2^N search using buddies
315   */
316 -#define MB_DEFAULT_ORDER2_REQS         2
317 +#define MB_DEFAULT_ORDER2_REQS         8
318  
319  /*
320   * default group prealloc size 512 blocks
321 -- 
322 2.34.1
323