summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2025-08-19 19:57:36 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2025-09-06 01:49:15 -0400
commitba533f0aa62ad91f4a1b8c665d4fb851563eaea0 (patch)
tree75e448b1a490b882fd0586e38bfb08bd58e3d2f8
parent1332c2ebe04f70b8a9528e4e69ec3104d9b86240 (diff)
bcachefs: Correct propagation of io options to indirect extents
io path options set from the inode should override existing indirect extent options, if REFLINK_P_MAY_UPDATE_OPTS is set. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/rebalance.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/fs/bcachefs/rebalance.c b/fs/bcachefs/rebalance.c
index fa73de7890da..44ef78b99543 100644
--- a/fs/bcachefs/rebalance.c
+++ b/fs/bcachefs/rebalance.c
@@ -246,13 +246,23 @@ static int bch2_get_update_rebalance_opts(struct btree_trans *trans,
BUG_ON(iter->flags & BTREE_ITER_is_extents);
BUG_ON(iter->flags & BTREE_ITER_filter_snapshots);
+ bool may_update_indirect = ctx == SET_NEEDS_REBALANCE_opt_change_indirect;
+
+ /*
+ * If it's an indirect extent, and we walked to it directly, we won't
+ * have the options from the inode that were directly applied: options
+ * from the extent take precedence - unless the io_opts option came from
+ * the inode and may_update_indirect is true (walked from a
+ * REFLINK_P_MAY_UPDATE_OPTIONS pointer).
+ */
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; \
+#define x(_name) \
+ if (r->_name##_from_inode && \
+ !(may_update_indirect && io_opts->_name##_from_inode)) { \
+ io_opts->_name = r->_name; \
+ io_opts->_name##_from_inode = true; \
}
BCH_REBALANCE_OPTS()
#undef x