1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifndef _BCACHEFS_BKEY_METHODS_H |
3 | #define _BCACHEFS_BKEY_METHODS_H |
4 | |
5 | #include "bkey.h" |
6 | |
7 | struct bch_fs; |
8 | struct btree; |
9 | struct btree_trans; |
10 | struct bkey; |
11 | enum btree_node_type; |
12 | |
13 | extern const char * const bch2_bkey_types[]; |
14 | extern const struct bkey_ops bch2_bkey_null_ops; |
15 | |
16 | /* |
17 | * key_invalid: checks validity of @k, returns 0 if good or -EINVAL if bad. If |
18 | * invalid, entire key will be deleted. |
19 | * |
20 | * When invalid, error string is returned via @err. @rw indicates whether key is |
21 | * being read or written; more aggressive checks can be enabled when rw == WRITE. |
22 | */ |
23 | struct bkey_ops { |
24 | int (*key_invalid)(struct bch_fs *c, struct bkey_s_c k, |
25 | enum bkey_invalid_flags flags, struct printbuf *err); |
26 | void (*val_to_text)(struct printbuf *, struct bch_fs *, |
27 | struct bkey_s_c); |
28 | void (*swab)(struct bkey_s); |
29 | bool (*key_normalize)(struct bch_fs *, struct bkey_s); |
30 | bool (*key_merge)(struct bch_fs *, struct bkey_s, struct bkey_s_c); |
31 | int (*trigger)(struct btree_trans *, enum btree_id, unsigned, |
32 | struct bkey_s_c, struct bkey_s, unsigned); |
33 | void (*compat)(enum btree_id id, unsigned version, |
34 | unsigned big_endian, int write, |
35 | struct bkey_s); |
36 | |
37 | /* Size of value type when first created: */ |
38 | unsigned min_val_size; |
39 | }; |
40 | |
41 | extern const struct bkey_ops bch2_bkey_ops[]; |
42 | |
43 | static inline const struct bkey_ops *bch2_bkey_type_ops(enum bch_bkey_type type) |
44 | { |
45 | return likely(type < KEY_TYPE_MAX) |
46 | ? &bch2_bkey_ops[type] |
47 | : &bch2_bkey_null_ops; |
48 | } |
49 | |
50 | int bch2_bkey_val_invalid(struct bch_fs *, struct bkey_s_c, |
51 | enum bkey_invalid_flags, struct printbuf *); |
52 | int __bch2_bkey_invalid(struct bch_fs *, struct bkey_s_c, enum btree_node_type, |
53 | enum bkey_invalid_flags, struct printbuf *); |
54 | int bch2_bkey_invalid(struct bch_fs *, struct bkey_s_c, enum btree_node_type, |
55 | enum bkey_invalid_flags, struct printbuf *); |
56 | int bch2_bkey_in_btree_node(struct bch_fs *, struct btree *, |
57 | struct bkey_s_c, struct printbuf *); |
58 | |
59 | void bch2_bpos_to_text(struct printbuf *, struct bpos); |
60 | void bch2_bkey_to_text(struct printbuf *, const struct bkey *); |
61 | void bch2_val_to_text(struct printbuf *, struct bch_fs *, |
62 | struct bkey_s_c); |
63 | void bch2_bkey_val_to_text(struct printbuf *, struct bch_fs *, |
64 | struct bkey_s_c); |
65 | |
66 | void bch2_bkey_swab_val(struct bkey_s); |
67 | |
68 | bool bch2_bkey_normalize(struct bch_fs *, struct bkey_s); |
69 | |
70 | static inline bool bch2_bkey_maybe_mergable(const struct bkey *l, const struct bkey *r) |
71 | { |
72 | return l->type == r->type && |
73 | !bversion_cmp(l: l->version, r: r->version) && |
74 | bpos_eq(l: l->p, r: bkey_start_pos(k: r)); |
75 | } |
76 | |
77 | bool bch2_bkey_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c); |
78 | |
79 | enum btree_update_flags { |
80 | __BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE = __BTREE_ITER_FLAGS_END, |
81 | __BTREE_UPDATE_NOJOURNAL, |
82 | __BTREE_UPDATE_KEY_CACHE_RECLAIM, |
83 | |
84 | __BTREE_TRIGGER_NORUN, |
85 | __BTREE_TRIGGER_TRANSACTIONAL, |
86 | __BTREE_TRIGGER_ATOMIC, |
87 | __BTREE_TRIGGER_GC, |
88 | __BTREE_TRIGGER_INSERT, |
89 | __BTREE_TRIGGER_OVERWRITE, |
90 | __BTREE_TRIGGER_BUCKET_INVALIDATE, |
91 | }; |
92 | |
93 | #define BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE (1U << __BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE) |
94 | #define BTREE_UPDATE_NOJOURNAL (1U << __BTREE_UPDATE_NOJOURNAL) |
95 | #define BTREE_UPDATE_KEY_CACHE_RECLAIM (1U << __BTREE_UPDATE_KEY_CACHE_RECLAIM) |
96 | |
97 | /* Don't run triggers at all */ |
98 | #define BTREE_TRIGGER_NORUN (1U << __BTREE_TRIGGER_NORUN) |
99 | |
100 | /* |
101 | * If set, we're running transactional triggers as part of a transaction commit: |
102 | * triggers may generate new updates |
103 | * |
104 | * If cleared, and either BTREE_TRIGGER_INSERT|BTREE_TRIGGER_OVERWRITE are set, |
105 | * we're running atomic triggers during a transaction commit: we have our |
106 | * journal reservation, we're holding btree node write locks, and we know the |
107 | * transaction is going to commit (returning an error here is a fatal error, |
108 | * causing us to go emergency read-only) |
109 | */ |
110 | #define BTREE_TRIGGER_TRANSACTIONAL (1U << __BTREE_TRIGGER_TRANSACTIONAL) |
111 | #define BTREE_TRIGGER_ATOMIC (1U << __BTREE_TRIGGER_ATOMIC) |
112 | |
113 | /* We're in gc/fsck: running triggers to recalculate e.g. disk usage */ |
114 | #define BTREE_TRIGGER_GC (1U << __BTREE_TRIGGER_GC) |
115 | |
116 | /* @new is entering the btree */ |
117 | #define BTREE_TRIGGER_INSERT (1U << __BTREE_TRIGGER_INSERT) |
118 | |
119 | /* @old is leaving the btree */ |
120 | #define BTREE_TRIGGER_OVERWRITE (1U << __BTREE_TRIGGER_OVERWRITE) |
121 | |
122 | /* signal from bucket invalidate path to alloc trigger */ |
123 | #define BTREE_TRIGGER_BUCKET_INVALIDATE (1U << __BTREE_TRIGGER_BUCKET_INVALIDATE) |
124 | |
125 | static inline int bch2_key_trigger(struct btree_trans *trans, |
126 | enum btree_id btree, unsigned level, |
127 | struct bkey_s_c old, struct bkey_s new, |
128 | unsigned flags) |
129 | { |
130 | const struct bkey_ops *ops = bch2_bkey_type_ops(type: old.k->type ?: new.k->type); |
131 | |
132 | return ops->trigger |
133 | ? ops->trigger(trans, btree, level, old, new, flags) |
134 | : 0; |
135 | } |
136 | |
137 | static inline int bch2_key_trigger_old(struct btree_trans *trans, |
138 | enum btree_id btree_id, unsigned level, |
139 | struct bkey_s_c old, unsigned flags) |
140 | { |
141 | struct bkey_i deleted; |
142 | |
143 | bkey_init(k: &deleted.k); |
144 | deleted.k.p = old.k->p; |
145 | |
146 | return bch2_key_trigger(trans, btree: btree_id, level, old, new: bkey_i_to_s(k: &deleted), |
147 | BTREE_TRIGGER_OVERWRITE|flags); |
148 | } |
149 | |
150 | static inline int bch2_key_trigger_new(struct btree_trans *trans, |
151 | enum btree_id btree_id, unsigned level, |
152 | struct bkey_s new, unsigned flags) |
153 | { |
154 | struct bkey_i deleted; |
155 | |
156 | bkey_init(k: &deleted.k); |
157 | deleted.k.p = new.k->p; |
158 | |
159 | return bch2_key_trigger(trans, btree: btree_id, level, old: bkey_i_to_s_c(k: &deleted), new, |
160 | BTREE_TRIGGER_INSERT|flags); |
161 | } |
162 | |
163 | void bch2_bkey_renumber(enum btree_node_type, struct bkey_packed *, int); |
164 | |
165 | void __bch2_bkey_compat(unsigned, enum btree_id, unsigned, unsigned, |
166 | int, struct bkey_format *, struct bkey_packed *); |
167 | |
168 | static inline void bch2_bkey_compat(unsigned level, enum btree_id btree_id, |
169 | unsigned version, unsigned big_endian, |
170 | int write, |
171 | struct bkey_format *f, |
172 | struct bkey_packed *k) |
173 | { |
174 | if (version < bcachefs_metadata_version_current || |
175 | big_endian != CPU_BIG_ENDIAN) |
176 | __bch2_bkey_compat(level, btree_id, version, |
177 | big_endian, write, f, k); |
178 | |
179 | } |
180 | |
181 | #endif /* _BCACHEFS_BKEY_METHODS_H */ |
182 | |