xref: /linux/fs/bcachefs/lru.c (revision ff0905bbf991f4337b5ebc19c0d43525ebb0d96b)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include "bcachefs.h"
4 #include "alloc_background.h"
5 #include "bkey_buf.h"
6 #include "btree_iter.h"
7 #include "btree_update.h"
8 #include "btree_write_buffer.h"
9 #include "ec.h"
10 #include "error.h"
11 #include "lru.h"
12 #include "recovery.h"
13 
14 /* KEY_TYPE_lru is obsolete: */
bch2_lru_validate(struct bch_fs * c,struct bkey_s_c k,struct bkey_validate_context from)15 int bch2_lru_validate(struct bch_fs *c, struct bkey_s_c k,
16 		      struct bkey_validate_context from)
17 {
18 	int ret = 0;
19 
20 	bkey_fsck_err_on(!lru_pos_time(k.k->p),
21 			 c, lru_entry_at_time_0,
22 			 "lru entry at time=0");
23 fsck_err:
24 	return ret;
25 }
26 
bch2_lru_to_text(struct printbuf * out,struct bch_fs * c,struct bkey_s_c k)27 void bch2_lru_to_text(struct printbuf *out, struct bch_fs *c,
28 		      struct bkey_s_c k)
29 {
30 	const struct bch_lru *lru = bkey_s_c_to_lru(k).v;
31 
32 	prt_printf(out, "idx %llu", le64_to_cpu(lru->idx));
33 }
34 
bch2_lru_pos_to_text(struct printbuf * out,struct bpos lru)35 void bch2_lru_pos_to_text(struct printbuf *out, struct bpos lru)
36 {
37 	prt_printf(out, "%llu:%llu -> %llu:%llu",
38 		   lru_pos_id(lru),
39 		   lru_pos_time(lru),
40 		   u64_to_bucket(lru.offset).inode,
41 		   u64_to_bucket(lru.offset).offset);
42 }
43 
__bch2_lru_set(struct btree_trans * trans,u16 lru_id,u64 dev_bucket,u64 time,bool set)44 static int __bch2_lru_set(struct btree_trans *trans, u16 lru_id,
45 			  u64 dev_bucket, u64 time, bool set)
46 {
47 	return time
48 		? bch2_btree_bit_mod_buffered(trans, BTREE_ID_lru,
49 					      lru_pos(lru_id, dev_bucket, time), set)
50 		: 0;
51 }
52 
bch2_lru_del(struct btree_trans * trans,u16 lru_id,u64 dev_bucket,u64 time)53 int bch2_lru_del(struct btree_trans *trans, u16 lru_id, u64 dev_bucket, u64 time)
54 {
55 	return __bch2_lru_set(trans, lru_id, dev_bucket, time, KEY_TYPE_deleted);
56 }
57 
bch2_lru_set(struct btree_trans * trans,u16 lru_id,u64 dev_bucket,u64 time)58 int bch2_lru_set(struct btree_trans *trans, u16 lru_id, u64 dev_bucket, u64 time)
59 {
60 	return __bch2_lru_set(trans, lru_id, dev_bucket, time, KEY_TYPE_set);
61 }
62 
__bch2_lru_change(struct btree_trans * trans,u16 lru_id,u64 dev_bucket,u64 old_time,u64 new_time)63 int __bch2_lru_change(struct btree_trans *trans,
64 		      u16 lru_id, u64 dev_bucket,
65 		      u64 old_time, u64 new_time)
66 {
67 	if (old_time == new_time)
68 		return 0;
69 
70 	return  bch2_lru_del(trans, lru_id, dev_bucket, old_time) ?:
71 		bch2_lru_set(trans, lru_id, dev_bucket, new_time);
72 }
73 
74 static const char * const bch2_lru_types[] = {
75 #define x(n) #n,
76 	BCH_LRU_TYPES()
77 #undef x
78 	NULL
79 };
80 
bch2_lru_check_set(struct btree_trans * trans,u16 lru_id,u64 dev_bucket,u64 time,struct bkey_s_c referring_k,struct bkey_buf * last_flushed)81 int bch2_lru_check_set(struct btree_trans *trans,
82 		       u16 lru_id,
83 		       u64 dev_bucket,
84 		       u64 time,
85 		       struct bkey_s_c referring_k,
86 		       struct bkey_buf *last_flushed)
87 {
88 	struct bch_fs *c = trans->c;
89 	struct printbuf buf = PRINTBUF;
90 	struct btree_iter lru_iter;
91 	struct bkey_s_c lru_k =
92 		bch2_bkey_get_iter(trans, &lru_iter, BTREE_ID_lru,
93 				   lru_pos(lru_id, dev_bucket, time), 0);
94 	int ret = bkey_err(lru_k);
95 	if (ret)
96 		return ret;
97 
98 	if (lru_k.k->type != KEY_TYPE_set) {
99 		ret = bch2_btree_write_buffer_maybe_flush(trans, referring_k, last_flushed);
100 		if (ret)
101 			goto err;
102 
103 		if (fsck_err(trans, alloc_key_to_missing_lru_entry,
104 			     "missing %s lru entry\n%s",
105 			     bch2_lru_types[lru_type(lru_k)],
106 			     (bch2_bkey_val_to_text(&buf, c, referring_k), buf.buf))) {
107 			ret = bch2_lru_set(trans, lru_id, dev_bucket, time);
108 			if (ret)
109 				goto err;
110 		}
111 	}
112 err:
113 fsck_err:
114 	bch2_trans_iter_exit(trans, &lru_iter);
115 	printbuf_exit(&buf);
116 	return ret;
117 }
118 
lru_pos_to_bp(struct bkey_s_c lru_k)119 static struct bbpos lru_pos_to_bp(struct bkey_s_c lru_k)
120 {
121 	enum bch_lru_type type = lru_type(lru_k);
122 
123 	switch (type) {
124 	case BCH_LRU_read:
125 	case BCH_LRU_fragmentation:
126 		return BBPOS(BTREE_ID_alloc, u64_to_bucket(lru_k.k->p.offset));
127 	case BCH_LRU_stripes:
128 		return BBPOS(BTREE_ID_stripes, POS(0, lru_k.k->p.offset));
129 	default:
130 		BUG();
131 	}
132 }
133 
bkey_lru_type_idx(struct bch_fs * c,enum bch_lru_type type,struct bkey_s_c k)134 static u64 bkey_lru_type_idx(struct bch_fs *c,
135 			     enum bch_lru_type type,
136 			     struct bkey_s_c k)
137 {
138 	struct bch_alloc_v4 a_convert;
139 	const struct bch_alloc_v4 *a;
140 
141 	switch (type) {
142 	case BCH_LRU_read:
143 		a = bch2_alloc_to_v4(k, &a_convert);
144 		return alloc_lru_idx_read(*a);
145 	case BCH_LRU_fragmentation: {
146 		a = bch2_alloc_to_v4(k, &a_convert);
147 
148 		guard(rcu)();
149 		struct bch_dev *ca = bch2_dev_rcu_noerror(c, k.k->p.inode);
150 		return ca
151 			? alloc_lru_idx_fragmentation(*a, ca)
152 			: 0;
153 	}
154 	case BCH_LRU_stripes:
155 		return k.k->type == KEY_TYPE_stripe
156 			? stripe_lru_pos(bkey_s_c_to_stripe(k).v)
157 			: 0;
158 	default:
159 		BUG();
160 	}
161 }
162 
bch2_check_lru_key(struct btree_trans * trans,struct btree_iter * lru_iter,struct bkey_s_c lru_k,struct bkey_buf * last_flushed)163 static int bch2_check_lru_key(struct btree_trans *trans,
164 			      struct btree_iter *lru_iter,
165 			      struct bkey_s_c lru_k,
166 			      struct bkey_buf *last_flushed)
167 {
168 	struct bch_fs *c = trans->c;
169 	struct printbuf buf1 = PRINTBUF;
170 	struct printbuf buf2 = PRINTBUF;
171 
172 	struct bbpos bp = lru_pos_to_bp(lru_k);
173 
174 	struct btree_iter iter;
175 	struct bkey_s_c k = bch2_bkey_get_iter(trans, &iter, bp.btree, bp.pos, 0);
176 	int ret = bkey_err(k);
177 	if (ret)
178 		goto err;
179 
180 	enum bch_lru_type type = lru_type(lru_k);
181 	u64 idx = bkey_lru_type_idx(c, type, k);
182 
183 	if (lru_pos_time(lru_k.k->p) != idx) {
184 		ret = bch2_btree_write_buffer_maybe_flush(trans, lru_k, last_flushed);
185 		if (ret)
186 			goto err;
187 
188 		if (fsck_err(trans, lru_entry_bad,
189 			     "incorrect lru entry: lru %s time %llu\n"
190 			     "%s\n"
191 			     "for %s",
192 			     bch2_lru_types[type],
193 			     lru_pos_time(lru_k.k->p),
194 			     (bch2_bkey_val_to_text(&buf1, c, lru_k), buf1.buf),
195 			     (bch2_bkey_val_to_text(&buf2, c, k), buf2.buf)))
196 			ret = bch2_btree_bit_mod_buffered(trans, BTREE_ID_lru, lru_iter->pos, false);
197 	}
198 err:
199 fsck_err:
200 	bch2_trans_iter_exit(trans, &iter);
201 	printbuf_exit(&buf2);
202 	printbuf_exit(&buf1);
203 	return ret;
204 }
205 
bch2_check_lrus(struct bch_fs * c)206 int bch2_check_lrus(struct bch_fs *c)
207 {
208 	struct bkey_buf last_flushed;
209 
210 	bch2_bkey_buf_init(&last_flushed);
211 	bkey_init(&last_flushed.k->k);
212 
213 	int ret = bch2_trans_run(c,
214 		for_each_btree_key_commit(trans, iter,
215 				BTREE_ID_lru, POS_MIN, BTREE_ITER_prefetch, k,
216 				NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
217 			bch2_check_lru_key(trans, &iter, k, &last_flushed)));
218 
219 	bch2_bkey_buf_exit(&last_flushed, c);
220 	bch_err_fn(c, ret);
221 	return ret;
222 
223 }
224