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