Commit | Line | Data |
---|---|---|
1c6fdbd8 KO |
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; | |
1c6fdbd8 | 10 | |
1ff7849f KO |
11 | void bch2_btree_node_prep_for_write(struct btree_trans *, |
12 | struct btree_path *, struct btree *); | |
67e0dd8f | 13 | bool bch2_btree_bset_insert_key(struct btree_trans *, struct btree_path *, |
9f6bd307 KO |
14 | struct btree *, struct btree_node_iter *, |
15 | struct bkey_i *); | |
83ec519a KO |
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); | |
6357d607 | 19 | void bch2_btree_add_journal_pin(struct bch_fs *, struct btree *, u64); |
1c6fdbd8 | 20 | |
920e69bc KO |
21 | void bch2_btree_insert_key_leaf(struct btree_trans *, struct btree_path *, |
22 | struct bkey_i *, u64); | |
23 | ||
cb52d23e KO |
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 { | |
ec14fc60 | 34 | /* First bits for bch_watermark: */ |
cb52d23e KO |
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 | |
1c6fdbd8 KO |
39 | }; |
40 | ||
cb52d23e KO |
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 | }; | |
2ca88e5a | 46 | |
449ceafb KO |
47 | void bch2_trans_commit_flags_to_text(struct printbuf *, enum bch_trans_commit_flags); |
48 | ||
aae29082 KO |
49 | int bch2_btree_delete_extent_at(struct btree_trans *, struct btree_iter *, |
50 | unsigned, unsigned); | |
0564b167 | 51 | int bch2_btree_delete_at(struct btree_trans *, struct btree_iter *, unsigned); |
aaad530a | 52 | int bch2_btree_delete(struct btree_trans *, enum btree_id, struct bpos, unsigned); |
1c6fdbd8 | 53 | |
2798143a | 54 | int bch2_btree_insert_nonextent(struct btree_trans *, enum btree_id, |
5dd8c60e | 55 | struct bkey_i *, enum btree_iter_update_trigger_flags); |
2798143a | 56 | |
aef32bf7 | 57 | int bch2_btree_insert_trans(struct btree_trans *, enum btree_id, struct bkey_i *, |
5dd8c60e | 58 | enum btree_iter_update_trigger_flags); |
1c6fdbd8 | 59 | int bch2_btree_insert(struct bch_fs *, enum btree_id, struct bkey_i *, |
96dea3d5 | 60 | struct disk_reservation *, int flags); |
1c6fdbd8 | 61 | |
087c2019 | 62 | int bch2_btree_delete_range_trans(struct btree_trans *, enum btree_id, |
ef1669ff | 63 | struct bpos, struct bpos, unsigned, u64 *); |
1c6fdbd8 | 64 | int bch2_btree_delete_range(struct bch_fs *, enum btree_id, |
d248ee56 | 65 | struct bpos, struct bpos, unsigned, u64 *); |
1c6fdbd8 | 66 | |
e07c28ab | 67 | int bch2_btree_bit_mod(struct btree_trans *, enum btree_id, struct bpos, bool); |
506b1876 | 68 | int bch2_btree_bit_mod_buffered(struct btree_trans *, enum btree_id, struct bpos, bool); |
8e992c6c | 69 | |
c259bd95 KO |
70 | static inline int bch2_btree_delete_at_buffered(struct btree_trans *trans, |
71 | enum btree_id btree, struct bpos pos) | |
72 | { | |
506b1876 | 73 | return bch2_btree_bit_mod_buffered(trans, btree, pos, false); |
c259bd95 KO |
74 | } |
75 | ||
ad520141 KO |
76 | int __bch2_insert_snapshot_whiteouts(struct btree_trans *, enum btree_id, |
77 | struct bpos, struct bpos); | |
78 | ||
79 | /* | |
80 | * For use when splitting extents in existing snapshots: | |
81 | * | |
82 | * If @old_pos is an interior snapshot node, iterate over descendent snapshot | |
83 | * nodes: for every descendent snapshot in whiche @old_pos is overwritten and | |
84 | * not visible, emit a whiteout at @new_pos. | |
85 | */ | |
86 | static inline int bch2_insert_snapshot_whiteouts(struct btree_trans *trans, | |
87 | enum btree_id btree, | |
88 | struct bpos old_pos, | |
89 | struct bpos new_pos) | |
90 | { | |
91 | if (!btree_type_has_snapshots(btree) || | |
92 | bkey_eq(old_pos, new_pos)) | |
93 | return 0; | |
94 | ||
95 | return __bch2_insert_snapshot_whiteouts(trans, btree, old_pos, new_pos); | |
96 | } | |
97 | ||
85beefef | 98 | int bch2_trans_update_extent_overwrite(struct btree_trans *, struct btree_iter *, |
5dd8c60e | 99 | enum btree_iter_update_trigger_flags, |
85beefef | 100 | struct bkey_s_c, struct bkey_s_c); |
1f2d9192 | 101 | |
51e84d3b KO |
102 | int bch2_bkey_get_empty_slot(struct btree_trans *, struct btree_iter *, |
103 | enum btree_id, struct bpos); | |
104 | ||
94a3e1a6 | 105 | int __must_check bch2_trans_update(struct btree_trans *, struct btree_iter *, |
5dd8c60e | 106 | struct bkey_i *, enum btree_iter_update_trigger_flags); |
1f2d9192 | 107 | |
24de63da KO |
108 | struct jset_entry *__bch2_trans_jset_entry_alloc(struct btree_trans *, unsigned); |
109 | ||
110 | static inline struct jset_entry *btree_trans_journal_entries_top(struct btree_trans *trans) | |
111 | { | |
112 | return (void *) ((u64 *) trans->journal_entries + trans->journal_entries_u64s); | |
113 | } | |
114 | ||
115 | static inline struct jset_entry * | |
116 | bch2_trans_jset_entry_alloc(struct btree_trans *trans, unsigned u64s) | |
117 | { | |
118 | if (!trans->journal_entries || | |
119 | trans->journal_entries_u64s + u64s > trans->journal_entries_size) | |
120 | return __bch2_trans_jset_entry_alloc(trans, u64s); | |
121 | ||
122 | struct jset_entry *e = btree_trans_journal_entries_top(trans); | |
123 | trans->journal_entries_u64s += u64s; | |
124 | return e; | |
125 | } | |
126 | ||
67997234 KO |
127 | int bch2_btree_insert_clone_trans(struct btree_trans *, enum btree_id, struct bkey_i *); |
128 | ||
129 | static inline int __must_check bch2_trans_update_buffered(struct btree_trans *trans, | |
130 | enum btree_id btree, | |
131 | struct bkey_i *k) | |
132 | { | |
133 | if (unlikely(trans->journal_replay_not_finished)) | |
134 | return bch2_btree_insert_clone_trans(trans, btree, k); | |
135 | ||
136 | struct jset_entry *e = bch2_trans_jset_entry_alloc(trans, jset_u64s(k->k.u64s)); | |
137 | int ret = PTR_ERR_OR_ZERO(e); | |
138 | if (ret) | |
139 | return ret; | |
140 | ||
141 | journal_entry_init(e, BCH_JSET_ENTRY_write_buffer_keys, btree, 0, k->k.u64s); | |
142 | bkey_copy(e->start, k); | |
143 | return 0; | |
144 | } | |
145 | ||
43d00243 KO |
146 | void bch2_trans_commit_hook(struct btree_trans *, |
147 | struct btree_trans_commit_hook *); | |
30ca6ece | 148 | int __bch2_trans_commit(struct btree_trans *, unsigned); |
2a9101a9 | 149 | |
96dea3d5 KO |
150 | __printf(2, 3) int bch2_fs_log_msg(struct bch_fs *, const char *, ...); |
151 | __printf(2, 3) int bch2_journal_log_msg(struct bch_fs *, const char *, ...); | |
5aabb324 | 152 | |
2a9101a9 KO |
153 | /** |
154 | * bch2_trans_commit - insert keys at given iterator positions | |
155 | * | |
156 | * This is main entry point for btree updates. | |
157 | * | |
158 | * Return values: | |
2a9101a9 KO |
159 | * -EROFS: filesystem read only |
160 | * -EIO: journal or btree node IO error | |
161 | */ | |
162 | static inline int bch2_trans_commit(struct btree_trans *trans, | |
163 | struct disk_reservation *disk_res, | |
164 | u64 *journal_seq, | |
165 | unsigned flags) | |
166 | { | |
167 | trans->disk_res = disk_res; | |
168 | trans->journal_seq = journal_seq; | |
2a9101a9 | 169 | |
30ca6ece | 170 | return __bch2_trans_commit(trans, flags); |
2a9101a9 | 171 | } |
1c6fdbd8 | 172 | |
e68914ca | 173 | #define commit_do(_trans, _disk_res, _journal_seq, _flags, _do) \ |
d3ff7fec KO |
174 | lockrestart_do(_trans, _do ?: bch2_trans_commit(_trans, (_disk_res),\ |
175 | (_journal_seq), (_flags))) | |
176 | ||
e941ae7d KO |
177 | #define nested_commit_do(_trans, _disk_res, _journal_seq, _flags, _do) \ |
178 | nested_lockrestart_do(_trans, _do ?: bch2_trans_commit(_trans, (_disk_res),\ | |
179 | (_journal_seq), (_flags))) | |
180 | ||
dadecd02 KO |
181 | #define bch2_trans_run(_c, _do) \ |
182 | ({ \ | |
6bd68ec2 KO |
183 | struct btree_trans *trans = bch2_trans_get(_c); \ |
184 | int _ret = (_do); \ | |
185 | bch2_trans_put(trans); \ | |
dadecd02 KO |
186 | _ret; \ |
187 | }) | |
188 | ||
6bd68ec2 KO |
189 | #define bch2_trans_do(_c, _disk_res, _journal_seq, _flags, _do) \ |
190 | bch2_trans_run(_c, commit_do(trans, _disk_res, _journal_seq, _flags, _do)) | |
191 | ||
a7199432 | 192 | #define trans_for_each_update(_trans, _i) \ |
559e6c23 | 193 | for (struct btree_insert_entry *_i = (_trans)->updates; \ |
a7199432 | 194 | (_i) < (_trans)->updates + (_trans)->nr_updates; \ |
9623ab27 KO |
195 | (_i)++) |
196 | ||
0fbf71f8 KO |
197 | static inline void bch2_trans_reset_updates(struct btree_trans *trans) |
198 | { | |
0fbf71f8 | 199 | trans_for_each_update(trans, i) |
7f9821a7 | 200 | bch2_path_put(trans, i->path, true); |
0fbf71f8 | 201 | |
0fbf71f8 | 202 | trans->nr_updates = 0; |
24de63da | 203 | trans->journal_entries_u64s = 0; |
0fbf71f8 | 204 | trans->hooks = NULL; |
6474b706 | 205 | trans->extra_disk_res = 0; |
464b4155 KO |
206 | |
207 | if (trans->fs_usage_deltas) { | |
208 | trans->fs_usage_deltas->used = 0; | |
209 | memset((void *) trans->fs_usage_deltas + | |
210 | offsetof(struct replicas_delta_list, memset_start), 0, | |
211 | (void *) &trans->fs_usage_deltas->memset_end - | |
212 | (void *) &trans->fs_usage_deltas->memset_start); | |
213 | } | |
0fbf71f8 KO |
214 | } |
215 | ||
dbda63bb | 216 | static inline struct bkey_i *__bch2_bkey_make_mut_noupdate(struct btree_trans *trans, struct bkey_s_c k, |
34dfa5db | 217 | unsigned type, unsigned min_bytes) |
d67a16df | 218 | { |
34dfa5db KO |
219 | unsigned bytes = max_t(unsigned, min_bytes, bkey_bytes(k.k)); |
220 | struct bkey_i *mut; | |
221 | ||
222 | if (type && k.k->type != type) | |
223 | return ERR_PTR(-ENOENT); | |
d67a16df | 224 | |
34dfa5db KO |
225 | mut = bch2_trans_kmalloc_nomemzero(trans, bytes); |
226 | if (!IS_ERR(mut)) { | |
d67a16df | 227 | bkey_reassemble(mut, k); |
34dfa5db KO |
228 | |
229 | if (unlikely(bytes > bkey_bytes(k.k))) { | |
230 | memset((void *) mut + bkey_bytes(k.k), 0, | |
231 | bytes - bkey_bytes(k.k)); | |
232 | mut->k.u64s = DIV_ROUND_UP(bytes, sizeof(u64)); | |
233 | } | |
234 | } | |
d67a16df KO |
235 | return mut; |
236 | } | |
237 | ||
dbda63bb | 238 | static inline struct bkey_i *bch2_bkey_make_mut_noupdate(struct btree_trans *trans, struct bkey_s_c k) |
d67a16df | 239 | { |
dbda63bb | 240 | return __bch2_bkey_make_mut_noupdate(trans, k, 0, 0); |
34dfa5db | 241 | } |
d67a16df | 242 | |
dbda63bb KO |
243 | #define bch2_bkey_make_mut_noupdate_typed(_trans, _k, _type) \ |
244 | bkey_i_to_##_type(__bch2_bkey_make_mut_noupdate(_trans, _k, \ | |
245 | KEY_TYPE_##_type, sizeof(struct bkey_i_##_type))) | |
246 | ||
247 | static inline struct bkey_i *__bch2_bkey_make_mut(struct btree_trans *trans, struct btree_iter *iter, | |
0fb3355d | 248 | struct bkey_s_c *k, unsigned flags, |
dbda63bb KO |
249 | unsigned type, unsigned min_bytes) |
250 | { | |
0fb3355d | 251 | struct bkey_i *mut = __bch2_bkey_make_mut_noupdate(trans, *k, type, min_bytes); |
dbda63bb KO |
252 | int ret; |
253 | ||
254 | if (IS_ERR(mut)) | |
255 | return mut; | |
256 | ||
257 | ret = bch2_trans_update(trans, iter, mut, flags); | |
258 | if (ret) | |
259 | return ERR_PTR(ret); | |
0fb3355d KO |
260 | |
261 | *k = bkey_i_to_s_c(mut); | |
dbda63bb KO |
262 | return mut; |
263 | } | |
264 | ||
265 | static inline struct bkey_i *bch2_bkey_make_mut(struct btree_trans *trans, struct btree_iter *iter, | |
0fb3355d | 266 | struct bkey_s_c *k, unsigned flags) |
dbda63bb KO |
267 | { |
268 | return __bch2_bkey_make_mut(trans, iter, k, flags, 0, 0); | |
269 | } | |
270 | ||
271 | #define bch2_bkey_make_mut_typed(_trans, _iter, _k, _flags, _type) \ | |
272 | bkey_i_to_##_type(__bch2_bkey_make_mut(_trans, _iter, _k, _flags,\ | |
34dfa5db KO |
273 | KEY_TYPE_##_type, sizeof(struct bkey_i_##_type))) |
274 | ||
f12a798a | 275 | static inline struct bkey_i *__bch2_bkey_get_mut_noupdate(struct btree_trans *trans, |
34dfa5db KO |
276 | struct btree_iter *iter, |
277 | unsigned btree_id, struct bpos pos, | |
278 | unsigned flags, unsigned type, unsigned min_bytes) | |
279 | { | |
280 | struct bkey_s_c k = __bch2_bkey_get_iter(trans, iter, | |
5dd8c60e | 281 | btree_id, pos, flags|BTREE_ITER_intent, type); |
1e81f89b | 282 | struct bkey_i *ret = IS_ERR(k.k) |
d67a16df | 283 | ? ERR_CAST(k.k) |
dbda63bb | 284 | : __bch2_bkey_make_mut_noupdate(trans, k, 0, min_bytes); |
1e81f89b | 285 | if (IS_ERR(ret)) |
34dfa5db KO |
286 | bch2_trans_iter_exit(trans, iter); |
287 | return ret; | |
d67a16df KO |
288 | } |
289 | ||
f12a798a KO |
290 | static inline struct bkey_i *bch2_bkey_get_mut_noupdate(struct btree_trans *trans, |
291 | struct btree_iter *iter, | |
292 | unsigned btree_id, struct bpos pos, | |
293 | unsigned flags) | |
294 | { | |
295 | return __bch2_bkey_get_mut_noupdate(trans, iter, btree_id, pos, flags, 0, 0); | |
296 | } | |
297 | ||
298 | static inline struct bkey_i *__bch2_bkey_get_mut(struct btree_trans *trans, | |
299 | struct btree_iter *iter, | |
300 | unsigned btree_id, struct bpos pos, | |
301 | unsigned flags, unsigned type, unsigned min_bytes) | |
302 | { | |
303 | struct bkey_i *mut = __bch2_bkey_get_mut_noupdate(trans, iter, | |
5dd8c60e | 304 | btree_id, pos, flags|BTREE_ITER_intent, type, min_bytes); |
f12a798a KO |
305 | int ret; |
306 | ||
307 | if (IS_ERR(mut)) | |
308 | return mut; | |
309 | ||
310 | ret = bch2_trans_update(trans, iter, mut, flags); | |
311 | if (ret) { | |
312 | bch2_trans_iter_exit(trans, iter); | |
313 | return ERR_PTR(ret); | |
314 | } | |
315 | ||
316 | return mut; | |
317 | } | |
318 | ||
34dfa5db KO |
319 | static inline struct bkey_i *bch2_bkey_get_mut_minsize(struct btree_trans *trans, |
320 | struct btree_iter *iter, | |
321 | unsigned btree_id, struct bpos pos, | |
322 | unsigned flags, unsigned min_bytes) | |
323 | { | |
324 | return __bch2_bkey_get_mut(trans, iter, btree_id, pos, flags, 0, min_bytes); | |
325 | } | |
326 | ||
327 | static inline struct bkey_i *bch2_bkey_get_mut(struct btree_trans *trans, | |
328 | struct btree_iter *iter, | |
329 | unsigned btree_id, struct bpos pos, | |
330 | unsigned flags) | |
331 | { | |
f12a798a | 332 | return __bch2_bkey_get_mut(trans, iter, btree_id, pos, flags, 0, 0); |
34dfa5db KO |
333 | } |
334 | ||
335 | #define bch2_bkey_get_mut_typed(_trans, _iter, _btree_id, _pos, _flags, _type)\ | |
336 | bkey_i_to_##_type(__bch2_bkey_get_mut(_trans, _iter, \ | |
337 | _btree_id, _pos, _flags, \ | |
338 | KEY_TYPE_##_type, sizeof(struct bkey_i_##_type))) | |
339 | ||
340 | static inline struct bkey_i *__bch2_bkey_alloc(struct btree_trans *trans, struct btree_iter *iter, | |
f8cb35fd | 341 | unsigned flags, unsigned type, unsigned val_size) |
34dfa5db KO |
342 | { |
343 | struct bkey_i *k = bch2_trans_kmalloc(trans, sizeof(*k) + val_size); | |
f8cb35fd | 344 | int ret; |
34dfa5db | 345 | |
f8cb35fd KO |
346 | if (IS_ERR(k)) |
347 | return k; | |
348 | ||
349 | bkey_init(&k->k); | |
350 | k->k.p = iter->pos; | |
351 | k->k.type = type; | |
352 | set_bkey_val_bytes(&k->k, val_size); | |
34dfa5db | 353 | |
f8cb35fd KO |
354 | ret = bch2_trans_update(trans, iter, k, flags); |
355 | if (unlikely(ret)) | |
356 | return ERR_PTR(ret); | |
34dfa5db KO |
357 | return k; |
358 | } | |
d67a16df | 359 | |
f8cb35fd KO |
360 | #define bch2_bkey_alloc(_trans, _iter, _flags, _type) \ |
361 | bkey_i_to_##_type(__bch2_bkey_alloc(_trans, _iter, _flags, \ | |
34dfa5db | 362 | KEY_TYPE_##_type, sizeof(struct bch_##_type))) |
d67a16df | 363 | |
1c6fdbd8 | 364 | #endif /* _BCACHEFS_BTREE_UPDATE_H */ |