// SPDX-License-Identifier: GPL-2.0 #include "bcachefs.h"#include "alloc_foreground.h"#include "btree_gc.h"#include "btree_io.h"#include "btree_iter.h"#include "btree_journal_iter.h"#include "btree_key_cache.h"#include "btree_update_interior.h"#include "btree_write_buffer.h"#include "buckets.h"#include "disk_accounting.h"#include "errcode.h"#include "error.h"#include "journal.h"#include "journal_io.h"#include "journal_reclaim.h"#include "replicas.h"#include "snapshot.h" #include <linux/prefetch.h> static const char * const trans_commit_flags_strs[] = {#define x(n, ...) #n, BCH_TRANS_COMMIT_FLAGS()#undef x NULL}; void bch2_trans_commit_flags_to_text(struct printbuf *out, enum bch_trans_commit_flags flags){ enum bch_watermark watermark = flags & BCH_WATERMARK_MASK; prt_printf(out, "watermark=%s", bch2_watermarks[watermark]); flags >>= BCH_WATERMARK_BITS; if (flags) { prt_char(out, ' '); bch2_prt_bitflags(out, trans_commit_flags_strs, flags); }} static void verify_update_old_key(struct btree_trans *trans, struct btree_insert_entry *i){#ifdef CONFIG_BCACHEFS_DEBUG struct bch_fs *c = trans->c; struct bkey u; struct bkey_s_c k = bch2_btree_path_peek_slot_exact(trans->paths + i->path, &u); if (unlikely(trans->journal_replay_not_finished)) { struct bkey_i *j_k = bch2_journal_keys_peek_slot(c, i->btree_id, i->level, i->k->k.p); if (j_k) k = bkey_i_to_s_c(j_k); } u = *k.k; u.needs_whiteout = i->old_k.needs_whiteout; BUG_ON(memcmp(&i->old_k, &u, sizeof(struct bkey))); BUG_ON(i->old_v != k.v);#endif} static inline struct btree_path_level *insert_l(struct btree_trans *trans, struct btree_insert_entry *i){ return (trans->paths + i->path)->l + i->level;} static inline bool same_leaf_as_prev(struct btree_trans *trans, struct btree_insert_entry *i){ return i != trans->updates && insert_l(trans, &i[0])->b == insert_l(trans, &i[-1])->b;} static inline bool same_leaf_as_next(struct btree_trans *trans, struct btree_insert_entry *i){ return i + 1 < trans->updates + trans->nr_updates && insert_l(trans, &i[0])->b == insert_l(trans, &i[1])->b;} inline void bch2_btree_node_prep_for_write(struct btree_trans *trans, struct btree_path *path, struct btree *b){ struct bch_fs *c = trans->c; if (unlikely(btree_node_just_written(b)) && bch2_btree_post_write_cleanup(c, b)) bch2_trans_node_reinit_iter(trans, b); /* * If the last bset has been written, or if it's gotten too big - start * a new bset to insert into: */ if (want_new_bset(c, b)) bch2_btree_init_next(trans, b);} static noinline int trans_lock_write_fail(struct btree_trans *trans, struct btree_insert_entry *i){ while (--i >= trans->updates) { if (same_leaf_as_prev(trans, i)) continue; bch2_btree_node_unlock_write(trans, trans->paths + i->path, insert_l(trans, i)->b); } trace_and_count(trans->c, trans_restart_would_deadlock_write, trans); return btree_trans_restart(trans, BCH_ERR_transaction_restart_would_deadlock_write);} static inline int bch2_trans_lock_write(struct btree_trans *trans){ EBUG_ON(trans->write_locked); trans_for_each_update(trans, i) { if (same_leaf_as_prev(trans, i)) continue; if (bch2_btree_node_lock_write(trans, trans->paths + i->path, &insert_l(trans, i)->b->c)) return trans_lock_write_fail(trans, i); if (!i->cached) bch2_btree_node_prep_for_write(trans, trans->paths + i->path, insert_l(trans, i)->b); } trans->write_locked = true; return 0;} static inline void bch2_trans_unlock_write(struct btree_trans *trans){ if (likely(trans->write_locked)) { trans_for_each_update(trans, i) if (btree_node_locked_type(trans->paths + i->path, i->level) == BTREE_NODE_WRITE_LOCKED) bch2_btree_node_unlock_write_inlined(trans, trans->paths + i->path, insert_l(trans, i)->b); trans->write_locked = false; }} /* Inserting into a given leaf node (last stage of insert): */ /* Handle overwrites and do insert, for non extents: */bool bch2_btree_bset_insert_key(struct btree_trans *trans, struct btree_path *path, struct btree *b, struct btree_node_iter *node_iter, struct bkey_i *insert){ struct bkey_packed *k; unsigned clobber_u64s = 0, new_u64s = 0; EBUG_ON(btree_node_just_written(b)); EBUG_ON(bset_written(b, btree_bset_last(b))); EBUG_ON(bkey_deleted(&insert->k) && bkey_val_u64s(&insert->k)); EBUG_ON(bpos_lt(insert->k.p, b->data->min_key)); EBUG_ON(bpos_gt(insert->k.p, b->data->max_key)); EBUG_ON(insert->k.u64s > bch2_btree_keys_u64s_remaining(b)); EBUG_ON(!b->c.level && !bpos_eq(insert->k.p, path->pos)); k = bch2_btree_node_iter_peek_all(node_iter, b); if (k && bkey_cmp_left_packed(b, k, &insert->k.p)) k = NULL; /* @k is the key being overwritten/deleted, if any: */ EBUG_ON(k && bkey_deleted(k)); /* Deleting, but not found? nothing to do: */ if (bkey_deleted(&insert->k) && !k) return false; if (bkey_deleted(&insert->k)) { /* Deleting: */ btree_account_key_drop(b, k); k->type = KEY_TYPE_deleted; if (k->needs_whiteout) push_whiteout(b, insert->k.p); k->needs_whiteout = false; if (k >= btree_bset_last(b)->start) { clobber_u64s = k->u64s; bch2_bset_delete(b, k, clobber_u64s); goto fix_iter; } else { bch2_btree_path_fix_key_modified(trans, b, k); } return true; } if (k) { /* Overwriting: */ btree_account_key_drop(b, k); k->type = KEY_TYPE_deleted; insert->k.needs_whiteout = k->needs_whiteout; k->needs_whiteout = false; if (k >= btree_bset_last(b)->start) { clobber_u64s = k->u64s; goto overwrite; } else { bch2_btree_path_fix_key_modified(trans, b, k); } } k = bch2_btree_node_iter_bset_pos(node_iter, b, bset_tree_last(b));overwrite: bch2_bset_insert(b, k, insert, clobber_u64s); new_u64s = k->u64s;fix_iter: if (clobber_u64s != new_u64s) bch2_btree_node_iter_fix(trans, path, b, node_iter, k, clobber_u64s, new_u64s); return true;} static int __btree_node_flush(struct journal *j, struct journal_entry_pin *pin, unsigned i, u64 seq){ struct bch_fs *c = container_of(j, struct bch_fs, journal); struct btree_write *w = container_of(pin, struct btree_write, journal); struct btree *b = container_of(w, struct btree, writes[i]); struct btree_trans *trans = bch2_trans_get(c); unsigned long old, new; unsigned idx = w - b->writes; btree_node_lock_nopath_nofail(trans, &b->c, SIX_LOCK_read); old = READ_ONCE(b->flags); do { new = old; if (!(old & (1 << BTREE_NODE_dirty)) || !!(old & (1 << BTREE_NODE_write_idx)) != idx || w->journal.seq != seq) break; new &= ~BTREE_WRITE_TYPE_MASK; new |= BTREE_WRITE_journal_reclaim; new |= 1 << BTREE_NODE_need_write; } while (!try_cmpxchg(&b->flags, &old, new)); btree_node_write_if_need(c, b, SIX_LOCK_read); six_unlock_read(&b->c.lock); bch2_trans_put(trans); return 0;} int bch2_btree_node_flush0(struct journal *j, struct journal_entry_pin *pin, u64 seq){ return __btree_node_flush(j, pin, 0, seq);} int bch2_btree_node_flush1(struct journal *j, struct journal_entry_pin *pin, u64 seq){ return __btree_node_flush(j, pin, 1, seq);} inline void bch2_btree_add_journal_pin(struct bch_fs *c, struct btree *b, u64 seq){ struct btree_write *w = btree_current_write(b); bch2_journal_pin_add(&c->journal, seq, &w->journal, btree_node_write_idx(b) == 0 ? bch2_btree_node_flush0 : bch2_btree_node_flush1);} /** * bch2_btree_insert_key_leaf() - insert a key one key into a leaf node * @trans: btree transaction object * @path: path pointing to @insert's pos * @insert: key to insert * @journal_seq: sequence number of journal reservation */inline void bch2_btree_insert_key_leaf(struct btree_trans *trans, struct btree_path *path, struct bkey_i *insert, u64 journal_seq){ struct bch_fs *c = trans->c; struct btree *b = path_l(path)->b; struct bset_tree *t = bset_tree_last(b); struct bset *i = bset(b, t); int old_u64s = bset_u64s(t); int old_live_u64s = b->nr.live_u64s; int live_u64s_added, u64s_added; if (unlikely(!bch2_btree_bset_insert_key(trans, path, b, &path_l(path)->iter, insert))) return; i->journal_seq = cpu_to_le64(max(journal_seq, le64_to_cpu(i->journal_seq))); bch2_btree_add_journal_pin(c, b, journal_seq); if (unlikely(!btree_node_dirty(b))) { EBUG_ON(test_bit(BCH_FS_clean_shutdown, &c->flags)); set_btree_node_dirty_acct(c, b); } live_u64s_added = (int) b->nr.live_u64s - old_live_u64s; u64s_added = (int) bset_u64s(t) - old_u64s; if (b->sib_u64s[0] != U16_MAX && live_u64s_added < 0) b->sib_u64s[0] = max(0, (int) b->sib_u64s[0] + live_u64s_added); if (b->sib_u64s[1] != U16_MAX && live_u64s_added < 0) b->sib_u64s[1] = max(0, (int) b->sib_u64s[1] + live_u64s_added); if (u64s_added > live_u64s_added && bch2_maybe_compact_whiteouts(c, b)) bch2_trans_node_reinit_iter(trans, b);} /* Cached btree updates: */ /* Normal update interface: */ static inline void btree_insert_entry_checks(struct btree_trans *trans, struct btree_insert_entry *i){ struct btree_path *path = trans->paths + i->path; BUG_ON(!bpos_eq(i->k->k.p, path->pos)); BUG_ON(i->cached != path->cached); BUG_ON(i->level != path->level); BUG_ON(i->btree_id != path->btree_id); EBUG_ON(!i->level && btree_type_has_snapshots(i->btree_id) && !(i->flags & BTREE_UPDATE_internal_snapshot_node) && test_bit(JOURNAL_replay_done, &trans->c->journal.flags) && i->k->k.p.snapshot && bch2_snapshot_is_internal_node(trans->c, i->k->k.p.snapshot) > 0);} static __always_inline int bch2_trans_journal_res_get(struct btree_trans *trans, unsigned flags){ return bch2_journal_res_get(&trans->c->journal, &trans->journal_res, trans->journal_u64s, flags);} #define JSET_ENTRY_LOG_U64s 4 static noinline void journal_transaction_name(struct btree_trans *trans){ struct bch_fs *c = trans->c; struct journal *j = &c->journal; struct jset_entry *entry = bch2_journal_add_entry(j, &trans->journal_res, BCH_JSET_ENTRY_log, 0, 0, JSET_ENTRY_LOG_U64s); struct jset_entry_log *l = container_of(entry, struct jset_entry_log, entry); strncpy(l->d, trans->fn, JSET_ENTRY_LOG_U64s * sizeof(u64));} static inline int btree_key_can_insert(struct btree_trans *trans, struct btree *b, unsigned u64s){ if (!bch2_btree_node_insert_fits(b, u64s)) return -BCH_ERR_btree_insert_btree_node_full; return 0;} noinline static intbtree_key_can_insert_cached_slowpath(struct btree_trans *trans, unsigned flags, struct btree_path *path, unsigned new_u64s){ struct bkey_cached *ck = (void *) path->l[0].b; struct bkey_i *new_k; int ret; bch2_trans_unlock_write(trans); bch2_trans_unlock(trans); new_k = kmalloc(new_u64s * sizeof(u64), GFP_KERNEL); if (!new_k) { bch_err(trans->c, "error allocating memory for key cache key, btree %s u64s %u", bch2_btree_id_str(path->btree_id), new_u64s); return -BCH_ERR_ENOMEM_btree_key_cache_insert; } ret = bch2_trans_relock(trans) ?: bch2_trans_lock_write(trans); if (unlikely(ret)) { kfree(new_k); return ret; } memcpy(new_k, ck->k, ck->u64s * sizeof(u64)); trans_for_each_update(trans, i) if (i->old_v == &ck->k->v) i->old_v = &new_k->v; kfree(ck->k); ck->u64s = new_u64s; ck->k = new_k; return 0;} static int btree_key_can_insert_cached(struct btree_trans *trans, unsigned flags, struct btree_path *path, unsigned u64s){ struct bch_fs *c = trans->c; struct bkey_cached *ck = (void *) path->l[0].b; unsigned new_u64s; struct bkey_i *new_k; unsigned watermark = flags & BCH_WATERMARK_MASK; EBUG_ON(path->level); if (watermark < BCH_WATERMARK_reclaim && !test_bit(BKEY_CACHED_DIRTY, &ck->flags) && bch2_btree_key_cache_must_wait(c)) return -BCH_ERR_btree_insert_need_journal_reclaim; /* * bch2_varint_decode can read past the end of the buffer by at most 7 * bytes (it won't be used): */ u64s += 1; if (u64s <= ck->u64s) return 0; new_u64s = roundup_pow_of_two(u64s); new_k = krealloc(ck->k, new_u64s * sizeof(u64), GFP_NOWAIT|__GFP_NOWARN); if (unlikely(!new_k)) return btree_key_can_insert_cached_slowpath(trans, flags, path, new_u64s); trans_for_each_update(trans, i) if (i->old_v == &ck->k->v) i->old_v = &new_k->v; ck->u64s = new_u64s; ck->k = new_k; return 0;} /* Triggers: */ static int run_one_mem_trigger(struct btree_trans *trans, struct btree_insert_entry *i, unsigned flags){ verify_update_old_key(trans, i); if (unlikely(flags & BTREE_TRIGGER_norun)) return 0; 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); if (old_ops->trigger == new_ops->trigger) return bch2_key_trigger(trans, i->btree_id, i->level, old, bkey_i_to_s(new), BTREE_TRIGGER_insert|BTREE_TRIGGER_overwrite|flags); else return bch2_key_trigger_new(trans, i->btree_id, i->level, bkey_i_to_s(new), flags) ?: bch2_key_trigger_old(trans, i->btree_id, i->level, old, flags);} static int run_one_trans_trigger(struct btree_trans *trans, struct btree_insert_entry *i, bool overwrite){ verify_update_old_key(trans, i); if ((i->flags & BTREE_TRIGGER_norun) || !btree_node_type_has_trans_triggers(i->bkey_type)) return 0; /* * Transactional triggers create new btree_insert_entries, so we can't * pass them a pointer to a btree_insert_entry, that memory is going to * move: */ 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); unsigned flags = i->flags|BTREE_TRIGGER_transactional;Lines 1–500 of 1157. Load more
// SPDX-License-Identifier: GPL-2.0 #include "bcachefs.h" #include "alloc_foreground.h" #include "btree_gc.h" #include "btree_io.h" #include "btree_iter.h" #include "btree_journal_iter.h" #include "btree_key_cache.h" #include "btree_update_interior.h" #include "btree_write_buffer.h" #include "buckets.h" #include "disk_accounting.h" #include "errcode.h" #include "error.h" #include "journal.h" #include "journal_io.h" #include "journal_reclaim.h" #include "replicas.h" #include "snapshot.h" #include <linux/prefetch.h> static const char * const trans_commit_flags_strs[] = { #define x(n, ...) #n, BCH_TRANS_COMMIT_FLAGS() #undef x NULL }; void bch2_trans_commit_flags_to_text(struct printbuf *out, enum bch_trans_commit_flags flags) { enum bch_watermark watermark = flags & BCH_WATERMARK_MASK; prt_printf(out, "watermark=%s", bch2_watermarks[watermark]); flags >>= BCH_WATERMARK_BITS; if (flags) { prt_char(out, ' '); bch2_prt_bitflags(out, trans_commit_flags_strs, flags); } } static void verify_update_old_key(struct btree_trans *trans, struct btree_insert_entry *i) { #ifdef CONFIG_BCACHEFS_DEBUG struct bch_fs *c = trans->c; struct bkey u; struct bkey_s_c k = bch2_btree_path_peek_slot_exact(trans->paths + i->path, &u); if (unlikely(trans->journal_replay_not_finished)) { struct bkey_i *j_k = bch2_journal_keys_peek_slot(c, i->btree_id, i->level, i->k->k.p); if (j_k) k = bkey_i_to_s_c(j_k); } u = *k.k; u.needs_whiteout = i->old_k.needs_whiteout; BUG_ON(memcmp(&i->old_k, &u, sizeof(struct bkey))); BUG_ON(i->old_v != k.v); #endif } static inline struct btree_path_level *insert_l(struct btree_trans *trans, struct btree_insert_entry *i) { return (trans->paths + i->path)->l + i->level; } static inline bool same_leaf_as_prev(struct btree_trans *trans, struct btree_insert_entry *i) { return i != trans->updates && insert_l(trans, &i[0])->b == insert_l(trans, &i[-1])->b; } static inline bool same_leaf_as_next(struct btree_trans *trans, struct btree_insert_entry *i) { return i + 1 < trans->updates + trans->nr_updates && insert_l(trans, &i[0])->b == insert_l(trans, &i[1])->b; } inline void bch2_btree_node_prep_for_write(struct btree_trans *trans, struct btree_path *path, struct btree *b) { struct bch_fs *c = trans->c; if (unlikely(btree_node_just_written(b)) && bch2_btree_post_write_cleanup(c, b)) bch2_trans_node_reinit_iter(trans, b); /* * If the last bset has been written, or if it's gotten too big - start * a new bset to insert into: */ if (want_new_bset(c, b)) bch2_btree_init_next(trans, b); } static noinline int trans_lock_write_fail(struct btree_trans *trans, struct btree_insert_entry *i) { while (--i >= trans->updates) { if (same_leaf_as_prev(trans, i)) continue; bch2_btree_node_unlock_write(trans, trans->paths + i->path, insert_l(trans, i)->b); } trace_and_count(trans->c, trans_restart_would_deadlock_write, trans); return btree_trans_restart(trans, BCH_ERR_transaction_restart_would_deadlock_write); } static inline int bch2_trans_lock_write(struct btree_trans *trans) { EBUG_ON(trans->write_locked); trans_for_each_update(trans, i) { if (same_leaf_as_prev(trans, i)) continue; if (bch2_btree_node_lock_write(trans, trans->paths + i->path, &insert_l(trans, i)->b->c)) return trans_lock_write_fail(trans, i); if (!i->cached) bch2_btree_node_prep_for_write(trans, trans->paths + i->path, insert_l(trans, i)->b); } trans->write_locked = true; return 0; } static inline void bch2_trans_unlock_write(struct btree_trans *trans) { if (likely(trans->write_locked)) { trans_for_each_update(trans, i) if (btree_node_locked_type(trans->paths + i->path, i->level) == BTREE_NODE_WRITE_LOCKED) bch2_btree_node_unlock_write_inlined(trans, trans->paths + i->path, insert_l(trans, i)->b); trans->write_locked = false; } } /* Inserting into a given leaf node (last stage of insert): */ /* Handle overwrites and do insert, for non extents: */ bool bch2_btree_bset_insert_key(struct btree_trans *trans, struct btree_path *path, struct btree *b, struct btree_node_iter *node_iter, struct bkey_i *insert) { struct bkey_packed *k; unsigned clobber_u64s = 0, new_u64s = 0; EBUG_ON(btree_node_just_written(b)); EBUG_ON(bset_written(b, btree_bset_last(b))); EBUG_ON(bkey_deleted(&insert->k) && bkey_val_u64s(&insert->k)); EBUG_ON(bpos_lt(insert->k.p, b->data->min_key)); EBUG_ON(bpos_gt(insert->k.p, b->data->max_key)); EBUG_ON(insert->k.u64s > bch2_btree_keys_u64s_remaining(b)); EBUG_ON(!b->c.level && !bpos_eq(insert->k.p, path->pos)); k = bch2_btree_node_iter_peek_all(node_iter, b); if (k && bkey_cmp_left_packed(b, k, &insert->k.p)) k = NULL; /* @k is the key being overwritten/deleted, if any: */ EBUG_ON(k && bkey_deleted(k)); /* Deleting, but not found? nothing to do: */ if (bkey_deleted(&insert->k) && !k) return false; if (bkey_deleted(&insert->k)) { /* Deleting: */ btree_account_key_drop(b, k); k->type = KEY_TYPE_deleted; if (k->needs_whiteout) push_whiteout(b, insert->k.p); k->needs_whiteout = false; if (k >= btree_bset_last(b)->start) { clobber_u64s = k->u64s; bch2_bset_delete(b, k, clobber_u64s); goto fix_iter; } else { bch2_btree_path_fix_key_modified(trans, b, k); } return true; } if (k) { /* Overwriting: */ btree_account_key_drop(b, k); k->type = KEY_TYPE_deleted; insert->k.needs_whiteout = k->needs_whiteout; k->needs_whiteout = false; if (k >= btree_bset_last(b)->start) { clobber_u64s = k->u64s; goto overwrite; } else { bch2_btree_path_fix_key_modified(trans, b, k); } } k = bch2_btree_node_iter_bset_pos(node_iter, b, bset_tree_last(b)); overwrite: bch2_bset_insert(b, k, insert, clobber_u64s); new_u64s = k->u64s; fix_iter: if (clobber_u64s != new_u64s) bch2_btree_node_iter_fix(trans, path, b, node_iter, k, clobber_u64s, new_u64s); return true; } static int __btree_node_flush(struct journal *j, struct journal_entry_pin *pin, unsigned i, u64 seq) { struct bch_fs *c = container_of(j, struct bch_fs, journal); struct btree_write *w = container_of(pin, struct btree_write, journal); struct btree *b = container_of(w, struct btree, writes[i]); struct btree_trans *trans = bch2_trans_get(c); unsigned long old, new; unsigned idx = w - b->writes; btree_node_lock_nopath_nofail(trans, &b->c, SIX_LOCK_read); old = READ_ONCE(b->flags); do { new = old; if (!(old & (1 << BTREE_NODE_dirty)) || !!(old & (1 << BTREE_NODE_write_idx)) != idx || w->journal.seq != seq) break; new &= ~BTREE_WRITE_TYPE_MASK; new |= BTREE_WRITE_journal_reclaim; new |= 1 << BTREE_NODE_need_write; } while (!try_cmpxchg(&b->flags, &old, new)); btree_node_write_if_need(c, b, SIX_LOCK_read); six_unlock_read(&b->c.lock); bch2_trans_put(trans); return 0; } int bch2_btree_node_flush0(struct journal *j, struct journal_entry_pin *pin, u64 seq) { return __btree_node_flush(j, pin, 0, seq); } int bch2_btree_node_flush1(struct journal *j, struct journal_entry_pin *pin, u64 seq) { return __btree_node_flush(j, pin, 1, seq); } inline void bch2_btree_add_journal_pin(struct bch_fs *c, struct btree *b, u64 seq) { struct btree_write *w = btree_current_write(b); bch2_journal_pin_add(&c->journal, seq, &w->journal, btree_node_write_idx(b) == 0 ? bch2_btree_node_flush0 : bch2_btree_node_flush1); } /** * bch2_btree_insert_key_leaf() - insert a key one key into a leaf node * @trans: btree transaction object * @path: path pointing to @insert's pos * @insert: key to insert * @journal_seq: sequence number of journal reservation */ inline void bch2_btree_insert_key_leaf(struct btree_trans *trans, struct btree_path *path, struct bkey_i *insert, u64 journal_seq) { struct bch_fs *c = trans->c; struct btree *b = path_l(path)->b; struct bset_tree *t = bset_tree_last(b); struct bset *i = bset(b, t); int old_u64s = bset_u64s(t); int old_live_u64s = b->nr.live_u64s; int live_u64s_added, u64s_added; if (unlikely(!bch2_btree_bset_insert_key(trans, path, b, &path_l(path)->iter, insert))) return; i->journal_seq = cpu_to_le64(max(journal_seq, le64_to_cpu(i->journal_seq))); bch2_btree_add_journal_pin(c, b, journal_seq); if (unlikely(!btree_node_dirty(b))) { EBUG_ON(test_bit(BCH_FS_clean_shutdown, &c->flags)); set_btree_node_dirty_acct(c, b); } live_u64s_added = (int) b->nr.live_u64s - old_live_u64s; u64s_added = (int) bset_u64s(t) - old_u64s; if (b->sib_u64s[0] != U16_MAX && live_u64s_added < 0) b->sib_u64s[0] = max(0, (int) b->sib_u64s[0] + live_u64s_added); if (b->sib_u64s[1] != U16_MAX && live_u64s_added < 0) b->sib_u64s[1] = max(0, (int) b->sib_u64s[1] + live_u64s_added); if (u64s_added > live_u64s_added && bch2_maybe_compact_whiteouts(c, b)) bch2_trans_node_reinit_iter(trans, b); } /* Cached btree updates: */ /* Normal update interface: */ static inline void btree_insert_entry_checks(struct btree_trans *trans, struct btree_insert_entry *i) { struct btree_path *path = trans->paths + i->path; BUG_ON(!bpos_eq(i->k->k.p, path->pos)); BUG_ON(i->cached != path->cached); BUG_ON(i->level != path->level); BUG_ON(i->btree_id != path->btree_id); EBUG_ON(!i->level && btree_type_has_snapshots(i->btree_id) && !(i->flags & BTREE_UPDATE_internal_snapshot_node) && test_bit(JOURNAL_replay_done, &trans->c->journal.flags) && i->k->k.p.snapshot && bch2_snapshot_is_internal_node(trans->c, i->k->k.p.snapshot) > 0); } static __always_inline int bch2_trans_journal_res_get(struct btree_trans *trans, unsigned flags) { return bch2_journal_res_get(&trans->c->journal, &trans->journal_res, trans->journal_u64s, flags); } #define JSET_ENTRY_LOG_U64s 4 static noinline void journal_transaction_name(struct btree_trans *trans) { struct bch_fs *c = trans->c; struct journal *j = &c->journal; struct jset_entry *entry = bch2_journal_add_entry(j, &trans->journal_res, BCH_JSET_ENTRY_log, 0, 0, JSET_ENTRY_LOG_U64s); struct jset_entry_log *l = container_of(entry, struct jset_entry_log, entry); strncpy(l->d, trans->fn, JSET_ENTRY_LOG_U64s * sizeof(u64)); } static inline int btree_key_can_insert(struct btree_trans *trans, struct btree *b, unsigned u64s) { if (!bch2_btree_node_insert_fits(b, u64s)) return -BCH_ERR_btree_insert_btree_node_full; return 0; } noinline static int btree_key_can_insert_cached_slowpath(struct btree_trans *trans, unsigned flags, struct btree_path *path, unsigned new_u64s) { struct bkey_cached *ck = (void *) path->l[0].b; struct bkey_i *new_k; int ret; bch2_trans_unlock_write(trans); bch2_trans_unlock(trans); new_k = kmalloc(new_u64s * sizeof(u64), GFP_KERNEL); if (!new_k) { bch_err(trans->c, "error allocating memory for key cache key, btree %s u64s %u", bch2_btree_id_str(path->btree_id), new_u64s); return -BCH_ERR_ENOMEM_btree_key_cache_insert; } ret = bch2_trans_relock(trans) ?: bch2_trans_lock_write(trans); if (unlikely(ret)) { kfree(new_k); return ret; } memcpy(new_k, ck->k, ck->u64s * sizeof(u64)); trans_for_each_update(trans, i) if (i->old_v == &ck->k->v) i->old_v = &new_k->v; kfree(ck->k); ck->u64s = new_u64s; ck->k = new_k; return 0; } static int btree_key_can_insert_cached(struct btree_trans *trans, unsigned flags, struct btree_path *path, unsigned u64s) { struct bch_fs *c = trans->c; struct bkey_cached *ck = (void *) path->l[0].b; unsigned new_u64s; struct bkey_i *new_k; unsigned watermark = flags & BCH_WATERMARK_MASK; EBUG_ON(path->level); if (watermark < BCH_WATERMARK_reclaim && !test_bit(BKEY_CACHED_DIRTY, &ck->flags) && bch2_btree_key_cache_must_wait(c)) return -BCH_ERR_btree_insert_need_journal_reclaim; /* * bch2_varint_decode can read past the end of the buffer by at most 7 * bytes (it won't be used): */ u64s += 1; if (u64s <= ck->u64s) return 0; new_u64s = roundup_pow_of_two(u64s); new_k = krealloc(ck->k, new_u64s * sizeof(u64), GFP_NOWAIT|__GFP_NOWARN); if (unlikely(!new_k)) return btree_key_can_insert_cached_slowpath(trans, flags, path, new_u64s); trans_for_each_update(trans, i) if (i->old_v == &ck->k->v) i->old_v = &new_k->v; ck->u64s = new_u64s; ck->k = new_k; return 0; } /* Triggers: */ static int run_one_mem_trigger(struct btree_trans *trans, struct btree_insert_entry *i, unsigned flags) { verify_update_old_key(trans, i); if (unlikely(flags & BTREE_TRIGGER_norun)) return 0; 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); if (old_ops->trigger == new_ops->trigger) return bch2_key_trigger(trans, i->btree_id, i->level, old, bkey_i_to_s(new), BTREE_TRIGGER_insert|BTREE_TRIGGER_overwrite|flags); else return bch2_key_trigger_new(trans, i->btree_id, i->level, bkey_i_to_s(new), flags) ?: bch2_key_trigger_old(trans, i->btree_id, i->level, old, flags); } static int run_one_trans_trigger(struct btree_trans *trans, struct btree_insert_entry *i, bool overwrite) { verify_update_old_key(trans, i); if ((i->flags & BTREE_TRIGGER_norun) || !btree_node_type_has_trans_triggers(i->bkey_type)) return 0; /* * Transactional triggers create new btree_insert_entries, so we can't * pass them a pointer to a btree_insert_entry, that memory is going to * move: */ 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); unsigned flags = i->flags|BTREE_TRIGGER_transactional;