diff options
Diffstat (limited to 'fs/bcachefs')
-rw-r--r-- | fs/bcachefs/ec.c | 9 | ||||
-rw-r--r-- | fs/bcachefs/move.c | 4 | ||||
-rw-r--r-- | fs/bcachefs/rebalance.c | 107 | ||||
-rw-r--r-- | fs/bcachefs/rebalance.h | 3 | ||||
-rw-r--r-- | fs/bcachefs/sb-errors_format.h | 4 |
5 files changed, 115 insertions, 12 deletions
diff --git a/fs/bcachefs/ec.c b/fs/bcachefs/ec.c index c2840cb674b2..81a92b907b63 100644 --- a/fs/bcachefs/ec.c +++ b/fs/bcachefs/ec.c @@ -22,6 +22,7 @@ #include "io_write.h" #include "keylist.h" #include "lru.h" +#include "rebalance.h" #include "recovery.h" #include "replicas.h" #include "super-io.h" @@ -1129,7 +1130,13 @@ static int ec_stripe_update_extent(struct btree_trans *trans, (union bch_extent_entry *) ec_ptr, (union bch_extent_entry *) &stripe_ptr); - ret = bch2_trans_update(trans, &iter, n, 0); + struct bch_inode_opts opts; + + ret = bch2_extent_get_io_opts_one(trans, &opts, &iter, bkey_i_to_s_c(n), + SET_NEEDS_REBALANCE_other) ?: + bch2_bkey_set_needs_rebalance(trans->c, &opts, n, + SET_NEEDS_REBALANCE_other, 0) ?: + bch2_trans_update(trans, &iter, n, 0); out: bch2_trans_iter_exit(&iter); return ret; diff --git a/fs/bcachefs/move.c b/fs/bcachefs/move.c index 62aeb54ef11b..0444083ec92a 100644 --- a/fs/bcachefs/move.c +++ b/fs/bcachefs/move.c @@ -790,8 +790,8 @@ static int __bch2_move_data_phys(struct moving_context *ctxt, goto next; if (!bp.v->level) { - ret = bch2_extent_get_io_opts_one(trans, &io_opts, &iter, k, - SET_NEEDS_REBALANCE_other); + ret = bch2_extent_get_apply_io_opts_one(trans, &io_opts, &iter, k, + SET_NEEDS_REBALANCE_other); if (ret) { bch2_trans_iter_exit(&iter); continue; diff --git a/fs/bcachefs/rebalance.c b/fs/bcachefs/rebalance.c index e84442e636da..4fed428a9266 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, @@ -340,8 +422,7 @@ struct bch_inode_opts *bch2_extent_get_apply_io_opts(struct btree_trans *trans, if (IS_ERR(opts) || btree_iter_path(trans, extent_iter)->level) return opts; - int ret = bch2_get_update_rebalance_opts(trans, opts, extent_iter, extent_k, - SET_NEEDS_REBALANCE_other); + int ret = bch2_get_update_rebalance_opts(trans, opts, extent_iter, extent_k, ctx); return ret ? ERR_PTR(ret) : opts; } @@ -372,11 +453,21 @@ int bch2_extent_get_io_opts_one(struct btree_trans *trans, } } - return bch2_get_update_rebalance_opts(trans, io_opts, extent_iter, extent_k, - ctx); + return 0; } -#define REBALANCE_WORK_SCAN_OFFSET (U64_MAX - 1) +int bch2_extent_get_apply_io_opts_one(struct btree_trans *trans, + struct bch_inode_opts *io_opts, + struct btree_iter *extent_iter, + struct bkey_s_c extent_k, + enum set_needs_rebalance_ctx ctx) +{ + int ret = bch2_extent_get_io_opts_one(trans, io_opts, extent_iter, extent_k, ctx); + if (ret || btree_iter_path(trans, extent_iter)->level) + return ret; + + return bch2_get_update_rebalance_opts(trans, io_opts, extent_iter, extent_k, ctx); +} static const char * const bch2_rebalance_state_strs[] = { #define x(t) #t, diff --git a/fs/bcachefs/rebalance.h b/fs/bcachefs/rebalance.h index 7a4e3a56d5a2..bff91aa0102e 100644 --- a/fs/bcachefs/rebalance.h +++ b/fs/bcachefs/rebalance.h @@ -72,6 +72,9 @@ struct bch_inode_opts *bch2_extent_get_apply_io_opts(struct btree_trans *, int bch2_extent_get_io_opts_one(struct btree_trans *, struct bch_inode_opts *, struct btree_iter *, struct bkey_s_c, enum set_needs_rebalance_ctx); +int bch2_extent_get_apply_io_opts_one(struct btree_trans *, struct bch_inode_opts *, + struct btree_iter *, struct bkey_s_c, + enum set_needs_rebalance_ctx); int bch2_set_rebalance_needs_scan_trans(struct btree_trans *, u64); int bch2_set_rebalance_needs_scan(struct bch_fs *, u64 inum); 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, |