summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/bcachefs/rebalance.c90
-rw-r--r--fs/bcachefs/sb-errors_format.h4
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,