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 "io_misc.h" 8 #include "logged_ops.h" 9 #include "super.h" 10 11 struct bch_logged_op_fn { 12 u8 type; 13 int (*resume)(struct btree_trans *, struct bkey_i *); 14 }; 15 16 static const struct bch_logged_op_fn logged_op_fns[] = { 17 #define x(n) { \ 18 .type = KEY_TYPE_logged_op_##n, \ 19 .resume = bch2_resume_logged_op_##n, \ 20 }, 21 BCH_LOGGED_OPS() 22 #undef x 23 }; 24 25 static const struct bch_logged_op_fn *logged_op_fn(enum bch_bkey_type type) 26 { 27 for (unsigned i = 0; i < ARRAY_SIZE(logged_op_fns); i++) 28 if (logged_op_fns[i].type == type) 29 return logged_op_fns + i; 30 return NULL; 31 } 32 33 static int resume_logged_op(struct btree_trans *trans, struct btree_iter *iter, 34 struct bkey_s_c k) 35 { 36 struct bch_fs *c = trans->c; 37 u32 restart_count = trans->restart_count; 38 struct printbuf buf = PRINTBUF; 39 int ret = 0; 40 41 fsck_err_on(test_bit(BCH_FS_clean_recovery, &c->flags), 42 trans, logged_op_but_clean, 43 "filesystem marked as clean but have logged op\n%s", 44 (bch2_bkey_val_to_text(&buf, c, k), 45 buf.buf)); 46 47 struct bkey_buf sk; 48 bch2_bkey_buf_init(&sk); 49 bch2_bkey_buf_reassemble(&sk, c, k); 50 51 const struct bch_logged_op_fn *fn = logged_op_fn(sk.k->k.type); 52 if (fn) 53 fn->resume(trans, sk.k); 54 55 ret = bch2_logged_op_finish(trans, sk.k); 56 57 bch2_bkey_buf_exit(&sk, c); 58 fsck_err: 59 printbuf_exit(&buf); 60 return ret ?: trans_was_restarted(trans, restart_count); 61 } 62 63 int bch2_resume_logged_ops(struct bch_fs *c) 64 { 65 int ret = bch2_trans_run(c, 66 for_each_btree_key(trans, iter, 67 BTREE_ID_logged_ops, POS_MIN, 68 BTREE_ITER_prefetch, k, 69 resume_logged_op(trans, &iter, k))); 70 bch_err_fn(c, ret); 71 return ret; 72 } 73 74 static int __bch2_logged_op_start(struct btree_trans *trans, struct bkey_i *k) 75 { 76 struct btree_iter iter; 77 int ret; 78 79 ret = bch2_bkey_get_empty_slot(trans, &iter, BTREE_ID_logged_ops, POS_MAX); 80 if (ret) 81 return ret; 82 83 k->k.p = iter.pos; 84 85 ret = bch2_trans_update(trans, &iter, k, 0); 86 bch2_trans_iter_exit(trans, &iter); 87 return ret; 88 } 89 90 int bch2_logged_op_start(struct btree_trans *trans, struct bkey_i *k) 91 { 92 return commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc, 93 __bch2_logged_op_start(trans, k)); 94 } 95 96 int bch2_logged_op_finish(struct btree_trans *trans, struct bkey_i *k) 97 { 98 int ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc, 99 bch2_btree_delete(trans, BTREE_ID_logged_ops, k->k.p, 0)); 100 /* 101 * This needs to be a fatal error because we've left an unfinished 102 * operation in the logged ops btree. 103 * 104 * We should only ever see an error here if the filesystem has already 105 * been shut down, but make sure of that here: 106 */ 107 if (ret) { 108 struct bch_fs *c = trans->c; 109 struct printbuf buf = PRINTBUF; 110 111 bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(k)); 112 bch2_fs_fatal_error(c, "deleting logged operation %s: %s", 113 buf.buf, bch2_err_str(ret)); 114 printbuf_exit(&buf); 115 } 116 117 return ret; 118 } 119