diff options
Diffstat (limited to 'fs/bcachefs/btree_update.h')
-rw-r--r-- | fs/bcachefs/btree_update.h | 215 |
1 files changed, 133 insertions, 82 deletions
diff --git a/fs/bcachefs/btree_update.h b/fs/bcachefs/btree_update.h index fd3e0affb636..616c103c05ec 100644 --- a/fs/bcachefs/btree_update.h +++ b/fs/bcachefs/btree_update.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _BCACHEFS_BTREE_UPDATE_H #define _BCACHEFS_BTREE_UPDATE_H @@ -6,126 +7,176 @@ struct bch_fs; struct btree; -struct btree_insert; void bch2_btree_node_lock_for_insert(struct bch_fs *, struct btree *, struct btree_iter *); bool bch2_btree_bset_insert_key(struct btree_iter *, struct btree *, struct btree_node_iter *, struct bkey_i *); -void bch2_btree_journal_key(struct btree_insert *trans, struct btree_iter *, +void bch2_btree_journal_key(struct btree_trans *, struct btree_iter *, struct bkey_i *); -/* Normal update interface: */ - -struct btree_insert { - struct bch_fs *c; - struct disk_reservation *disk_res; - struct journal_res journal_res; - u64 *journal_seq; - struct extent_insert_hook *hook; - unsigned flags; - bool did_work; - - unsigned short nr; - struct btree_insert_entry { - struct btree_iter *iter; - struct bkey_i *k; - unsigned extra_res; - /* - * true if entire key was inserted - can only be false for - * extents - */ - bool done; - } *entries; -}; - -int __bch2_btree_insert_at(struct btree_insert *); +void bch2_deferred_update_free(struct bch_fs *, + struct deferred_update *); +struct deferred_update * +bch2_deferred_update_alloc(struct bch_fs *, enum btree_id, unsigned); #define BTREE_INSERT_ENTRY(_iter, _k) \ ((struct btree_insert_entry) { \ .iter = (_iter), \ .k = (_k), \ - .done = false, \ }) -#define BTREE_INSERT_ENTRY_EXTRA_RES(_iter, _k, _extra) \ +#define BTREE_INSERT_DEFERRED(_d, _k) \ ((struct btree_insert_entry) { \ - .iter = (_iter), \ .k = (_k), \ - .extra_res = (_extra), \ - .done = false, \ + .d = (_d), \ + .deferred = true, \ }) -/** - * bch_btree_insert_at - insert one or more keys at iterator positions - * @iter: btree iterator - * @insert_key: key to insert - * @disk_res: disk reservation - * @hook: extent insert callback - * - * Return values: - * -EINTR: locking changed, this function should be called again. Only returned - * if passed BTREE_INSERT_ATOMIC. - * -EROFS: filesystem read only - * -EIO: journal or btree node IO error +enum { + __BTREE_INSERT_ATOMIC, + __BTREE_INSERT_NOUNLOCK, + __BTREE_INSERT_NOFAIL, + __BTREE_INSERT_NOCHECK_RW, + __BTREE_INSERT_LAZY_RW, + __BTREE_INSERT_USE_RESERVE, + __BTREE_INSERT_USE_ALLOC_RESERVE, + __BTREE_INSERT_JOURNAL_REPLAY, + __BTREE_INSERT_JOURNAL_RESERVED, + __BTREE_INSERT_NOMARK_INSERT, + __BTREE_INSERT_NOMARK_OVERWRITES, + __BTREE_INSERT_NOMARK, + __BTREE_INSERT_MARK_INMEM, + __BTREE_INSERT_NO_CLEAR_REPLICAS, + __BTREE_INSERT_BUCKET_INVALIDATE, + __BTREE_INSERT_NOWAIT, + __BTREE_INSERT_GC_LOCK_HELD, + __BCH_HASH_SET_MUST_CREATE, + __BCH_HASH_SET_MUST_REPLACE, +}; + +/* + * Don't drop/retake locks before doing btree update, instead return -EINTR if + * we had to drop locks for any reason */ -#define bch2_btree_insert_at(_c, _disk_res, _hook, \ - _journal_seq, _flags, ...) \ - __bch2_btree_insert_at(&(struct btree_insert) { \ - .c = (_c), \ - .disk_res = (_disk_res), \ - .journal_seq = (_journal_seq), \ - .hook = (_hook), \ - .flags = (_flags), \ - .nr = COUNT_ARGS(__VA_ARGS__), \ - .entries = (struct btree_insert_entry[]) { \ - __VA_ARGS__ \ - }}) +#define BTREE_INSERT_ATOMIC (1 << __BTREE_INSERT_ATOMIC) /* - * Don't drop/retake locks: instead return -EINTR if need to upgrade to intent - * locks, -EAGAIN if need to wait on btree reserve + * Don't drop locks _after_ successfully updating btree: */ -#define BTREE_INSERT_ATOMIC (1 << 0) +#define BTREE_INSERT_NOUNLOCK (1 << __BTREE_INSERT_NOUNLOCK) /* Don't check for -ENOSPC: */ -#define BTREE_INSERT_NOFAIL (1 << 1) +#define BTREE_INSERT_NOFAIL (1 << __BTREE_INSERT_NOFAIL) + +#define BTREE_INSERT_NOCHECK_RW (1 << __BTREE_INSERT_NOCHECK_RW) +#define BTREE_INSERT_LAZY_RW (1 << __BTREE_INSERT_LAZY_RW) /* for copygc, or when merging btree nodes */ -#define BTREE_INSERT_USE_RESERVE (1 << 2) -#define BTREE_INSERT_USE_ALLOC_RESERVE (1 << 3) +#define BTREE_INSERT_USE_RESERVE (1 << __BTREE_INSERT_USE_RESERVE) +#define BTREE_INSERT_USE_ALLOC_RESERVE (1 << __BTREE_INSERT_USE_ALLOC_RESERVE) -/* - * Insert is for journal replay: don't get journal reservations, or mark extents - * (bch_mark_key) - */ -#define BTREE_INSERT_JOURNAL_REPLAY (1 << 4) +/* Insert is for journal replay - don't get journal reservations: */ +#define BTREE_INSERT_JOURNAL_REPLAY (1 << __BTREE_INSERT_JOURNAL_REPLAY) -/* Don't block on allocation failure (for new btree nodes: */ -#define BTREE_INSERT_NOWAIT (1 << 5) -#define BTREE_INSERT_GC_LOCK_HELD (1 << 6) +#define BTREE_INSERT_JOURNAL_RESERVED (1 << __BTREE_INSERT_JOURNAL_RESERVED) -#define BCH_HASH_SET_MUST_CREATE (1 << 7) -#define BCH_HASH_SET_MUST_REPLACE (1 << 8) +/* Don't mark new key, just overwrites: */ +#define BTREE_INSERT_NOMARK_INSERT (1 << __BTREE_INSERT_NOMARK_INSERT) -int bch2_btree_delete_at(struct btree_iter *, unsigned); +/* Don't mark overwrites, just new key: */ +#define BTREE_INSERT_NOMARK_OVERWRITES (1 << __BTREE_INSERT_NOMARK_OVERWRITES) -int bch2_btree_insert_list_at(struct btree_iter *, struct keylist *, - struct disk_reservation *, - struct extent_insert_hook *, u64 *, unsigned); +/* Don't call mark new key at all: */ +#define BTREE_INSERT_NOMARK (1 << __BTREE_INSERT_NOMARK) + +/* Don't mark transactionally: */ +#define BTREE_INSERT_MARK_INMEM (1 << __BTREE_INSERT_MARK_INMEM) + +#define BTREE_INSERT_NO_CLEAR_REPLICAS (1 << __BTREE_INSERT_NO_CLEAR_REPLICAS) + +#define BTREE_INSERT_BUCKET_INVALIDATE (1 << __BTREE_INSERT_BUCKET_INVALIDATE) + +/* Don't block on allocation failure (for new btree nodes: */ +#define BTREE_INSERT_NOWAIT (1 << __BTREE_INSERT_NOWAIT) +#define BTREE_INSERT_GC_LOCK_HELD (1 << __BTREE_INSERT_GC_LOCK_HELD) + +#define BCH_HASH_SET_MUST_CREATE (1 << __BCH_HASH_SET_MUST_CREATE) +#define BCH_HASH_SET_MUST_REPLACE (1 << __BCH_HASH_SET_MUST_REPLACE) + +int bch2_btree_delete_at(struct btree_trans *, struct btree_iter *, unsigned); int bch2_btree_insert(struct bch_fs *, enum btree_id, struct bkey_i *, - struct disk_reservation *, - struct extent_insert_hook *, u64 *, int flags); + struct disk_reservation *, u64 *, int flags); +int bch2_btree_delete_at_range(struct btree_trans *, struct btree_iter *, + struct bpos, u64 *); int bch2_btree_delete_range(struct bch_fs *, enum btree_id, - struct bpos, struct bpos, struct bversion, - struct disk_reservation *, - struct extent_insert_hook *, u64 *); + struct bpos, struct bpos, u64 *); int bch2_btree_node_rewrite(struct bch_fs *c, struct btree_iter *, __le64, unsigned); int bch2_btree_node_update_key(struct bch_fs *, struct btree_iter *, - struct btree *, struct bkey_i_extent *); + struct btree *, struct bkey_i_btree_ptr *); + +int bch2_trans_commit(struct btree_trans *, + struct disk_reservation *, + u64 *, unsigned); + +struct btree_insert_entry *bch2_trans_update(struct btree_trans *, + struct btree_insert_entry); + +#define bch2_trans_do(_c, _journal_seq, _flags, _do) \ +({ \ + struct btree_trans trans; \ + int _ret; \ + \ + bch2_trans_init(&trans, (_c), 0, 0); \ + \ + do { \ + bch2_trans_begin(&trans); \ + \ + _ret = (_do) ?: bch2_trans_commit(&trans, NULL, \ + (_journal_seq), (_flags)); \ + } while (_ret == -EINTR); \ + \ + bch2_trans_exit(&trans); \ + _ret; \ +}) + +/* + * We sort transaction entries so that if multiple iterators point to the same + * leaf node they'll be adjacent: + */ +static inline bool same_leaf_as_prev(struct btree_trans *trans, + struct btree_insert_entry *i) +{ + return i != trans->updates && + !i->deferred && + i[0].iter->l[0].b == i[-1].iter->l[0].b; +} + +#define __trans_next_update(_trans, _i, _filter) \ +({ \ + while ((_i) < (_trans)->updates + (_trans->nr_updates) && !(_filter))\ + (_i)++; \ + \ + (_i) < (_trans)->updates + (_trans->nr_updates); \ +}) + +#define __trans_for_each_update(_trans, _i, _filter) \ + for ((_i) = (_trans)->updates; \ + __trans_next_update(_trans, _i, _filter); \ + (_i)++) + +#define trans_for_each_update(trans, i) \ + __trans_for_each_update(trans, i, true) + +#define trans_for_each_update_iter(trans, i) \ + __trans_for_each_update(trans, i, !(i)->deferred) + +#define trans_for_each_update_leaf(trans, i) \ + __trans_for_each_update(trans, i, !(i)->deferred && \ + !same_leaf_as_prev(trans, i)) #endif /* _BCACHEFS_BTREE_UPDATE_H */ |