]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/lru.c
Update bcachefs sources to 5e392aed7a bcachefs: Kill bch2_alloc_write()
[bcachefs-tools-debian] / libbcachefs / lru.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include "bcachefs.h"
4 #include "alloc_background.h"
5 #include "btree_iter.h"
6 #include "btree_update.h"
7 #include "error.h"
8 #include "lru.h"
9 #include "recovery.h"
10
11 const char *bch2_lru_invalid(const struct bch_fs *c, struct bkey_s_c k)
12 {
13         const struct bch_lru *lru = bkey_s_c_to_lru(k).v;
14
15         if (bkey_val_bytes(k.k) < sizeof(*lru))
16                 return "incorrect value size";
17
18         return NULL;
19 }
20
21 void bch2_lru_to_text(struct printbuf *out, struct bch_fs *c,
22                       struct bkey_s_c k)
23 {
24         const struct bch_lru *lru = bkey_s_c_to_lru(k).v;
25
26         pr_buf(out, "idx %llu", le64_to_cpu(lru->idx));
27 }
28
29 static int lru_delete(struct btree_trans *trans, u64 id, u64 idx, u64 time)
30 {
31         struct bch_fs *c = trans->c;
32         struct btree_iter iter;
33         struct bkey_s_c k;
34         u64 existing_idx;
35         int ret = 0;
36
37         if (!time)
38                 return 0;
39
40         bch2_trans_iter_init(trans, &iter, BTREE_ID_lru,
41                              POS(id, time),
42                              BTREE_ITER_INTENT|
43                              BTREE_ITER_WITH_UPDATES);
44         k = bch2_btree_iter_peek_slot(&iter);
45         ret = bkey_err(k);
46         if (ret)
47                 goto err;
48
49         if (k.k->type != KEY_TYPE_lru) {
50                 bch2_fs_inconsistent(c,
51                         "pointer to nonexistent lru %llu:%llu",
52                         id, time);
53                 ret = -EIO;
54                 goto err;
55         }
56
57         existing_idx = le64_to_cpu(bkey_s_c_to_lru(k).v->idx);
58         if (existing_idx != idx) {
59                 bch2_fs_inconsistent(c,
60                         "lru %llu:%llu with wrong backpointer: got %llu, should be %llu",
61                         id, time, existing_idx, idx);
62                 ret = -EIO;
63                 goto err;
64         }
65
66         ret = bch2_btree_delete_at(trans, &iter, 0);
67 err:
68         bch2_trans_iter_exit(trans, &iter);
69         return ret;
70 }
71
72 static int lru_set(struct btree_trans *trans, u64 lru_id, u64 idx, u64 *time)
73 {
74         struct btree_iter iter;
75         struct bkey_s_c k;
76         struct bkey_i_lru *lru;
77         int ret = 0;
78
79         if (!*time)
80                 return 0;
81
82         for_each_btree_key_norestart(trans, iter, BTREE_ID_lru,
83                         POS(lru_id, *time),
84                         BTREE_ITER_SLOTS|
85                         BTREE_ITER_INTENT|
86                         BTREE_ITER_WITH_UPDATES, k, ret)
87                 if (bkey_deleted(k.k))
88                         break;
89
90         if (ret)
91                 goto err;
92
93         BUG_ON(iter.pos.inode != lru_id);
94         *time = iter.pos.offset;
95
96         lru = bch2_trans_kmalloc(trans, sizeof(*lru));
97         ret = PTR_ERR_OR_ZERO(lru);
98         if (ret)
99                 goto err;
100
101         bkey_lru_init(&lru->k_i);
102         lru->k.p        = iter.pos;
103         lru->v.idx      = cpu_to_le64(idx);
104
105         ret = bch2_trans_update(trans, &iter, &lru->k_i, 0);
106         if (ret)
107                 goto err;
108 err:
109         bch2_trans_iter_exit(trans, &iter);
110         return ret;
111 }
112
113 int bch2_lru_change(struct btree_trans *trans, u64 id, u64 idx,
114                     u64 old_time, u64 *new_time)
115 {
116         if (old_time == *new_time)
117                 return 0;
118
119         return  lru_delete(trans, id, idx, old_time) ?:
120                 lru_set(trans, id, idx, new_time);
121 }
122
123 static int bch2_check_lru_key(struct btree_trans *trans,
124                               struct btree_iter *lru_iter, bool initial)
125 {
126         struct bch_fs *c = trans->c;
127         struct btree_iter iter;
128         struct bkey_s_c lru_k, k;
129         struct bch_alloc_v4 a;
130         struct printbuf buf1 = PRINTBUF;
131         struct printbuf buf2 = PRINTBUF;
132         u64 idx;
133         int ret;
134
135         lru_k = bch2_btree_iter_peek(lru_iter);
136         if (!lru_k.k)
137                 return 0;
138
139         ret = bkey_err(lru_k);
140         if (ret)
141                 return ret;
142
143         idx = le64_to_cpu(bkey_s_c_to_lru(lru_k).v->idx);
144
145         bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc,
146                              POS(lru_k.k->p.inode, idx), 0);
147         k = bch2_btree_iter_peek_slot(&iter);
148         ret = bkey_err(k);
149         if (ret)
150                 goto err;
151
152         bch2_alloc_to_v4(k, &a);
153
154         if (fsck_err_on(bucket_state(a) != BUCKET_cached ||
155                         a.io_time[READ] != lru_k.k->p.offset, c,
156                         "incorrect lru entry %s\n"
157                         "  for %s",
158                         (bch2_bkey_val_to_text(&buf1, c, lru_k), buf1.buf),
159                         (bch2_bkey_val_to_text(&buf2, c, k), buf2.buf))) {
160                 struct bkey_i *update =
161                         bch2_trans_kmalloc(trans, sizeof(*update));
162
163                 ret = PTR_ERR_OR_ZERO(update);
164                 if (ret)
165                         goto err;
166
167                 bkey_init(&update->k);
168                 update->k.p = lru_iter->pos;
169
170                 ret = bch2_trans_update(trans, lru_iter, update, 0);
171                 if (ret)
172                         goto err;
173         }
174 err:
175 fsck_err:
176         bch2_trans_iter_exit(trans, &iter);
177         printbuf_exit(&buf2);
178         printbuf_exit(&buf1);
179         return ret;
180 }
181
182 int bch2_check_lrus(struct bch_fs *c, bool initial)
183 {
184         struct btree_trans trans;
185         struct btree_iter iter;
186         struct bkey_s_c k;
187         int ret = 0;
188
189         bch2_trans_init(&trans, c, 0, 0);
190
191         for_each_btree_key(&trans, iter, BTREE_ID_lru, POS_MIN,
192                            BTREE_ITER_PREFETCH, k, ret) {
193                 ret = __bch2_trans_do(&trans, NULL, NULL, 0,
194                         bch2_check_lru_key(&trans, &iter, initial));
195                 if (ret)
196                         break;
197         }
198         bch2_trans_iter_exit(&trans, &iter);
199
200         bch2_trans_exit(&trans);
201         return ret;
202
203 }