From 183e9c430ea9775fdd1f7097f309ef61471562fc Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Thu, 6 Jul 2023 19:23:27 -0400 Subject: [PATCH] bcachefs: Allow for unknown key types This adds a new helper for lookups bkey_ops for a given key type, which returns a null bkey_ops for unknown key types; various bkey_ops users are tweaked as well to handle unknown key types. Signed-off-by: Kent Overstreet --- fs/bcachefs/bkey_methods.c | 38 +++++++++++++++------------------ fs/bcachefs/bkey_methods.h | 12 +++++++++-- fs/bcachefs/btree_update_leaf.c | 10 +++++---- 3 files changed, 33 insertions(+), 27 deletions(-) diff --git a/fs/bcachefs/bkey_methods.c b/fs/bcachefs/bkey_methods.c index 79f3fbe925d5..59a4f4802ee9 100644 --- a/fs/bcachefs/bkey_methods.c +++ b/fs/bcachefs/bkey_methods.c @@ -118,17 +118,14 @@ const struct bkey_ops bch2_bkey_ops[] = { #undef x }; +const struct bkey_ops bch2_bkey_null_ops = { + .min_val_size = U8_MAX, +}; + int bch2_bkey_val_invalid(struct bch_fs *c, struct bkey_s_c k, unsigned flags, struct printbuf *err) { - const struct bkey_ops *ops; - - if (k.k->type >= KEY_TYPE_MAX) { - prt_printf(err, "invalid type (%u >= %u)", k.k->type, KEY_TYPE_MAX); - return -BCH_ERR_invalid_bkey; - } - - ops = &bch2_bkey_ops[k.k->type]; + const struct bkey_ops *ops = bch2_bkey_type_ops(k.k->type); if (bkey_val_bytes(k.k) < ops->min_val_size) { prt_printf(err, "bad val size (%zu < %u)", @@ -136,6 +133,9 @@ int bch2_bkey_val_invalid(struct bch_fs *c, struct bkey_s_c k, return -BCH_ERR_invalid_bkey; } + if (!ops->key_invalid) + return 0; + return ops->key_invalid(c, k, flags, err); } @@ -340,14 +340,10 @@ void bch2_bkey_to_text(struct printbuf *out, const struct bkey *k) void bch2_val_to_text(struct printbuf *out, struct bch_fs *c, struct bkey_s_c k) { - if (k.k->type < KEY_TYPE_MAX) { - const struct bkey_ops *ops = &bch2_bkey_ops[k.k->type]; + const struct bkey_ops *ops = bch2_bkey_type_ops(k.k->type); - if (likely(ops->val_to_text)) - ops->val_to_text(out, c, k); - } else { - prt_printf(out, "(invalid type %u)", k.k->type); - } + if (likely(ops->val_to_text)) + ops->val_to_text(out, c, k); } void bch2_bkey_val_to_text(struct printbuf *out, struct bch_fs *c, @@ -363,7 +359,7 @@ void bch2_bkey_val_to_text(struct printbuf *out, struct bch_fs *c, void bch2_bkey_swab_val(struct bkey_s k) { - const struct bkey_ops *ops = &bch2_bkey_ops[k.k->type]; + const struct bkey_ops *ops = bch2_bkey_type_ops(k.k->type); if (ops->swab) ops->swab(k); @@ -371,7 +367,7 @@ void bch2_bkey_swab_val(struct bkey_s k) bool bch2_bkey_normalize(struct bch_fs *c, struct bkey_s k) { - const struct bkey_ops *ops = &bch2_bkey_ops[k.k->type]; + const struct bkey_ops *ops = bch2_bkey_type_ops(k.k->type); return ops->key_normalize ? ops->key_normalize(c, k) @@ -380,11 +376,11 @@ bool bch2_bkey_normalize(struct bch_fs *c, struct bkey_s k) bool bch2_bkey_merge(struct bch_fs *c, struct bkey_s l, struct bkey_s_c r) { - const struct bkey_ops *ops = &bch2_bkey_ops[l.k->type]; + const struct bkey_ops *ops = bch2_bkey_type_ops(l.k->type); - return bch2_bkey_maybe_mergable(l.k, r.k) && + return ops->key_merge && + bch2_bkey_maybe_mergable(l.k, r.k) && (u64) l.k->size + r.k->size <= KEY_SIZE_MAX && - bch2_bkey_ops[l.k->type].key_merge && !bch2_key_merging_disabled && ops->key_merge(c, l, r); } @@ -509,7 +505,7 @@ void __bch2_bkey_compat(unsigned level, enum btree_id btree_id, if (big_endian != CPU_BIG_ENDIAN) bch2_bkey_swab_val(u); - ops = &bch2_bkey_ops[k->type]; + ops = bch2_bkey_type_ops(k->type); if (ops->compat) ops->compat(btree_id, version, big_endian, write, u); diff --git a/fs/bcachefs/bkey_methods.h b/fs/bcachefs/bkey_methods.h index a65756e306b0..32b86c74cc9a 100644 --- a/fs/bcachefs/bkey_methods.h +++ b/fs/bcachefs/bkey_methods.h @@ -11,6 +11,7 @@ struct bkey; enum btree_node_type; extern const char * const bch2_bkey_types[]; +extern const struct bkey_ops bch2_bkey_null_ops; /* * key_invalid: checks validity of @k, returns 0 if good or -EINVAL if bad. If @@ -41,6 +42,13 @@ struct bkey_ops { extern const struct bkey_ops bch2_bkey_ops[]; +static inline const struct bkey_ops *bch2_bkey_type_ops(enum bch_bkey_type type) +{ + return likely(type < KEY_TYPE_MAX) + ? &bch2_bkey_ops[type] + : &bch2_bkey_null_ops; +} + #define BKEY_INVALID_FROM_JOURNAL (1 << 1) int bch2_bkey_val_invalid(struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *); @@ -75,7 +83,7 @@ static inline int bch2_mark_key(struct btree_trans *trans, struct bkey_s_c old, struct bkey_s_c new, unsigned flags) { - const struct bkey_ops *ops = &bch2_bkey_ops[old.k->type ?: new.k->type]; + const struct bkey_ops *ops = bch2_bkey_type_ops(old.k->type ?: new.k->type); return ops->atomic_trigger ? ops->atomic_trigger(trans, btree, level, old, new, flags) @@ -125,7 +133,7 @@ static inline int bch2_trans_mark_key(struct btree_trans *trans, struct bkey_s_c old, struct bkey_i *new, unsigned flags) { - const struct bkey_ops *ops = &bch2_bkey_ops[old.k->type ?: new->k.type]; + const struct bkey_ops *ops = bch2_bkey_type_ops(old.k->type ?: new->k.type); return ops->trans_trigger ? ops->trans_trigger(trans, btree_id, level, old, new, flags) diff --git a/fs/bcachefs/btree_update_leaf.c b/fs/bcachefs/btree_update_leaf.c index ce6ec28d8f60..ad058b9252e1 100644 --- a/fs/bcachefs/btree_update_leaf.c +++ b/fs/bcachefs/btree_update_leaf.c @@ -407,6 +407,8 @@ static int run_one_mem_trigger(struct btree_trans *trans, { struct bkey_s_c old = { &i->old_k, i->old_v }; struct bkey_i *new = i->k; + const struct bkey_ops *old_ops = bch2_bkey_type_ops(old.k->type); + const struct bkey_ops *new_ops = bch2_bkey_type_ops(i->k->k.type); int ret; verify_update_old_key(trans, i); @@ -417,8 +419,7 @@ static int run_one_mem_trigger(struct btree_trans *trans, if (!btree_node_type_needs_gc(i->btree_id)) return 0; - if (bch2_bkey_ops[old.k->type].atomic_trigger == - bch2_bkey_ops[i->k->k.type].atomic_trigger && + if (old_ops->atomic_trigger == new_ops->atomic_trigger && ((1U << old.k->type) & BTREE_TRIGGER_WANTS_OLD_AND_NEW)) { ret = bch2_mark_key(trans, i->btree_id, i->level, old, bkey_i_to_s_c(new), @@ -450,6 +451,8 @@ static int run_one_trans_trigger(struct btree_trans *trans, struct btree_insert_ */ struct bkey old_k = i->old_k; struct bkey_s_c old = { &old_k, i->old_v }; + const struct bkey_ops *old_ops = bch2_bkey_type_ops(old.k->type); + const struct bkey_ops *new_ops = bch2_bkey_type_ops(i->k->k.type); verify_update_old_key(trans, i); @@ -459,8 +462,7 @@ static int run_one_trans_trigger(struct btree_trans *trans, struct btree_insert_ if (!i->insert_trigger_run && !i->overwrite_trigger_run && - bch2_bkey_ops[old.k->type].trans_trigger == - bch2_bkey_ops[i->k->k.type].trans_trigger && + old_ops->trans_trigger == new_ops->trans_trigger && ((1U << old.k->type) & BTREE_TRIGGER_WANTS_OLD_AND_NEW)) { i->overwrite_trigger_run = true; i->insert_trigger_run = true;