~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/bcachefs/sb-downgrade.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 
  3 /*
  4  * Superblock section that contains a list of recovery passes to run when
  5  * downgrading past a given version
  6  */
  7 
  8 #include "bcachefs.h"
  9 #include "darray.h"
 10 #include "recovery_passes.h"
 11 #include "sb-downgrade.h"
 12 #include "sb-errors.h"
 13 #include "super-io.h"
 14 
 15 #define RECOVERY_PASS_ALL_FSCK          BIT_ULL(63)
 16 
 17 /*
 18  * Upgrade, downgrade tables - run certain recovery passes, fix certain errors
 19  *
 20  * x(version, recovery_passes, errors...)
 21  */
 22 #define UPGRADE_TABLE()                                         \
 23         x(backpointers,                                         \
 24           RECOVERY_PASS_ALL_FSCK)                               \
 25         x(inode_v3,                                             \
 26           RECOVERY_PASS_ALL_FSCK)                               \
 27         x(unwritten_extents,                                    \
 28           RECOVERY_PASS_ALL_FSCK)                               \
 29         x(bucket_gens,                                          \
 30           BIT_ULL(BCH_RECOVERY_PASS_bucket_gens_init)|          \
 31           RECOVERY_PASS_ALL_FSCK)                               \
 32         x(lru_v2,                                               \
 33           RECOVERY_PASS_ALL_FSCK)                               \
 34         x(fragmentation_lru,                                    \
 35           RECOVERY_PASS_ALL_FSCK)                               \
 36         x(no_bps_in_alloc_keys,                                 \
 37           RECOVERY_PASS_ALL_FSCK)                               \
 38         x(snapshot_trees,                                       \
 39           RECOVERY_PASS_ALL_FSCK)                               \
 40         x(snapshot_skiplists,                                   \
 41           BIT_ULL(BCH_RECOVERY_PASS_check_snapshots),           \
 42           BCH_FSCK_ERR_snapshot_bad_depth,                      \
 43           BCH_FSCK_ERR_snapshot_bad_skiplist)                   \
 44         x(deleted_inodes,                                       \
 45           BIT_ULL(BCH_RECOVERY_PASS_check_inodes),              \
 46           BCH_FSCK_ERR_unlinked_inode_not_on_deleted_list)      \
 47         x(rebalance_work,                                       \
 48           BIT_ULL(BCH_RECOVERY_PASS_set_fs_needs_rebalance))    \
 49         x(subvolume_fs_parent,                                  \
 50           BIT_ULL(BCH_RECOVERY_PASS_check_dirents),             \
 51           BCH_FSCK_ERR_subvol_fs_path_parent_wrong)             \
 52         x(btree_subvolume_children,                             \
 53           BIT_ULL(BCH_RECOVERY_PASS_check_subvols),             \
 54           BCH_FSCK_ERR_subvol_children_not_set)                 \
 55         x(mi_btree_bitmap,                                      \
 56           BIT_ULL(BCH_RECOVERY_PASS_check_allocations),         \
 57           BCH_FSCK_ERR_btree_bitmap_not_marked)                 \
 58         x(disk_accounting_v2,                                   \
 59           BIT_ULL(BCH_RECOVERY_PASS_check_allocations),         \
 60           BCH_FSCK_ERR_bkey_version_in_future,                  \
 61           BCH_FSCK_ERR_dev_usage_buckets_wrong,                 \
 62           BCH_FSCK_ERR_dev_usage_sectors_wrong,                 \
 63           BCH_FSCK_ERR_dev_usage_fragmented_wrong,              \
 64           BCH_FSCK_ERR_accounting_mismatch)                     \
 65         x(disk_accounting_v3,                                   \
 66           BIT_ULL(BCH_RECOVERY_PASS_check_allocations),         \
 67           BCH_FSCK_ERR_bkey_version_in_future,                  \
 68           BCH_FSCK_ERR_dev_usage_buckets_wrong,                 \
 69           BCH_FSCK_ERR_dev_usage_sectors_wrong,                 \
 70           BCH_FSCK_ERR_dev_usage_fragmented_wrong,              \
 71           BCH_FSCK_ERR_accounting_mismatch,                     \
 72           BCH_FSCK_ERR_accounting_key_replicas_nr_devs_0,       \
 73           BCH_FSCK_ERR_accounting_key_replicas_nr_required_bad, \
 74           BCH_FSCK_ERR_accounting_key_replicas_devs_unsorted,   \
 75           BCH_FSCK_ERR_accounting_key_junk_at_end)
 76 
 77 #define DOWNGRADE_TABLE()                                       \
 78         x(bucket_stripe_sectors,                                \
 79           0)                                                    \
 80         x(disk_accounting_v2,                                   \
 81           BIT_ULL(BCH_RECOVERY_PASS_check_allocations),         \
 82           BCH_FSCK_ERR_dev_usage_buckets_wrong,                 \
 83           BCH_FSCK_ERR_dev_usage_sectors_wrong,                 \
 84           BCH_FSCK_ERR_dev_usage_fragmented_wrong,              \
 85           BCH_FSCK_ERR_fs_usage_hidden_wrong,                   \
 86           BCH_FSCK_ERR_fs_usage_btree_wrong,                    \
 87           BCH_FSCK_ERR_fs_usage_data_wrong,                     \
 88           BCH_FSCK_ERR_fs_usage_cached_wrong,                   \
 89           BCH_FSCK_ERR_fs_usage_reserved_wrong,                 \
 90           BCH_FSCK_ERR_fs_usage_nr_inodes_wrong,                \
 91           BCH_FSCK_ERR_fs_usage_persistent_reserved_wrong,      \
 92           BCH_FSCK_ERR_fs_usage_replicas_wrong,                 \
 93           BCH_FSCK_ERR_bkey_version_in_future)                  \
 94         x(disk_accounting_v3,                                   \
 95           BIT_ULL(BCH_RECOVERY_PASS_check_allocations),         \
 96           BCH_FSCK_ERR_dev_usage_buckets_wrong,                 \
 97           BCH_FSCK_ERR_dev_usage_sectors_wrong,                 \
 98           BCH_FSCK_ERR_dev_usage_fragmented_wrong,              \
 99           BCH_FSCK_ERR_fs_usage_hidden_wrong,                   \
100           BCH_FSCK_ERR_fs_usage_btree_wrong,                    \
101           BCH_FSCK_ERR_fs_usage_data_wrong,                     \
102           BCH_FSCK_ERR_fs_usage_cached_wrong,                   \
103           BCH_FSCK_ERR_fs_usage_reserved_wrong,                 \
104           BCH_FSCK_ERR_fs_usage_nr_inodes_wrong,                \
105           BCH_FSCK_ERR_fs_usage_persistent_reserved_wrong,      \
106           BCH_FSCK_ERR_fs_usage_replicas_wrong,                 \
107           BCH_FSCK_ERR_bkey_version_in_future)
108 
109 struct upgrade_downgrade_entry {
110         u64             recovery_passes;
111         u16             version;
112         u16             nr_errors;
113         const u16       *errors;
114 };
115 
116 #define x(ver, passes, ...) static const u16 upgrade_##ver##_errors[] = { __VA_ARGS__ };
117 UPGRADE_TABLE()
118 #undef x
119 
120 static const struct upgrade_downgrade_entry upgrade_table[] = {
121 #define x(ver, passes, ...) {                                   \
122         .recovery_passes        = passes,                       \
123         .version                = bcachefs_metadata_version_##ver,\
124         .nr_errors              = ARRAY_SIZE(upgrade_##ver##_errors),   \
125         .errors                 = upgrade_##ver##_errors,       \
126 },
127 UPGRADE_TABLE()
128 #undef x
129 };
130 
131 static int have_stripes(struct bch_fs *c)
132 {
133         return !btree_node_fake(c->btree_roots_known[BTREE_ID_stripes].b);
134 }
135 
136 int bch2_sb_set_upgrade_extra(struct bch_fs *c)
137 {
138         unsigned old_version = c->sb.version_upgrade_complete ?: c->sb.version;
139         unsigned new_version = c->sb.version;
140         bool write_sb = false;
141         int ret = 0;
142 
143         mutex_lock(&c->sb_lock);
144         struct bch_sb_field_ext *ext = bch2_sb_field_get(c->disk_sb.sb, ext);
145 
146         if (old_version <  bcachefs_metadata_version_bucket_stripe_sectors &&
147             new_version >= bcachefs_metadata_version_bucket_stripe_sectors &&
148             (ret = have_stripes(c) > 0)) {
149                 __set_bit_le64(BCH_RECOVERY_PASS_STABLE_check_allocations, ext->recovery_passes_required);
150                 __set_bit_le64(BCH_FSCK_ERR_alloc_key_dirty_sectors_wrong, ext->errors_silent);
151                 __set_bit_le64(BCH_FSCK_ERR_alloc_key_stripe_sectors_wrong, ext->errors_silent);
152                 write_sb = true;
153         }
154 
155         if (write_sb)
156                 bch2_write_super(c);
157         mutex_unlock(&c->sb_lock);
158 
159         return ret < 0 ? ret : 0;
160 }
161 
162 void bch2_sb_set_upgrade(struct bch_fs *c,
163                          unsigned old_version,
164                          unsigned new_version)
165 {
166         lockdep_assert_held(&c->sb_lock);
167 
168         struct bch_sb_field_ext *ext = bch2_sb_field_get(c->disk_sb.sb, ext);
169 
170         for (const struct upgrade_downgrade_entry *i = upgrade_table;
171              i < upgrade_table + ARRAY_SIZE(upgrade_table);
172              i++)
173                 if (i->version > old_version && i->version <= new_version) {
174                         u64 passes = i->recovery_passes;
175 
176                         if (passes & RECOVERY_PASS_ALL_FSCK)
177                                 passes |= bch2_fsck_recovery_passes();
178                         passes &= ~RECOVERY_PASS_ALL_FSCK;
179 
180                         ext->recovery_passes_required[0] |=
181                                 cpu_to_le64(bch2_recovery_passes_to_stable(passes));
182 
183                         for (const u16 *e = i->errors; e < i->errors + i->nr_errors; e++)
184                                 __set_bit_le64(*e, ext->errors_silent);
185                 }
186 }
187 
188 #define x(ver, passes, ...) static const u16 downgrade_##ver##_errors[] = { __VA_ARGS__ };
189 DOWNGRADE_TABLE()
190 #undef x
191 
192 static const struct upgrade_downgrade_entry downgrade_table[] = {
193 #define x(ver, passes, ...) {                                   \
194         .recovery_passes        = passes,                       \
195         .version                = bcachefs_metadata_version_##ver,\
196         .nr_errors              = ARRAY_SIZE(downgrade_##ver##_errors), \
197         .errors                 = downgrade_##ver##_errors,     \
198 },
199 DOWNGRADE_TABLE()
200 #undef x
201 };
202 
203 static int downgrade_table_extra(struct bch_fs *c, darray_char *table)
204 {
205         struct bch_sb_field_downgrade_entry *dst = (void *) &darray_top(*table);
206         unsigned bytes = sizeof(*dst) + sizeof(dst->errors[0]) * le16_to_cpu(dst->nr_errors);
207         int ret = 0;
208 
209         unsigned nr_errors = le16_to_cpu(dst->nr_errors);
210 
211         switch (le16_to_cpu(dst->version)) {
212         case bcachefs_metadata_version_bucket_stripe_sectors:
213                 if (have_stripes(c)) {
214                         bytes += sizeof(dst->errors[0]) * 2;
215 
216                         ret = darray_make_room(table, bytes);
217                         if (ret)
218                                 return ret;
219 
220                         /* open coded __set_bit_le64, as dst is packed and
221                          * dst->recovery_passes is misaligned */
222                         unsigned b = BCH_RECOVERY_PASS_STABLE_check_allocations;
223                         dst->recovery_passes[b / 64] |= cpu_to_le64(BIT_ULL(b % 64));
224 
225                         dst->errors[nr_errors++] = cpu_to_le16(BCH_FSCK_ERR_alloc_key_dirty_sectors_wrong);
226                 }
227                 break;
228         }
229 
230         dst->nr_errors = cpu_to_le16(nr_errors);
231         return ret;
232 }
233 
234 static inline const struct bch_sb_field_downgrade_entry *
235 downgrade_entry_next_c(const struct bch_sb_field_downgrade_entry *e)
236 {
237         return (void *) &e->errors[le16_to_cpu(e->nr_errors)];
238 }
239 
240 #define for_each_downgrade_entry(_d, _i)                                                \
241         for (const struct bch_sb_field_downgrade_entry *_i = (_d)->entries;             \
242              (void *) _i        < vstruct_end(&(_d)->field) &&                          \
243              (void *) &_i->errors[0] <= vstruct_end(&(_d)->field) &&                    \
244              (void *) downgrade_entry_next_c(_i) <= vstruct_end(&(_d)->field);          \
245              _i = downgrade_entry_next_c(_i))
246 
247 static int bch2_sb_downgrade_validate(struct bch_sb *sb, struct bch_sb_field *f,
248                                       enum bch_validate_flags flags, struct printbuf *err)
249 {
250         struct bch_sb_field_downgrade *e = field_to_type(f, downgrade);
251 
252         for (const struct bch_sb_field_downgrade_entry *i = e->entries;
253              (void *) i < vstruct_end(&e->field);
254              i = downgrade_entry_next_c(i)) {
255                 /*
256                  * Careful: sb_field_downgrade_entry is only 2 byte aligned, but
257                  * section sizes are 8 byte aligned - an empty entry spanning
258                  * the end of the section is allowed (and ignored):
259                  */
260                 if ((void *) &i->errors[0] > vstruct_end(&e->field))
261                         break;
262 
263                 if (flags & BCH_VALIDATE_write &&
264                     (void *) downgrade_entry_next_c(i) > vstruct_end(&e->field)) {
265                         prt_printf(err, "downgrade entry overruns end of superblock section");
266                         return -BCH_ERR_invalid_sb_downgrade;
267                 }
268 
269                 if (BCH_VERSION_MAJOR(le16_to_cpu(i->version)) !=
270                     BCH_VERSION_MAJOR(le16_to_cpu(sb->version))) {
271                         prt_printf(err, "downgrade entry with mismatched major version (%u != %u)",
272                                    BCH_VERSION_MAJOR(le16_to_cpu(i->version)),
273                                    BCH_VERSION_MAJOR(le16_to_cpu(sb->version)));
274                         return -BCH_ERR_invalid_sb_downgrade;
275                 }
276         }
277 
278         return 0;
279 }
280 
281 static void bch2_sb_downgrade_to_text(struct printbuf *out, struct bch_sb *sb,
282                                       struct bch_sb_field *f)
283 {
284         struct bch_sb_field_downgrade *e = field_to_type(f, downgrade);
285 
286         if (out->nr_tabstops <= 1)
287                 printbuf_tabstop_push(out, 16);
288 
289         for_each_downgrade_entry(e, i) {
290                 prt_str(out, "version:\t");
291                 bch2_version_to_text(out, le16_to_cpu(i->version));
292                 prt_newline(out);
293 
294                 prt_str(out, "recovery passes:\t");
295                 prt_bitflags(out, bch2_recovery_passes,
296                              bch2_recovery_passes_from_stable(le64_to_cpu(i->recovery_passes[0])));
297                 prt_newline(out);
298 
299                 prt_str(out, "errors:\t");
300                 bool first = true;
301                 for (unsigned j = 0; j < le16_to_cpu(i->nr_errors); j++) {
302                         if (!first)
303                                 prt_char(out, ',');
304                         first = false;
305                         unsigned e = le16_to_cpu(i->errors[j]);
306                         prt_str(out, e < BCH_SB_ERR_MAX ? bch2_sb_error_strs[e] : "(unknown)");
307                 }
308                 prt_newline(out);
309         }
310 }
311 
312 const struct bch_sb_field_ops bch_sb_field_ops_downgrade = {
313         .validate       = bch2_sb_downgrade_validate,
314         .to_text        = bch2_sb_downgrade_to_text,
315 };
316 
317 int bch2_sb_downgrade_update(struct bch_fs *c)
318 {
319         if (!test_bit(BCH_FS_btree_running, &c->flags))
320                 return 0;
321 
322         darray_char table = {};
323         int ret = 0;
324 
325         for (const struct upgrade_downgrade_entry *src = downgrade_table;
326              src < downgrade_table + ARRAY_SIZE(downgrade_table);
327              src++) {
328                 if (BCH_VERSION_MAJOR(src->version) != BCH_VERSION_MAJOR(le16_to_cpu(c->disk_sb.sb->version)))
329                         continue;
330 
331                 struct bch_sb_field_downgrade_entry *dst;
332                 unsigned bytes = sizeof(*dst) + sizeof(dst->errors[0]) * src->nr_errors;
333 
334                 ret = darray_make_room(&table, bytes);
335                 if (ret)
336                         goto out;
337 
338                 dst = (void *) &darray_top(table);
339                 dst->version = cpu_to_le16(src->version);
340                 dst->recovery_passes[0] = cpu_to_le64(bch2_recovery_passes_to_stable(src->recovery_passes));
341                 dst->recovery_passes[1] = 0;
342                 dst->nr_errors          = cpu_to_le16(src->nr_errors);
343                 for (unsigned i = 0; i < src->nr_errors; i++)
344                         dst->errors[i] = cpu_to_le16(src->errors[i]);
345 
346                 downgrade_table_extra(c, &table);
347 
348                 if (!dst->recovery_passes[0] &&
349                     !dst->recovery_passes[1] &&
350                     !dst->nr_errors)
351                         continue;
352 
353                 table.nr += sizeof(*dst) + sizeof(dst->errors[0]) * le16_to_cpu(dst->nr_errors);
354         }
355 
356         struct bch_sb_field_downgrade *d = bch2_sb_field_get(c->disk_sb.sb, downgrade);
357 
358         unsigned sb_u64s = DIV_ROUND_UP(sizeof(*d) + table.nr, sizeof(u64));
359 
360         if (d && le32_to_cpu(d->field.u64s) > sb_u64s)
361                 goto out;
362 
363         d = bch2_sb_field_resize(&c->disk_sb, downgrade, sb_u64s);
364         if (!d) {
365                 ret = -BCH_ERR_ENOSPC_sb_downgrade;
366                 goto out;
367         }
368 
369         memcpy(d->entries, table.data, table.nr);
370         memset_u64s_tail(d->entries, 0, table.nr);
371 out:
372         darray_exit(&table);
373         return ret;
374 }
375 
376 void bch2_sb_set_downgrade(struct bch_fs *c, unsigned new_minor, unsigned old_minor)
377 {
378         struct bch_sb_field_downgrade *d = bch2_sb_field_get(c->disk_sb.sb, downgrade);
379         if (!d)
380                 return;
381 
382         struct bch_sb_field_ext *ext = bch2_sb_field_get(c->disk_sb.sb, ext);
383 
384         for_each_downgrade_entry(d, i) {
385                 unsigned minor = BCH_VERSION_MINOR(le16_to_cpu(i->version));
386                 if (new_minor < minor && minor <= old_minor) {
387                         ext->recovery_passes_required[0] |= i->recovery_passes[0];
388                         ext->recovery_passes_required[1] |= i->recovery_passes[1];
389 
390                         for (unsigned j = 0; j < le16_to_cpu(i->nr_errors); j++) {
391                                 unsigned e = le16_to_cpu(i->errors[j]);
392                                 if (e < BCH_SB_ERR_MAX)
393                                         __set_bit(e, c->sb.errors_silent);
394                                 if (e < sizeof(ext->errors_silent) * 8)
395                                         __set_bit_le64(e, ext->errors_silent);
396                         }
397                 }
398         }
399 }
400 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php