Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bcachefs: BTREE_ID_logged_ops

Add a new btree for long running logged operations - i.e. for logging
operations that we can't do within a single btree transaction, so that
they can be resumed if we crash.

Keys in the logged operations btree will represent operations in
progress, with the state of the operation stored in the value.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>

+156 -1
+1
fs/bcachefs/Makefile
··· 55 55 journal_sb.o \ 56 56 journal_seq_blacklist.o \ 57 57 keylist.o \ 58 + logged_ops.o \ 58 59 lru.o \ 59 60 mean_and_variance.o \ 60 61 migrate.o \
+1
fs/bcachefs/bcachefs.h
··· 454 454 GC_PHASE_BTREE_bucket_gens, 455 455 GC_PHASE_BTREE_snapshot_trees, 456 456 GC_PHASE_BTREE_deleted_inodes, 457 + GC_PHASE_BTREE_logged_ops, 457 458 458 459 GC_PHASE_PENDING_DELETE, 459 460 };
+3 -1
fs/bcachefs/bcachefs_format.h
··· 2249 2249 x(snapshot_trees, 15, 0, \ 2250 2250 BIT_ULL(KEY_TYPE_snapshot_tree)) \ 2251 2251 x(deleted_inodes, 16, BTREE_ID_SNAPSHOTS, \ 2252 - BIT_ULL(KEY_TYPE_set)) 2252 + BIT_ULL(KEY_TYPE_set)) \ 2253 + x(logged_ops, 17, 0, \ 2254 + 0) 2253 2255 2254 2256 enum btree_id { 2255 2257 #define x(name, nr, ...) BTREE_ID_##name = nr,
+18
fs/bcachefs/btree_update.c
··· 653 653 int ret; 654 654 655 655 bch2_trans_iter_init(trans, &iter, btree, k->k.p, 656 + BTREE_ITER_CACHED| 656 657 BTREE_ITER_NOT_EXTENTS| 657 658 BTREE_ITER_INTENT); 658 659 ret = bch2_btree_iter_traverse(&iter) ?: ··· 726 725 bkey_init(&k->k); 727 726 k->k.p = pos; 728 727 return bch2_trans_update_buffered(trans, btree, k); 728 + } 729 + 730 + int bch2_btree_delete(struct btree_trans *trans, 731 + enum btree_id btree, struct bpos pos, 732 + unsigned update_flags) 733 + { 734 + struct btree_iter iter; 735 + int ret; 736 + 737 + bch2_trans_iter_init(trans, &iter, btree, pos, 738 + BTREE_ITER_CACHED| 739 + BTREE_ITER_INTENT); 740 + ret = bch2_btree_iter_traverse(&iter) ?: 741 + bch2_btree_delete_at(trans, &iter, update_flags); 742 + bch2_trans_iter_exit(trans, &iter); 743 + 744 + return ret; 729 745 } 730 746 731 747 int bch2_btree_delete_range_trans(struct btree_trans *trans, enum btree_id id,
+1
fs/bcachefs/btree_update.h
··· 58 58 unsigned, unsigned); 59 59 int bch2_btree_delete_at(struct btree_trans *, struct btree_iter *, unsigned); 60 60 int bch2_btree_delete_at_buffered(struct btree_trans *, enum btree_id, struct bpos); 61 + int bch2_btree_delete(struct btree_trans *, enum btree_id, struct bpos, unsigned); 61 62 62 63 int bch2_btree_insert_nonextent(struct btree_trans *, enum btree_id, 63 64 struct bkey_i *, enum btree_update_flags);
+111
fs/bcachefs/logged_ops.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include "bcachefs.h" 4 + #include "bkey_buf.h" 5 + #include "btree_update.h" 6 + #include "error.h" 7 + #include "logged_ops.h" 8 + #include "super.h" 9 + 10 + struct bch_logged_op_fn { 11 + u8 type; 12 + int (*resume)(struct btree_trans *, struct bkey_i *); 13 + }; 14 + 15 + static const struct bch_logged_op_fn logged_op_fns[] = { 16 + #define x(n) { \ 17 + .type = KEY_TYPE_logged_op_##n, \ 18 + .resume = bch2_resume_logged_op_##n, \ 19 + }, 20 + BCH_LOGGED_OPS() 21 + #undef x 22 + }; 23 + 24 + static const struct bch_logged_op_fn *logged_op_fn(enum bch_bkey_type type) 25 + { 26 + for (unsigned i = 0; i < ARRAY_SIZE(logged_op_fns); i++) 27 + if (logged_op_fns[i].type == type) 28 + return logged_op_fns + i; 29 + return NULL; 30 + } 31 + 32 + static int resume_logged_op(struct btree_trans *trans, struct btree_iter *iter, 33 + struct bkey_s_c k) 34 + { 35 + struct bch_fs *c = trans->c; 36 + const struct bch_logged_op_fn *fn = logged_op_fn(k.k->type); 37 + struct bkey_buf sk; 38 + u32 restart_count = trans->restart_count; 39 + int ret; 40 + 41 + if (!fn) 42 + return 0; 43 + 44 + bch2_bkey_buf_init(&sk); 45 + bch2_bkey_buf_reassemble(&sk, c, k); 46 + 47 + ret = drop_locks_do(trans, (bch2_fs_lazy_rw(c), 0)) ?: 48 + fn->resume(trans, sk.k) ?: trans_was_restarted(trans, restart_count); 49 + 50 + bch2_bkey_buf_exit(&sk, c); 51 + return ret; 52 + } 53 + 54 + int bch2_resume_logged_ops(struct bch_fs *c) 55 + { 56 + struct btree_iter iter; 57 + struct bkey_s_c k; 58 + int ret; 59 + 60 + ret = bch2_trans_run(c, 61 + for_each_btree_key2(&trans, iter, 62 + BTREE_ID_logged_ops, POS_MIN, BTREE_ITER_PREFETCH, k, 63 + resume_logged_op(&trans, &iter, k))); 64 + if (ret) 65 + bch_err_fn(c, ret); 66 + return ret; 67 + } 68 + 69 + static int __bch2_logged_op_start(struct btree_trans *trans, struct bkey_i *k) 70 + { 71 + struct btree_iter iter; 72 + int ret; 73 + 74 + ret = bch2_bkey_get_empty_slot(trans, &iter, BTREE_ID_logged_ops, POS_MAX); 75 + if (ret) 76 + return ret; 77 + 78 + k->k.p = iter.pos; 79 + 80 + ret = bch2_trans_update(trans, &iter, k, 0); 81 + bch2_trans_iter_exit(trans, &iter); 82 + return ret; 83 + } 84 + 85 + int bch2_logged_op_start(struct btree_trans *trans, struct bkey_i *k) 86 + { 87 + return commit_do(trans, NULL, NULL, BTREE_INSERT_NOFAIL, 88 + __bch2_logged_op_start(trans, k)); 89 + } 90 + 91 + void bch2_logged_op_finish(struct btree_trans *trans, struct bkey_i *k) 92 + { 93 + int ret = commit_do(trans, NULL, NULL, BTREE_INSERT_NOFAIL, 94 + bch2_btree_delete(trans, BTREE_ID_logged_ops, k->k.p, 0)); 95 + /* 96 + * This needs to be a fatal error because we've left an unfinished 97 + * operation in the logged ops btree. 98 + * 99 + * We should only ever see an error here if the filesystem has already 100 + * been shut down, but make sure of that here: 101 + */ 102 + if (ret) { 103 + struct bch_fs *c = trans->c; 104 + struct printbuf buf = PRINTBUF; 105 + 106 + bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(k)); 107 + bch2_fs_fatal_error(c, "%s: error deleting logged operation %s: %s", 108 + __func__, buf.buf, bch2_err_str(ret)); 109 + printbuf_exit(&buf); 110 + } 111 + }
+18
fs/bcachefs/logged_ops.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _BCACHEFS_LOGGED_OPS_H 3 + #define _BCACHEFS_LOGGED_OPS_H 4 + 5 + #include "bkey.h" 6 + 7 + #define BCH_LOGGED_OPS() 8 + 9 + static inline int bch2_logged_op_update(struct btree_trans *trans, struct bkey_i *op) 10 + { 11 + return bch2_btree_insert_nonextent(trans, BTREE_ID_logged_ops, op, 0); 12 + } 13 + 14 + int bch2_resume_logged_ops(struct bch_fs *); 15 + int bch2_logged_op_start(struct btree_trans *, struct bkey_i *); 16 + void bch2_logged_op_finish(struct btree_trans *, struct bkey_i *); 17 + 18 + #endif /* _BCACHEFS_LOGGED_OPS_H */
+1
fs/bcachefs/recovery.c
··· 20 20 #include "journal_reclaim.h" 21 21 #include "journal_seq_blacklist.h" 22 22 #include "lru.h" 23 + #include "logged_ops.h" 23 24 #include "move.h" 24 25 #include "quota.h" 25 26 #include "recovery.h"
+1
fs/bcachefs/recovery_types.h
··· 29 29 x(check_subvols, PASS_FSCK) \ 30 30 x(delete_dead_snapshots, PASS_FSCK|PASS_UNCLEAN) \ 31 31 x(fs_upgrade_for_subvolumes, 0) \ 32 + x(resume_logged_ops, PASS_ALWAYS) \ 32 33 x(check_inodes, PASS_FSCK) \ 33 34 x(check_extents, PASS_FSCK) \ 34 35 x(check_dirents, PASS_FSCK) \
+1
fs/bcachefs/super.c
··· 791 791 c->btree_key_cache_btrees |= 1U << BTREE_ID_alloc; 792 792 if (c->opts.inodes_use_key_cache) 793 793 c->btree_key_cache_btrees |= 1U << BTREE_ID_inodes; 794 + c->btree_key_cache_btrees |= 1U << BTREE_ID_logged_ops; 794 795 795 796 c->block_bits = ilog2(block_sectors(c)); 796 797 c->btree_foreground_merge_threshold = BTREE_FOREGROUND_MERGE_THRESHOLD(c);