xref: /linux/fs/bcachefs/sb-members.c (revision 031fba65fc202abf1f193e321be7a2c274fd88ba)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include "bcachefs.h"
4 #include "disk_groups.h"
5 #include "opts.h"
6 #include "replicas.h"
7 #include "sb-members.h"
8 #include "super-io.h"
9 
10 /* Code for bch_sb_field_members_v1: */
11 
12 static struct bch_member *members_v2_get_mut(struct bch_sb_field_members_v2 *mi, int i)
13 {
14 	return (void *) mi->_members + (i * le16_to_cpu(mi->member_bytes));
15 }
16 
17 struct bch_member *bch2_members_v2_get_mut(struct bch_sb *sb, int i)
18 {
19 	return members_v2_get_mut(bch2_sb_field_get(sb, members_v2), i);
20 }
21 
22 static struct bch_member members_v2_get(struct bch_sb_field_members_v2 *mi, int i)
23 {
24 	struct bch_member ret, *p = members_v2_get_mut(mi, i);
25 	memset(&ret, 0, sizeof(ret));
26 	memcpy(&ret, p, min_t(size_t, le16_to_cpu(mi->member_bytes), sizeof(ret)));
27 	return ret;
28 }
29 
30 static struct bch_member *members_v1_get_mut(struct bch_sb_field_members_v1 *mi, int i)
31 {
32 	return (void *) mi->_members + (i * BCH_MEMBER_V1_BYTES);
33 }
34 
35 static struct bch_member members_v1_get(struct bch_sb_field_members_v1 *mi, int i)
36 {
37 	struct bch_member ret, *p = members_v1_get_mut(mi, i);
38 	memset(&ret, 0, sizeof(ret));
39 	memcpy(&ret, p, min_t(size_t, sizeof(struct bch_member), sizeof(ret))); return ret;
40 }
41 
42 struct bch_member bch2_sb_member_get(struct bch_sb *sb, int i)
43 {
44 	struct bch_sb_field_members_v2 *mi2 = bch2_sb_field_get(sb, members_v2);
45 	if (mi2)
46 		return members_v2_get(mi2, i);
47 	struct bch_sb_field_members_v1 *mi1 = bch2_sb_field_get(sb, members_v1);
48 	return members_v1_get(mi1, i);
49 }
50 
51 static int sb_members_v2_resize_entries(struct bch_fs *c)
52 {
53 	struct bch_sb_field_members_v2 *mi = bch2_sb_field_get(c->disk_sb.sb, members_v2);
54 
55 	if (le16_to_cpu(mi->member_bytes) < sizeof(struct bch_member)) {
56 		unsigned u64s = DIV_ROUND_UP((sizeof(*mi) + sizeof(mi->_members[0]) *
57 					      c->disk_sb.sb->nr_devices), 8);
58 
59 		mi = bch2_sb_field_resize(&c->disk_sb, members_v2, u64s);
60 		if (!mi)
61 			return -BCH_ERR_ENOSPC_sb_members_v2;
62 
63 		for (int i = c->disk_sb.sb->nr_devices - 1; i >= 0; --i) {
64 			void *dst = (void *) mi->_members + (i * sizeof(struct bch_member));
65 			memmove(dst, members_v2_get_mut(mi, i), le16_to_cpu(mi->member_bytes));
66 			memset(dst + le16_to_cpu(mi->member_bytes),
67 			       0, (sizeof(struct bch_member) - le16_to_cpu(mi->member_bytes)));
68 		}
69 		mi->member_bytes = cpu_to_le16(sizeof(struct bch_member));
70 	}
71 	return 0;
72 }
73 
74 int bch2_members_v2_init(struct bch_fs *c)
75 {
76 	struct bch_sb_field_members_v1 *mi1;
77 	struct bch_sb_field_members_v2 *mi2;
78 
79 	if (!bch2_sb_field_get(c->disk_sb.sb, members_v2)) {
80 		mi2 = bch2_sb_field_resize(&c->disk_sb, members_v2,
81 				DIV_ROUND_UP(sizeof(*mi2) +
82 					     sizeof(struct bch_member) * c->sb.nr_devices,
83 					     sizeof(u64)));
84 		mi1 = bch2_sb_field_get(c->disk_sb.sb, members_v1);
85 		memcpy(&mi2->_members[0], &mi1->_members[0],
86 		       BCH_MEMBER_V1_BYTES * c->sb.nr_devices);
87 		memset(&mi2->pad[0], 0, sizeof(mi2->pad));
88 		mi2->member_bytes = cpu_to_le16(BCH_MEMBER_V1_BYTES);
89 	}
90 
91 	return sb_members_v2_resize_entries(c);
92 }
93 
94 int bch_members_cpy_v2_v1(struct bch_sb_handle *disk_sb)
95 {
96 	struct bch_sb_field_members_v1 *mi1;
97 	struct bch_sb_field_members_v2 *mi2;
98 
99 	mi1 = bch2_sb_field_resize(disk_sb, members_v1,
100 			DIV_ROUND_UP(sizeof(*mi1) + BCH_MEMBER_V1_BYTES *
101 				     disk_sb->sb->nr_devices, sizeof(u64)));
102 	if (!mi1)
103 		return -BCH_ERR_ENOSPC_sb_members;
104 
105 	mi2 = bch2_sb_field_get(disk_sb->sb, members_v2);
106 
107 	for (unsigned i = 0; i < disk_sb->sb->nr_devices; i++)
108 		memcpy(members_v1_get_mut(mi1, i), members_v2_get_mut(mi2, i), BCH_MEMBER_V1_BYTES);
109 
110 	return 0;
111 }
112 
113 static int validate_member(struct printbuf *err,
114 			   struct bch_member m,
115 			   struct bch_sb *sb,
116 			   int i)
117 {
118 	if (le64_to_cpu(m.nbuckets) > LONG_MAX) {
119 		prt_printf(err, "device %u: too many buckets (got %llu, max %lu)",
120 			   i, le64_to_cpu(m.nbuckets), LONG_MAX);
121 		return -BCH_ERR_invalid_sb_members;
122 	}
123 
124 	if (le64_to_cpu(m.nbuckets) -
125 	    le16_to_cpu(m.first_bucket) < BCH_MIN_NR_NBUCKETS) {
126 		prt_printf(err, "device %u: not enough buckets (got %llu, max %u)",
127 			   i, le64_to_cpu(m.nbuckets), BCH_MIN_NR_NBUCKETS);
128 		return -BCH_ERR_invalid_sb_members;
129 	}
130 
131 	if (le16_to_cpu(m.bucket_size) <
132 	    le16_to_cpu(sb->block_size)) {
133 		prt_printf(err, "device %u: bucket size %u smaller than block size %u",
134 			   i, le16_to_cpu(m.bucket_size), le16_to_cpu(sb->block_size));
135 		return -BCH_ERR_invalid_sb_members;
136 	}
137 
138 	if (le16_to_cpu(m.bucket_size) <
139 	    BCH_SB_BTREE_NODE_SIZE(sb)) {
140 		prt_printf(err, "device %u: bucket size %u smaller than btree node size %llu",
141 			   i, le16_to_cpu(m.bucket_size), BCH_SB_BTREE_NODE_SIZE(sb));
142 		return -BCH_ERR_invalid_sb_members;
143 	}
144 
145 	return 0;
146 }
147 
148 static void member_to_text(struct printbuf *out,
149 			   struct bch_member m,
150 			   struct bch_sb_field_disk_groups *gi,
151 			   struct bch_sb *sb,
152 			   int i)
153 {
154 	unsigned data_have = bch2_sb_dev_has_data(sb, i);
155 	u64 bucket_size = le16_to_cpu(m.bucket_size);
156 	u64 device_size = le64_to_cpu(m.nbuckets) * bucket_size;
157 
158 
159 	prt_printf(out, "Device:");
160 	prt_tab(out);
161 	prt_printf(out, "%u", i);
162 	prt_newline(out);
163 
164 	printbuf_indent_add(out, 2);
165 
166 	prt_printf(out, "UUID:");
167 	prt_tab(out);
168 	pr_uuid(out, m.uuid.b);
169 	prt_newline(out);
170 
171 	prt_printf(out, "Size:");
172 	prt_tab(out);
173 	prt_units_u64(out, device_size << 9);
174 	prt_newline(out);
175 
176 	for (unsigned i = 0; i < BCH_IOPS_NR; i++) {
177 		prt_printf(out, "%s iops:", bch2_iops_measurements[i]);
178 		prt_tab(out);
179 		prt_printf(out, "%u", le32_to_cpu(m.iops[i]));
180 		prt_newline(out);
181 	}
182 
183 	prt_printf(out, "Bucket size:");
184 	prt_tab(out);
185 	prt_units_u64(out, bucket_size << 9);
186 	prt_newline(out);
187 
188 	prt_printf(out, "First bucket:");
189 	prt_tab(out);
190 	prt_printf(out, "%u", le16_to_cpu(m.first_bucket));
191 	prt_newline(out);
192 
193 	prt_printf(out, "Buckets:");
194 	prt_tab(out);
195 	prt_printf(out, "%llu", le64_to_cpu(m.nbuckets));
196 	prt_newline(out);
197 
198 	prt_printf(out, "Last mount:");
199 	prt_tab(out);
200 	if (m.last_mount)
201 		pr_time(out, le64_to_cpu(m.last_mount));
202 	else
203 		prt_printf(out, "(never)");
204 	prt_newline(out);
205 
206 	prt_printf(out, "State:");
207 	prt_tab(out);
208 	prt_printf(out, "%s",
209 		   BCH_MEMBER_STATE(&m) < BCH_MEMBER_STATE_NR
210 		   ? bch2_member_states[BCH_MEMBER_STATE(&m)]
211 		   : "unknown");
212 	prt_newline(out);
213 
214 	prt_printf(out, "Label:");
215 	prt_tab(out);
216 	if (BCH_MEMBER_GROUP(&m)) {
217 		unsigned idx = BCH_MEMBER_GROUP(&m) - 1;
218 
219 		if (idx < disk_groups_nr(gi))
220 			prt_printf(out, "%s (%u)",
221 				   gi->entries[idx].label, idx);
222 		else
223 			prt_printf(out, "(bad disk labels section)");
224 	} else {
225 		prt_printf(out, "(none)");
226 	}
227 	prt_newline(out);
228 
229 	prt_printf(out, "Data allowed:");
230 	prt_tab(out);
231 	if (BCH_MEMBER_DATA_ALLOWED(&m))
232 		prt_bitflags(out, bch2_data_types, BCH_MEMBER_DATA_ALLOWED(&m));
233 	else
234 		prt_printf(out, "(none)");
235 	prt_newline(out);
236 
237 	prt_printf(out, "Has data:");
238 	prt_tab(out);
239 	if (data_have)
240 		prt_bitflags(out, bch2_data_types, data_have);
241 	else
242 		prt_printf(out, "(none)");
243 	prt_newline(out);
244 
245 	prt_printf(out, "Discard:");
246 	prt_tab(out);
247 	prt_printf(out, "%llu", BCH_MEMBER_DISCARD(&m));
248 	prt_newline(out);
249 
250 	prt_printf(out, "Freespace initialized:");
251 	prt_tab(out);
252 	prt_printf(out, "%llu", BCH_MEMBER_FREESPACE_INITIALIZED(&m));
253 	prt_newline(out);
254 
255 	printbuf_indent_sub(out, 2);
256 }
257 
258 static int bch2_sb_members_v1_validate(struct bch_sb *sb,
259 				    struct bch_sb_field *f,
260 				    struct printbuf *err)
261 {
262 	struct bch_sb_field_members_v1 *mi = field_to_type(f, members_v1);
263 	unsigned i;
264 
265 	if ((void *) members_v1_get_mut(mi, sb->nr_devices)  >
266 	    vstruct_end(&mi->field)) {
267 		prt_printf(err, "too many devices for section size");
268 		return -BCH_ERR_invalid_sb_members;
269 	}
270 
271 	for (i = 0; i < sb->nr_devices; i++) {
272 		struct bch_member m = members_v1_get(mi, i);
273 
274 		int ret = validate_member(err, m, sb, i);
275 		if (ret)
276 			return ret;
277 	}
278 
279 	return 0;
280 }
281 
282 static void bch2_sb_members_v1_to_text(struct printbuf *out, struct bch_sb *sb,
283 				       struct bch_sb_field *f)
284 {
285 	struct bch_sb_field_members_v1 *mi = field_to_type(f, members_v1);
286 	struct bch_sb_field_disk_groups *gi = bch2_sb_field_get(sb, disk_groups);
287 	unsigned i;
288 
289 	for (i = 0; i < sb->nr_devices; i++) {
290 		struct bch_member m = members_v1_get(mi, i);
291 		member_to_text(out, m, gi, sb, i);
292 	}
293 }
294 
295 const struct bch_sb_field_ops bch_sb_field_ops_members_v1 = {
296 	.validate	= bch2_sb_members_v1_validate,
297 	.to_text	= bch2_sb_members_v1_to_text,
298 };
299 
300 static void bch2_sb_members_v2_to_text(struct printbuf *out, struct bch_sb *sb,
301 				       struct bch_sb_field *f)
302 {
303 	struct bch_sb_field_members_v2 *mi = field_to_type(f, members_v2);
304 	struct bch_sb_field_disk_groups *gi = bch2_sb_field_get(sb, disk_groups);
305 	unsigned i;
306 
307 	for (i = 0; i < sb->nr_devices; i++) {
308 		struct bch_member m = members_v2_get(mi, i);
309 		member_to_text(out, m, gi, sb, i);
310 	}
311 }
312 
313 static int bch2_sb_members_v2_validate(struct bch_sb *sb,
314 				       struct bch_sb_field *f,
315 				       struct printbuf *err)
316 {
317 	struct bch_sb_field_members_v2 *mi = field_to_type(f, members_v2);
318 	size_t mi_bytes = (void *) members_v2_get_mut(mi, sb->nr_devices) -
319 		(void *) mi;
320 
321 	if (mi_bytes > vstruct_bytes(&mi->field)) {
322 		prt_printf(err, "section too small (%zu > %zu)",
323 			   mi_bytes, vstruct_bytes(&mi->field));
324 		return -BCH_ERR_invalid_sb_members;
325 	}
326 
327 	for (unsigned i = 0; i < sb->nr_devices; i++) {
328 		int ret = validate_member(err, members_v2_get(mi, i), sb, i);
329 		if (ret)
330 			return ret;
331 	}
332 
333 	return 0;
334 }
335 
336 const struct bch_sb_field_ops bch_sb_field_ops_members_v2 = {
337 	.validate	= bch2_sb_members_v2_validate,
338 	.to_text	= bch2_sb_members_v2_to_text,
339 };
340