]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bcachefs: get_update_rebalance_opts()
authorKent Overstreet <kent.overstreet@linux.dev>
Sun, 20 Oct 2024 01:41:20 +0000 (21:41 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sat, 21 Dec 2024 06:36:16 +0000 (01:36 -0500)
bch2_move_get_io_opts() now synchronizes options loaded from the
filesystem and inode (if present, i.e. not walking the reflink btree
directly) with options from the bch_extent_rebalance_entry, updating the
extent if necessary.

Since bch_extent_rebalance tracks where its option came from we can
preserve "inode options override filesystem options", even for indirect
extents where we don't have access to the inode the options came from.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/extents.c
fs/bcachefs/extents.h
fs/bcachefs/move.c
fs/bcachefs/move.h
fs/bcachefs/rebalance.c

index 467ffed0809e0f84630f7d9f35bcc01c726a8b98..4988056ab4f1753b9b87c5a811bb407469456b59 100644 (file)
@@ -1521,6 +1521,23 @@ incompressible:
        return sectors;
 }
 
+bool bch2_bkey_rebalance_needs_update(struct bch_fs *c, struct bch_io_opts *opts,
+                                     struct bkey_s_c k)
+{
+       if (!bkey_extent_is_direct_data(k.k))
+               return 0;
+
+       const struct bch_extent_rebalance *old = bch2_bkey_rebalance_opts(k);
+
+       if (k.k->type == KEY_TYPE_reflink_v ||
+           bch2_bkey_ptrs_need_rebalance(c, k, opts->background_target, opts->background_compression)) {
+               struct bch_extent_rebalance new = io_opts_to_rebalance_opts(opts);
+               return old == NULL || memcmp(old, &new, sizeof(new));
+       } else {
+               return old != NULL;
+       }
+}
+
 int bch2_bkey_set_needs_rebalance(struct bch_fs *c, struct bch_io_opts *opts,
                                  struct bkey_i *_k)
 {
index 97af0d6e431911e602b000ddb039f72bd5131e5c..abe7d4b2fc6b0f0ab1e3e907129c549a5705e1b2 100644 (file)
@@ -715,6 +715,7 @@ unsigned bch2_bkey_ptrs_need_rebalance(struct bch_fs *, struct bkey_s_c,
                                       unsigned, unsigned);
 u64 bch2_bkey_sectors_need_rebalance(struct bch_fs *, struct bkey_s_c);
 
+bool bch2_bkey_rebalance_needs_update(struct bch_fs *, struct bch_io_opts *, struct bkey_s_c);
 int bch2_bkey_set_needs_rebalance(struct bch_fs *, struct bch_io_opts *, struct bkey_i *);
 
 /* Generic extent code: */
index 0ef4a86850bbc8773b1315f4bb88bfd41c1b84a4..1003f7fe4f50b074a89d137f018bc0821a7d7bec 100644 (file)
@@ -379,14 +379,57 @@ err:
        return ret;
 }
 
-struct bch_io_opts *bch2_move_get_io_opts(struct btree_trans *trans,
+static int get_update_rebalance_opts(struct btree_trans *trans,
+                                    struct bch_io_opts *io_opts,
+                                    struct btree_iter *iter,
+                                    struct bkey_s_c k)
+{
+       BUG_ON(iter->flags & BTREE_ITER_is_extents);
+       BUG_ON(iter->flags & BTREE_ITER_filter_snapshots);
+
+       const struct bch_extent_rebalance *r = k.k->type == KEY_TYPE_reflink_v
+               ? bch2_bkey_rebalance_opts(k) : NULL;
+       if (r) {
+#define x(_name)                                                       \
+               if (r->_name##_from_inode) {                            \
+                       io_opts->_name = r->_name;                      \
+                       io_opts->_name##_from_inode = true;             \
+               }
+               BCH_REBALANCE_OPTS()
+#undef x
+       }
+
+       if (!bch2_bkey_rebalance_needs_update(trans->c, io_opts, k))
+               return 0;
+
+       struct bkey_i *n = bch2_trans_kmalloc(trans, bkey_bytes(k.k) + 8);
+       int ret = PTR_ERR_OR_ZERO(n);
+       if (ret)
+               return ret;
+
+       bkey_reassemble(n, k);
+
+       /* On successfull transaction commit, @k was invalidated: */
+
+       return bch2_bkey_set_needs_rebalance(trans->c, io_opts, n) ?:
+               bch2_trans_update(trans, iter, n, BTREE_UPDATE_internal_snapshot_node) ?:
+               bch2_trans_commit(trans, NULL, NULL, 0) ?:
+               -BCH_ERR_transaction_restart_nested;
+}
+
+static struct bch_io_opts *bch2_move_get_io_opts(struct btree_trans *trans,
                          struct per_snapshot_io_opts *io_opts,
+                         struct btree_iter *extent_iter,
                          struct bkey_s_c extent_k)
 {
        struct bch_fs *c = trans->c;
        u32 restart_count = trans->restart_count;
+       struct bch_io_opts *opts_ret = &io_opts->fs_io_opts;
        int ret = 0;
 
+       if (extent_k.k->type == KEY_TYPE_reflink_v)
+               goto out;
+
        if (io_opts->cur_inum != extent_k.k->p.inode) {
                io_opts->d.nr = 0;
 
@@ -415,43 +458,46 @@ struct bch_io_opts *bch2_move_get_io_opts(struct btree_trans *trans,
 
        if (extent_k.k->p.snapshot)
                darray_for_each(io_opts->d, i)
-                       if (bch2_snapshot_is_ancestor(c, extent_k.k->p.snapshot, i->snapshot))
-                               return &i->io_opts;
-
-       return &io_opts->fs_io_opts;
+                       if (bch2_snapshot_is_ancestor(c, extent_k.k->p.snapshot, i->snapshot)) {
+                               opts_ret = &i->io_opts;
+                               break;
+                       }
+out:
+       ret = get_update_rebalance_opts(trans, opts_ret, extent_iter, extent_k);
+       if (ret)
+               return ERR_PTR(ret);
+       return opts_ret;
 }
 
 int bch2_move_get_io_opts_one(struct btree_trans *trans,
                              struct bch_io_opts *io_opts,
+                             struct btree_iter *extent_iter,
                              struct bkey_s_c extent_k)
 {
-       struct btree_iter iter;
-       struct bkey_s_c k;
-       int ret;
+       struct bch_fs *c = trans->c;
+
+       *io_opts = bch2_opts_to_inode_opts(c->opts);
 
        /* reflink btree? */
-       if (!extent_k.k->p.inode) {
-               *io_opts = bch2_opts_to_inode_opts(trans->c->opts);
-               return 0;
-       }
+       if (!extent_k.k->p.inode)
+               goto out;
 
-       k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_inodes,
+       struct btree_iter inode_iter;
+       struct bkey_s_c inode_k = bch2_bkey_get_iter(trans, &inode_iter, BTREE_ID_inodes,
                               SPOS(0, extent_k.k->p.inode, extent_k.k->p.snapshot),
                               BTREE_ITER_cached);
-       ret = bkey_err(k);
+       int ret = bkey_err(inode_k);
        if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
                return ret;
 
-       if (!ret && bkey_is_inode(k.k)) {
+       if (!ret && bkey_is_inode(inode_k.k)) {
                struct bch_inode_unpacked inode;
-               bch2_inode_unpack(k, &inode);
-               bch2_inode_opts_get(io_opts, trans->c, &inode);
-       } else {
-               *io_opts = bch2_opts_to_inode_opts(trans->c->opts);
+               bch2_inode_unpack(inode_k, &inode);
+               bch2_inode_opts_get(io_opts, c, &inode);
        }
-
-       bch2_trans_iter_exit(trans, &iter);
-       return 0;
+       bch2_trans_iter_exit(trans, &inode_iter);
+out:
+       return get_update_rebalance_opts(trans, io_opts, extent_iter, extent_k);
 }
 
 int bch2_move_ratelimit(struct moving_context *ctxt)
@@ -552,7 +598,7 @@ static int bch2_move_data_btree(struct moving_context *ctxt,
                if (!bkey_extent_is_direct_data(k.k))
                        goto next_nondata;
 
-               io_opts = bch2_move_get_io_opts(trans, &snapshot_io_opts, k);
+               io_opts = bch2_move_get_io_opts(trans, &snapshot_io_opts, &iter, k);
                ret = PTR_ERR_OR_ZERO(io_opts);
                if (ret)
                        continue;
@@ -728,7 +774,7 @@ int bch2_evacuate_bucket(struct moving_context *ctxt,
                        bch2_bkey_buf_reassemble(&sk, c, k);
                        k = bkey_i_to_s_c(sk.k);
 
-                       ret = bch2_move_get_io_opts_one(trans, &io_opts, k);
+                       ret = bch2_move_get_io_opts_one(trans, &io_opts, &iter, k);
                        if (ret) {
                                bch2_trans_iter_exit(trans, &iter);
                                continue;
index 9baf3093a678a69dd428627dc0297fc1c2a61c69..51e0505a8156afc5b8d2662c2d8e88f5b8f5f1ad 100644 (file)
@@ -110,9 +110,8 @@ static inline void per_snapshot_io_opts_exit(struct per_snapshot_io_opts *io_opt
        darray_exit(&io_opts->d);
 }
 
-struct bch_io_opts *bch2_move_get_io_opts(struct btree_trans *,
-                               struct per_snapshot_io_opts *, struct bkey_s_c);
-int bch2_move_get_io_opts_one(struct btree_trans *, struct bch_io_opts *, struct bkey_s_c);
+int bch2_move_get_io_opts_one(struct btree_trans *, struct bch_io_opts *,
+                             struct btree_iter *, struct bkey_s_c);
 
 int bch2_scan_old_btree_nodes(struct bch_fs *, struct bch_move_stats *);
 
index 926b9d5eba4562cd853bb774a7cd934a250494d9..e79459a5891d0650f360d040afc69ec4bb7e087c 100644 (file)
@@ -216,7 +216,7 @@ static int do_rebalance_extent(struct moving_context *ctxt,
        if (ret || !k.k)
                goto out;
 
-       ret = bch2_move_get_io_opts_one(trans, &io_opts, k);
+       ret = bch2_move_get_io_opts_one(trans, &io_opts, extent_iter, k);
        if (ret)
                goto out;