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 11struct bch_logged_op_fn { 12 u8 type; 13 int (*resume)(struct btree_trans *, struct bkey_i *); 14}; 15 16static 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 25static 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 33static 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 const struct bch_logged_op_fn *fn = logged_op_fn(k.k->type); 38 struct bkey_buf sk; 39 u32 restart_count = trans->restart_count; 40 41 if (!fn) 42 return 0; 43 44 bch2_bkey_buf_init(&sk); 45 bch2_bkey_buf_reassemble(&sk, c, k); 46 47 fn->resume(trans, sk.k); 48 49 bch2_bkey_buf_exit(&sk, c); 50 51 return trans_was_restarted(trans, restart_count); 52} 53 54int bch2_resume_logged_ops(struct bch_fs *c) 55{ 56 int ret = bch2_trans_run(c, 57 for_each_btree_key(trans, iter, 58 BTREE_ID_logged_ops, POS_MIN, 59 BTREE_ITER_PREFETCH, k, 60 resume_logged_op(trans, &iter, k))); 61 bch_err_fn(c, ret); 62 return ret; 63} 64 65static int __bch2_logged_op_start(struct btree_trans *trans, struct bkey_i *k) 66{ 67 struct btree_iter iter; 68 int ret; 69 70 ret = bch2_bkey_get_empty_slot(trans, &iter, BTREE_ID_logged_ops, POS_MAX); 71 if (ret) 72 return ret; 73 74 k->k.p = iter.pos; 75 76 ret = bch2_trans_update(trans, &iter, k, 0); 77 bch2_trans_iter_exit(trans, &iter); 78 return ret; 79} 80 81int bch2_logged_op_start(struct btree_trans *trans, struct bkey_i *k) 82{ 83 return commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc, 84 __bch2_logged_op_start(trans, k)); 85} 86 87void bch2_logged_op_finish(struct btree_trans *trans, struct bkey_i *k) 88{ 89 int ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc, 90 bch2_btree_delete(trans, BTREE_ID_logged_ops, k->k.p, 0)); 91 /* 92 * This needs to be a fatal error because we've left an unfinished 93 * operation in the logged ops btree. 94 * 95 * We should only ever see an error here if the filesystem has already 96 * been shut down, but make sure of that here: 97 */ 98 if (ret) { 99 struct bch_fs *c = trans->c; 100 struct printbuf buf = PRINTBUF; 101 102 bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(k)); 103 bch2_fs_fatal_error(c, "deleting logged operation %s: %s", 104 buf.buf, bch2_err_str(ret)); 105 printbuf_exit(&buf); 106 } 107} 108