]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/logged_ops.c
Update bcachefs sources to f9c612bbf82d bcachefs: Fixes for building in userspace
[bcachefs-tools-debian] / libbcachefs / 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 "io_misc.h"
8 #include "logged_ops.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 = fn->resume(trans, sk.k) ?: trans_was_restarted(trans, restart_count);
48
49         bch2_bkey_buf_exit(&sk, c);
50         return ret;
51 }
52
53 int bch2_resume_logged_ops(struct bch_fs *c)
54 {
55         struct btree_iter iter;
56         struct bkey_s_c k;
57         int ret;
58
59         ret = bch2_trans_run(c,
60                 for_each_btree_key2(trans, iter,
61                                 BTREE_ID_logged_ops, POS_MIN, BTREE_ITER_PREFETCH, k,
62                         resume_logged_op(trans, &iter, k)));
63         if (ret)
64                 bch_err_fn(c, ret);
65         return ret;
66 }
67
68 static int __bch2_logged_op_start(struct btree_trans *trans, struct bkey_i *k)
69 {
70         struct btree_iter iter;
71         int ret;
72
73         ret = bch2_bkey_get_empty_slot(trans, &iter, BTREE_ID_logged_ops, POS_MAX);
74         if (ret)
75                 return ret;
76
77         k->k.p = iter.pos;
78
79         ret = bch2_trans_update(trans, &iter, k, 0);
80         bch2_trans_iter_exit(trans, &iter);
81         return ret;
82 }
83
84 int bch2_logged_op_start(struct btree_trans *trans, struct bkey_i *k)
85 {
86         return commit_do(trans, NULL, NULL, BTREE_INSERT_NOFAIL,
87                          __bch2_logged_op_start(trans, k));
88 }
89
90 void bch2_logged_op_finish(struct btree_trans *trans, struct bkey_i *k)
91 {
92         int ret = commit_do(trans, NULL, NULL, BTREE_INSERT_NOFAIL,
93                             bch2_btree_delete(trans, BTREE_ID_logged_ops, k->k.p, 0));
94         /*
95          * This needs to be a fatal error because we've left an unfinished
96          * operation in the logged ops btree.
97          *
98          * We should only ever see an error here if the filesystem has already
99          * been shut down, but make sure of that here:
100          */
101         if (ret) {
102                 struct bch_fs *c = trans->c;
103                 struct printbuf buf = PRINTBUF;
104
105                 bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(k));
106                 bch2_fs_fatal_error(c, "%s: error deleting logged operation %s: %s",
107                                      __func__, buf.buf, bch2_err_str(ret));
108                 printbuf_exit(&buf);
109         }
110 }