1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifndef _BCACHEFS_BTREE_UPDATE_H |
3 | #define _BCACHEFS_BTREE_UPDATE_H |
4 | |
5 | #include "btree_iter.h" |
6 | #include "journal.h" |
7 | |
8 | struct bch_fs; |
9 | struct btree; |
10 | |
11 | void bch2_btree_node_prep_for_write(struct btree_trans *, |
12 | struct btree_path *, struct btree *); |
13 | bool bch2_btree_bset_insert_key(struct btree_trans *, struct btree_path *, |
14 | struct btree *, struct btree_node_iter *, |
15 | struct bkey_i *); |
16 | |
17 | int bch2_btree_node_flush0(struct journal *, struct journal_entry_pin *, u64); |
18 | int bch2_btree_node_flush1(struct journal *, struct journal_entry_pin *, u64); |
19 | void bch2_btree_add_journal_pin(struct bch_fs *, struct btree *, u64); |
20 | |
21 | void bch2_btree_insert_key_leaf(struct btree_trans *, struct btree_path *, |
22 | struct bkey_i *, u64); |
23 | |
24 | #define BCH_TRANS_COMMIT_FLAGS() \ |
25 | x(no_enospc, "don't check for enospc") \ |
26 | x(no_check_rw, "don't attempt to take a ref on c->writes") \ |
27 | x(lazy_rw, "go read-write if we haven't yet - only for use in recovery") \ |
28 | x(no_journal_res, "don't take a journal reservation, instead " \ |
29 | "pin journal entry referred to by trans->journal_res.seq") \ |
30 | x(journal_reclaim, "operation required for journal reclaim; may return error" \ |
31 | "instead of deadlocking if BCH_WATERMARK_reclaim not specified")\ |
32 | |
33 | enum __bch_trans_commit_flags { |
34 | /* First bits for bch_watermark: */ |
35 | __BCH_TRANS_COMMIT_FLAGS_START = BCH_WATERMARK_BITS, |
36 | #define x(n, ...) __BCH_TRANS_COMMIT_##n, |
37 | BCH_TRANS_COMMIT_FLAGS() |
38 | #undef x |
39 | }; |
40 | |
41 | enum bch_trans_commit_flags { |
42 | #define x(n, ...) BCH_TRANS_COMMIT_##n = BIT(__BCH_TRANS_COMMIT_##n), |
43 | BCH_TRANS_COMMIT_FLAGS() |
44 | #undef x |
45 | }; |
46 | |
47 | int bch2_btree_delete_extent_at(struct btree_trans *, struct btree_iter *, |
48 | unsigned, unsigned); |
49 | int bch2_btree_delete_at(struct btree_trans *, struct btree_iter *, unsigned); |
50 | int bch2_btree_delete(struct btree_trans *, enum btree_id, struct bpos, unsigned); |
51 | |
52 | int bch2_btree_insert_nonextent(struct btree_trans *, enum btree_id, |
53 | struct bkey_i *, enum btree_update_flags); |
54 | |
55 | int bch2_btree_insert_trans(struct btree_trans *, enum btree_id, struct bkey_i *, |
56 | enum btree_update_flags); |
57 | int bch2_btree_insert(struct bch_fs *, enum btree_id, struct bkey_i *, |
58 | struct disk_reservation *, int flags); |
59 | |
60 | int bch2_btree_delete_range_trans(struct btree_trans *, enum btree_id, |
61 | struct bpos, struct bpos, unsigned, u64 *); |
62 | int bch2_btree_delete_range(struct bch_fs *, enum btree_id, |
63 | struct bpos, struct bpos, unsigned, u64 *); |
64 | |
65 | int bch2_btree_bit_mod(struct btree_trans *, enum btree_id, struct bpos, bool); |
66 | int bch2_btree_bit_mod_buffered(struct btree_trans *, enum btree_id, struct bpos, bool); |
67 | |
68 | static inline int bch2_btree_delete_at_buffered(struct btree_trans *trans, |
69 | enum btree_id btree, struct bpos pos) |
70 | { |
71 | return bch2_btree_bit_mod_buffered(trans, btree, pos, false); |
72 | } |
73 | |
74 | int __bch2_insert_snapshot_whiteouts(struct btree_trans *, enum btree_id, |
75 | struct bpos, struct bpos); |
76 | |
77 | /* |
78 | * For use when splitting extents in existing snapshots: |
79 | * |
80 | * If @old_pos is an interior snapshot node, iterate over descendent snapshot |
81 | * nodes: for every descendent snapshot in whiche @old_pos is overwritten and |
82 | * not visible, emit a whiteout at @new_pos. |
83 | */ |
84 | static inline int bch2_insert_snapshot_whiteouts(struct btree_trans *trans, |
85 | enum btree_id btree, |
86 | struct bpos old_pos, |
87 | struct bpos new_pos) |
88 | { |
89 | if (!btree_type_has_snapshots(id: btree) || |
90 | bkey_eq(l: old_pos, r: new_pos)) |
91 | return 0; |
92 | |
93 | return __bch2_insert_snapshot_whiteouts(trans, btree, old_pos, new_pos); |
94 | } |
95 | |
96 | int bch2_trans_update_extent_overwrite(struct btree_trans *, struct btree_iter *, |
97 | enum btree_update_flags, |
98 | struct bkey_s_c, struct bkey_s_c); |
99 | |
100 | int bch2_bkey_get_empty_slot(struct btree_trans *, struct btree_iter *, |
101 | enum btree_id, struct bpos); |
102 | |
103 | int __must_check bch2_trans_update(struct btree_trans *, struct btree_iter *, |
104 | struct bkey_i *, enum btree_update_flags); |
105 | |
106 | struct jset_entry *__bch2_trans_jset_entry_alloc(struct btree_trans *, unsigned); |
107 | |
108 | static inline struct jset_entry *btree_trans_journal_entries_top(struct btree_trans *trans) |
109 | { |
110 | return (void *) ((u64 *) trans->journal_entries + trans->journal_entries_u64s); |
111 | } |
112 | |
113 | static inline struct jset_entry * |
114 | bch2_trans_jset_entry_alloc(struct btree_trans *trans, unsigned u64s) |
115 | { |
116 | if (!trans->journal_entries || |
117 | trans->journal_entries_u64s + u64s > trans->journal_entries_size) |
118 | return __bch2_trans_jset_entry_alloc(trans, u64s); |
119 | |
120 | struct jset_entry *e = btree_trans_journal_entries_top(trans); |
121 | trans->journal_entries_u64s += u64s; |
122 | return e; |
123 | } |
124 | |
125 | int bch2_btree_insert_clone_trans(struct btree_trans *, enum btree_id, struct bkey_i *); |
126 | |
127 | static inline int __must_check bch2_trans_update_buffered(struct btree_trans *trans, |
128 | enum btree_id btree, |
129 | struct bkey_i *k) |
130 | { |
131 | if (unlikely(trans->journal_replay_not_finished)) |
132 | return bch2_btree_insert_clone_trans(trans, btree, k); |
133 | |
134 | struct jset_entry *e = bch2_trans_jset_entry_alloc(trans, u64s: jset_u64s(u64s: k->k.u64s)); |
135 | int ret = PTR_ERR_OR_ZERO(ptr: e); |
136 | if (ret) |
137 | return ret; |
138 | |
139 | journal_entry_init(entry: e, type: BCH_JSET_ENTRY_write_buffer_keys, id: btree, level: 0, u64s: k->k.u64s); |
140 | bkey_copy(dst: e->start, src: k); |
141 | return 0; |
142 | } |
143 | |
144 | void bch2_trans_commit_hook(struct btree_trans *, |
145 | struct btree_trans_commit_hook *); |
146 | int __bch2_trans_commit(struct btree_trans *, unsigned); |
147 | |
148 | __printf(2, 3) int bch2_fs_log_msg(struct bch_fs *, const char *, ...); |
149 | __printf(2, 3) int bch2_journal_log_msg(struct bch_fs *, const char *, ...); |
150 | |
151 | /** |
152 | * bch2_trans_commit - insert keys at given iterator positions |
153 | * |
154 | * This is main entry point for btree updates. |
155 | * |
156 | * Return values: |
157 | * -EROFS: filesystem read only |
158 | * -EIO: journal or btree node IO error |
159 | */ |
160 | static inline int bch2_trans_commit(struct btree_trans *trans, |
161 | struct disk_reservation *disk_res, |
162 | u64 *journal_seq, |
163 | unsigned flags) |
164 | { |
165 | trans->disk_res = disk_res; |
166 | trans->journal_seq = journal_seq; |
167 | |
168 | return __bch2_trans_commit(trans, flags); |
169 | } |
170 | |
171 | #define commit_do(_trans, _disk_res, _journal_seq, _flags, _do) \ |
172 | lockrestart_do(_trans, _do ?: bch2_trans_commit(_trans, (_disk_res),\ |
173 | (_journal_seq), (_flags))) |
174 | |
175 | #define nested_commit_do(_trans, _disk_res, _journal_seq, _flags, _do) \ |
176 | nested_lockrestart_do(_trans, _do ?: bch2_trans_commit(_trans, (_disk_res),\ |
177 | (_journal_seq), (_flags))) |
178 | |
179 | #define bch2_trans_run(_c, _do) \ |
180 | ({ \ |
181 | struct btree_trans *trans = bch2_trans_get(_c); \ |
182 | int _ret = (_do); \ |
183 | bch2_trans_put(trans); \ |
184 | _ret; \ |
185 | }) |
186 | |
187 | #define bch2_trans_do(_c, _disk_res, _journal_seq, _flags, _do) \ |
188 | bch2_trans_run(_c, commit_do(trans, _disk_res, _journal_seq, _flags, _do)) |
189 | |
190 | #define trans_for_each_update(_trans, _i) \ |
191 | for (struct btree_insert_entry *_i = (_trans)->updates; \ |
192 | (_i) < (_trans)->updates + (_trans)->nr_updates; \ |
193 | (_i)++) |
194 | |
195 | static inline void bch2_trans_reset_updates(struct btree_trans *trans) |
196 | { |
197 | trans_for_each_update(trans, i) |
198 | bch2_path_put(trans, i->path, true); |
199 | |
200 | trans->nr_updates = 0; |
201 | trans->journal_entries_u64s = 0; |
202 | trans->hooks = NULL; |
203 | trans->extra_disk_res = 0; |
204 | |
205 | if (trans->fs_usage_deltas) { |
206 | trans->fs_usage_deltas->used = 0; |
207 | memset((void *) trans->fs_usage_deltas + |
208 | offsetof(struct replicas_delta_list, memset_start), 0, |
209 | (void *) &trans->fs_usage_deltas->memset_end - |
210 | (void *) &trans->fs_usage_deltas->memset_start); |
211 | } |
212 | } |
213 | |
214 | static inline struct bkey_i *__bch2_bkey_make_mut_noupdate(struct btree_trans *trans, struct bkey_s_c k, |
215 | unsigned type, unsigned min_bytes) |
216 | { |
217 | unsigned bytes = max_t(unsigned, min_bytes, bkey_bytes(k.k)); |
218 | struct bkey_i *mut; |
219 | |
220 | if (type && k.k->type != type) |
221 | return ERR_PTR(error: -ENOENT); |
222 | |
223 | mut = bch2_trans_kmalloc_nomemzero(trans, size: bytes); |
224 | if (!IS_ERR(ptr: mut)) { |
225 | bkey_reassemble(dst: mut, src: k); |
226 | |
227 | if (unlikely(bytes > bkey_bytes(k.k))) { |
228 | memset((void *) mut + bkey_bytes(k.k), 0, |
229 | bytes - bkey_bytes(k.k)); |
230 | mut->k.u64s = DIV_ROUND_UP(bytes, sizeof(u64)); |
231 | } |
232 | } |
233 | return mut; |
234 | } |
235 | |
236 | static inline struct bkey_i *bch2_bkey_make_mut_noupdate(struct btree_trans *trans, struct bkey_s_c k) |
237 | { |
238 | return __bch2_bkey_make_mut_noupdate(trans, k, type: 0, min_bytes: 0); |
239 | } |
240 | |
241 | #define bch2_bkey_make_mut_noupdate_typed(_trans, _k, _type) \ |
242 | bkey_i_to_##_type(__bch2_bkey_make_mut_noupdate(_trans, _k, \ |
243 | KEY_TYPE_##_type, sizeof(struct bkey_i_##_type))) |
244 | |
245 | static inline struct bkey_i *__bch2_bkey_make_mut(struct btree_trans *trans, struct btree_iter *iter, |
246 | struct bkey_s_c *k, unsigned flags, |
247 | unsigned type, unsigned min_bytes) |
248 | { |
249 | struct bkey_i *mut = __bch2_bkey_make_mut_noupdate(trans, k: *k, type, min_bytes); |
250 | int ret; |
251 | |
252 | if (IS_ERR(ptr: mut)) |
253 | return mut; |
254 | |
255 | ret = bch2_trans_update(trans, iter, mut, flags); |
256 | if (ret) |
257 | return ERR_PTR(error: ret); |
258 | |
259 | *k = bkey_i_to_s_c(k: mut); |
260 | return mut; |
261 | } |
262 | |
263 | static inline struct bkey_i *bch2_bkey_make_mut(struct btree_trans *trans, struct btree_iter *iter, |
264 | struct bkey_s_c *k, unsigned flags) |
265 | { |
266 | return __bch2_bkey_make_mut(trans, iter, k, flags, type: 0, min_bytes: 0); |
267 | } |
268 | |
269 | #define bch2_bkey_make_mut_typed(_trans, _iter, _k, _flags, _type) \ |
270 | bkey_i_to_##_type(__bch2_bkey_make_mut(_trans, _iter, _k, _flags,\ |
271 | KEY_TYPE_##_type, sizeof(struct bkey_i_##_type))) |
272 | |
273 | static inline struct bkey_i *__bch2_bkey_get_mut_noupdate(struct btree_trans *trans, |
274 | struct btree_iter *iter, |
275 | unsigned btree_id, struct bpos pos, |
276 | unsigned flags, unsigned type, unsigned min_bytes) |
277 | { |
278 | struct bkey_s_c k = __bch2_bkey_get_iter(trans, iter, |
279 | btree_id, pos, flags: flags|BTREE_ITER_INTENT, type); |
280 | struct bkey_i *ret = IS_ERR(ptr: k.k) |
281 | ? ERR_CAST(ptr: k.k) |
282 | : __bch2_bkey_make_mut_noupdate(trans, k, type: 0, min_bytes); |
283 | if (IS_ERR(ptr: ret)) |
284 | bch2_trans_iter_exit(trans, iter); |
285 | return ret; |
286 | } |
287 | |
288 | static inline struct bkey_i *bch2_bkey_get_mut_noupdate(struct btree_trans *trans, |
289 | struct btree_iter *iter, |
290 | unsigned btree_id, struct bpos pos, |
291 | unsigned flags) |
292 | { |
293 | return __bch2_bkey_get_mut_noupdate(trans, iter, btree_id, pos, flags, type: 0, min_bytes: 0); |
294 | } |
295 | |
296 | static inline struct bkey_i *__bch2_bkey_get_mut(struct btree_trans *trans, |
297 | struct btree_iter *iter, |
298 | unsigned btree_id, struct bpos pos, |
299 | unsigned flags, unsigned type, unsigned min_bytes) |
300 | { |
301 | struct bkey_i *mut = __bch2_bkey_get_mut_noupdate(trans, iter, |
302 | btree_id, pos, flags: flags|BTREE_ITER_INTENT, type, min_bytes); |
303 | int ret; |
304 | |
305 | if (IS_ERR(ptr: mut)) |
306 | return mut; |
307 | |
308 | ret = bch2_trans_update(trans, iter, mut, flags); |
309 | if (ret) { |
310 | bch2_trans_iter_exit(trans, iter); |
311 | return ERR_PTR(error: ret); |
312 | } |
313 | |
314 | return mut; |
315 | } |
316 | |
317 | static inline struct bkey_i *bch2_bkey_get_mut_minsize(struct btree_trans *trans, |
318 | struct btree_iter *iter, |
319 | unsigned btree_id, struct bpos pos, |
320 | unsigned flags, unsigned min_bytes) |
321 | { |
322 | return __bch2_bkey_get_mut(trans, iter, btree_id, pos, flags, type: 0, min_bytes); |
323 | } |
324 | |
325 | static inline struct bkey_i *bch2_bkey_get_mut(struct btree_trans *trans, |
326 | struct btree_iter *iter, |
327 | unsigned btree_id, struct bpos pos, |
328 | unsigned flags) |
329 | { |
330 | return __bch2_bkey_get_mut(trans, iter, btree_id, pos, flags, type: 0, min_bytes: 0); |
331 | } |
332 | |
333 | #define bch2_bkey_get_mut_typed(_trans, _iter, _btree_id, _pos, _flags, _type)\ |
334 | bkey_i_to_##_type(__bch2_bkey_get_mut(_trans, _iter, \ |
335 | _btree_id, _pos, _flags, \ |
336 | KEY_TYPE_##_type, sizeof(struct bkey_i_##_type))) |
337 | |
338 | static inline struct bkey_i *__bch2_bkey_alloc(struct btree_trans *trans, struct btree_iter *iter, |
339 | unsigned flags, unsigned type, unsigned val_size) |
340 | { |
341 | struct bkey_i *k = bch2_trans_kmalloc(trans, size: sizeof(*k) + val_size); |
342 | int ret; |
343 | |
344 | if (IS_ERR(ptr: k)) |
345 | return k; |
346 | |
347 | bkey_init(k: &k->k); |
348 | k->k.p = iter->pos; |
349 | k->k.type = type; |
350 | set_bkey_val_bytes(k: &k->k, bytes: val_size); |
351 | |
352 | ret = bch2_trans_update(trans, iter, k, flags); |
353 | if (unlikely(ret)) |
354 | return ERR_PTR(error: ret); |
355 | return k; |
356 | } |
357 | |
358 | #define bch2_bkey_alloc(_trans, _iter, _flags, _type) \ |
359 | bkey_i_to_##_type(__bch2_bkey_alloc(_trans, _iter, _flags, \ |
360 | KEY_TYPE_##_type, sizeof(struct bch_##_type))) |
361 | |
362 | #endif /* _BCACHEFS_BTREE_UPDATE_H */ |
363 | |