diff options
-rw-r--r-- | fs/bcachefs/rebalance.c | 90 | ||||
-rw-r--r-- | fs/bcachefs/sb-errors_format.h | 4 |
2 files changed, 88 insertions, 6 deletions
diff --git a/fs/bcachefs/rebalance.c b/fs/bcachefs/rebalance.c index e84442e636da..f1497302332f 100644 --- a/fs/bcachefs/rebalance.c +++ b/fs/bcachefs/rebalance.c @@ -25,6 +25,8 @@ #include <linux/kthread.h> #include <linux/sched/cputime.h> +#define REBALANCE_WORK_SCAN_OFFSET (U64_MAX - 1) + /* bch_extent_rebalance: */ static const struct bch_extent_rebalance *bch2_bkey_ptrs_rebalance_opts(struct bkey_ptrs_c ptrs) @@ -219,6 +221,35 @@ int bch2_bkey_set_needs_rebalance(struct bch_fs *c, struct bch_inode_opts *opts, return 0; } +static int have_rebalance_scan_cookie(struct btree_trans *trans, u64 inum) +{ + /* + * If opts need to be propagated to the extent, a scan cookie should be + * present: + */ + CLASS(btree_iter, iter)(trans, BTREE_ID_rebalance_work, + SPOS(inum, REBALANCE_WORK_SCAN_OFFSET, U32_MAX), + BTREE_ITER_intent); + struct bkey_s_c k = bch2_btree_iter_peek_slot(&iter); + int ret = bkey_err(k); + if (ret) + return ret; + + if (k.k->type == KEY_TYPE_cookie) + return 1; + + if (!inum) + return 0; + + bch2_btree_iter_set_pos(&iter, SPOS(0, REBALANCE_WORK_SCAN_OFFSET, U32_MAX)); + k = bch2_btree_iter_peek_slot(&iter); + ret = bkey_err(k); + if (ret) + return ret; + + return k.k->type == KEY_TYPE_cookie; +} + static int bch2_get_update_rebalance_opts(struct btree_trans *trans, struct bch_inode_opts *io_opts, struct btree_iter *iter, @@ -226,6 +257,7 @@ static int bch2_get_update_rebalance_opts(struct btree_trans *trans, enum set_needs_rebalance_ctx ctx) { struct bch_fs *c = trans->c; + int ret = 0; BUG_ON(iter->flags & BTREE_ITER_is_extents); BUG_ON(iter->flags & BTREE_ITER_filter_snapshots); @@ -256,13 +288,61 @@ static int bch2_get_update_rebalance_opts(struct btree_trans *trans, struct bch_extent_rebalance new = io_opts_to_rebalance_opts(c, io_opts); - if (bkey_should_have_rb_opts(c, io_opts, k) + bool should_have_rb_opts = bkey_should_have_rb_opts(c, io_opts, k); + + if (should_have_rb_opts ? old && !memcmp(old, &new, sizeof(new)) : !old) return 0; + if (k.k->type != KEY_TYPE_reflink_v) { + if (old && !should_have_rb_opts) { + CLASS(printbuf, buf)(); + + prt_printf(&buf, "extent with unneeded rebalance opts:\n"); + bch2_bkey_val_to_text(&buf, c, k); + + fsck_err(trans, extent_io_opts_not_set, "%s", buf.buf); + } else { + ret = have_rebalance_scan_cookie(trans, k.k->p.inode); + if (ret < 0) + return ret; + + if (!ret) { + CLASS(printbuf, buf)(); + + prt_printf(&buf, "extent with incorrect/missing rebalance opts:\n"); + bch2_bkey_val_to_text(&buf, c, k); + const struct bch_extent_rebalance _old = {}; + if (!old) + old = &_old; + +#define x(_name) \ + if (old->_name != new._name) \ + prt_printf(&buf, "\n" #_name " %u != %u", \ + old->_name, new._name); \ + if (old->_name##_from_inode != new._name##_from_inode) \ + prt_printf(&buf, "\n" #_name "_from_inode %u != %u", \ + old->_name##_from_inode, new._name##_from_inode); + BCH_REBALANCE_OPTS() +#undef x + + if (old->unused != new.unused) + prt_printf(&buf, "\nunused %u != %u", old->unused, new.unused); + + if (old->type != new.type) + prt_printf(&buf, "\ntype %u != %u", old->type, new.type); + + prt_newline(&buf); + bch2_extent_rebalance_to_text(&buf, c, &new); + + fsck_err(trans, extent_io_opts_not_set, "%s", buf.buf); + } + } + } + struct bkey_i *n = bch2_trans_kmalloc(trans, bkey_bytes(k.k) + 8); - int ret = PTR_ERR_OR_ZERO(n); + ret = PTR_ERR_OR_ZERO(n); if (ret) return ret; @@ -270,10 +350,12 @@ static int bch2_get_update_rebalance_opts(struct btree_trans *trans, /* On successfull transaction commit, @k was invalidated: */ - return bch2_bkey_set_needs_rebalance(c, io_opts, n, ctx, 0) ?: + ret = bch2_bkey_set_needs_rebalance(c, io_opts, n, ctx, 0) ?: bch2_trans_update(trans, iter, n, BTREE_UPDATE_internal_snapshot_node) ?: bch2_trans_commit(trans, NULL, NULL, 0) ?: bch_err_throw(c, transaction_restart_commit); +fsck_err: + return ret; } static struct bch_inode_opts *bch2_extent_get_io_opts(struct btree_trans *trans, @@ -376,8 +458,6 @@ int bch2_extent_get_io_opts_one(struct btree_trans *trans, ctx); } -#define REBALANCE_WORK_SCAN_OFFSET (U64_MAX - 1) - static const char * const bch2_rebalance_state_strs[] = { #define x(t) #t, BCH_REBALANCE_STATES() diff --git a/fs/bcachefs/sb-errors_format.h b/fs/bcachefs/sb-errors_format.h index aa0ea1ec9f10..cac8236317b2 100644 --- a/fs/bcachefs/sb-errors_format.h +++ b/fs/bcachefs/sb-errors_format.h @@ -337,7 +337,9 @@ enum bch_fsck_flags { x(dirent_stray_data_after_cf_name, 305, 0) \ x(rebalance_work_incorrectly_set, 309, FSCK_AUTOFIX) \ x(rebalance_work_incorrectly_unset, 310, FSCK_AUTOFIX) \ - x(MAX, 326, 0) + x(extent_io_opts_not_set, 326, FSCK_AUTOFIX) \ + x(extent_io_opts_unneeded, 327, FSCK_AUTOFIX) \ + x(MAX, 328, 0) enum bch_sb_error_id { #define x(t, n, ...) BCH_FSCK_ERR_##t = n, |