mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-15 21:23:23 +00:00
bcachefs: get_update_rebalance_opts()
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>
This commit is contained in:
parent
e2aeaaa5c9
commit
f14488c8cf
@ -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)
|
||||
{
|
||||
|
@ -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: */
|
||||
|
@ -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;
|
||||
|
@ -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 *);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user