1  // SPDX-License-Identifier: GPL-2.0
2  #include "bcachefs.h"
3  #include "disk_groups.h"
4  #include "sb-members.h"
5  #include "super-io.h"
6  
7  #include <linux/sort.h>
8  
group_cmp(const void * _l,const void * _r)9  static int group_cmp(const void *_l, const void *_r)
10  {
11  	const struct bch_disk_group *l = _l;
12  	const struct bch_disk_group *r = _r;
13  
14  	return ((BCH_GROUP_DELETED(l) > BCH_GROUP_DELETED(r)) -
15  		(BCH_GROUP_DELETED(l) < BCH_GROUP_DELETED(r))) ?:
16  		((BCH_GROUP_PARENT(l) > BCH_GROUP_PARENT(r)) -
17  		 (BCH_GROUP_PARENT(l) < BCH_GROUP_PARENT(r))) ?:
18  		strncmp(l->label, r->label, sizeof(l->label));
19  }
20  
bch2_sb_disk_groups_validate(struct bch_sb * sb,struct bch_sb_field * f,enum bch_validate_flags flags,struct printbuf * err)21  static int bch2_sb_disk_groups_validate(struct bch_sb *sb, struct bch_sb_field *f,
22  				enum bch_validate_flags flags, struct printbuf *err)
23  {
24  	struct bch_sb_field_disk_groups *groups =
25  		field_to_type(f, disk_groups);
26  	struct bch_disk_group *g, *sorted = NULL;
27  	unsigned nr_groups = disk_groups_nr(groups);
28  	unsigned i, len;
29  	int ret = 0;
30  
31  	for (i = 0; i < sb->nr_devices; i++) {
32  		struct bch_member m = bch2_sb_member_get(sb, i);
33  		unsigned group_id;
34  
35  		if (!BCH_MEMBER_GROUP(&m))
36  			continue;
37  
38  		group_id = BCH_MEMBER_GROUP(&m) - 1;
39  
40  		if (group_id >= nr_groups) {
41  			prt_printf(err, "disk %u has invalid label %u (have %u)",
42  				   i, group_id, nr_groups);
43  			return -BCH_ERR_invalid_sb_disk_groups;
44  		}
45  
46  		if (BCH_GROUP_DELETED(&groups->entries[group_id])) {
47  			prt_printf(err, "disk %u has deleted label %u", i, group_id);
48  			return -BCH_ERR_invalid_sb_disk_groups;
49  		}
50  	}
51  
52  	if (!nr_groups)
53  		return 0;
54  
55  	for (i = 0; i < nr_groups; i++) {
56  		g = groups->entries + i;
57  
58  		if (BCH_GROUP_DELETED(g))
59  			continue;
60  
61  		len = strnlen(g->label, sizeof(g->label));
62  		if (!len) {
63  			prt_printf(err, "label %u empty", i);
64  			return -BCH_ERR_invalid_sb_disk_groups;
65  		}
66  	}
67  
68  	sorted = kmalloc_array(nr_groups, sizeof(*sorted), GFP_KERNEL);
69  	if (!sorted)
70  		return -BCH_ERR_ENOMEM_disk_groups_validate;
71  
72  	memcpy(sorted, groups->entries, nr_groups * sizeof(*sorted));
73  	sort(sorted, nr_groups, sizeof(*sorted), group_cmp, NULL);
74  
75  	for (g = sorted; g + 1 < sorted + nr_groups; g++)
76  		if (!BCH_GROUP_DELETED(g) &&
77  		    !group_cmp(&g[0], &g[1])) {
78  			prt_printf(err, "duplicate label %llu.%.*s",
79  			       BCH_GROUP_PARENT(g),
80  			       (int) sizeof(g->label), g->label);
81  			ret = -BCH_ERR_invalid_sb_disk_groups;
82  			goto err;
83  		}
84  err:
85  	kfree(sorted);
86  	return ret;
87  }
88  
bch2_disk_groups_to_text(struct printbuf * out,struct bch_fs * c)89  void bch2_disk_groups_to_text(struct printbuf *out, struct bch_fs *c)
90  {
91  	out->atomic++;
92  	rcu_read_lock();
93  
94  	struct bch_disk_groups_cpu *g = rcu_dereference(c->disk_groups);
95  	if (!g)
96  		goto out;
97  
98  	for (unsigned i = 0; i < g->nr; i++) {
99  		if (i)
100  			prt_printf(out, " ");
101  
102  		if (g->entries[i].deleted) {
103  			prt_printf(out, "[deleted]");
104  			continue;
105  		}
106  
107  		prt_printf(out, "[parent %d devs", g->entries[i].parent);
108  		for_each_member_device_rcu(c, ca, &g->entries[i].devs)
109  			prt_printf(out, " %s", ca->name);
110  		prt_printf(out, "]");
111  	}
112  
113  out:
114  	rcu_read_unlock();
115  	out->atomic--;
116  }
117  
bch2_sb_disk_groups_to_text(struct printbuf * out,struct bch_sb * sb,struct bch_sb_field * f)118  static void bch2_sb_disk_groups_to_text(struct printbuf *out,
119  					struct bch_sb *sb,
120  					struct bch_sb_field *f)
121  {
122  	struct bch_sb_field_disk_groups *groups =
123  		field_to_type(f, disk_groups);
124  	struct bch_disk_group *g;
125  	unsigned nr_groups = disk_groups_nr(groups);
126  
127  	for (g = groups->entries;
128  	     g < groups->entries + nr_groups;
129  	     g++) {
130  		if (g != groups->entries)
131  			prt_printf(out, " ");
132  
133  		if (BCH_GROUP_DELETED(g))
134  			prt_printf(out, "[deleted]");
135  		else
136  			prt_printf(out, "[parent %llu name %s]",
137  			       BCH_GROUP_PARENT(g), g->label);
138  	}
139  }
140  
141  const struct bch_sb_field_ops bch_sb_field_ops_disk_groups = {
142  	.validate	= bch2_sb_disk_groups_validate,
143  	.to_text	= bch2_sb_disk_groups_to_text
144  };
145  
bch2_sb_disk_groups_to_cpu(struct bch_fs * c)146  int bch2_sb_disk_groups_to_cpu(struct bch_fs *c)
147  {
148  	struct bch_sb_field_disk_groups *groups;
149  	struct bch_disk_groups_cpu *cpu_g, *old_g;
150  	unsigned i, g, nr_groups;
151  
152  	lockdep_assert_held(&c->sb_lock);
153  
154  	groups		= bch2_sb_field_get(c->disk_sb.sb, disk_groups);
155  	nr_groups	= disk_groups_nr(groups);
156  
157  	if (!groups)
158  		return 0;
159  
160  	cpu_g = kzalloc(struct_size(cpu_g, entries, nr_groups), GFP_KERNEL);
161  	if (!cpu_g)
162  		return -BCH_ERR_ENOMEM_disk_groups_to_cpu;
163  
164  	cpu_g->nr = nr_groups;
165  
166  	for (i = 0; i < nr_groups; i++) {
167  		struct bch_disk_group *src	= &groups->entries[i];
168  		struct bch_disk_group_cpu *dst	= &cpu_g->entries[i];
169  
170  		dst->deleted	= BCH_GROUP_DELETED(src);
171  		dst->parent	= BCH_GROUP_PARENT(src);
172  		memcpy(dst->label, src->label, sizeof(dst->label));
173  	}
174  
175  	for (i = 0; i < c->disk_sb.sb->nr_devices; i++) {
176  		struct bch_member m = bch2_sb_member_get(c->disk_sb.sb, i);
177  		struct bch_disk_group_cpu *dst;
178  
179  		if (!bch2_member_alive(&m))
180  			continue;
181  
182  		g = BCH_MEMBER_GROUP(&m);
183  		while (g) {
184  			dst = &cpu_g->entries[g - 1];
185  			__set_bit(i, dst->devs.d);
186  			g = dst->parent;
187  		}
188  	}
189  
190  	old_g = rcu_dereference_protected(c->disk_groups,
191  				lockdep_is_held(&c->sb_lock));
192  	rcu_assign_pointer(c->disk_groups, cpu_g);
193  	if (old_g)
194  		kfree_rcu(old_g, rcu);
195  
196  	return 0;
197  }
198  
bch2_target_to_mask(struct bch_fs * c,unsigned target)199  const struct bch_devs_mask *bch2_target_to_mask(struct bch_fs *c, unsigned target)
200  {
201  	struct target t = target_decode(target);
202  	struct bch_devs_mask *devs;
203  
204  	rcu_read_lock();
205  
206  	switch (t.type) {
207  	case TARGET_NULL:
208  		devs = NULL;
209  		break;
210  	case TARGET_DEV: {
211  		struct bch_dev *ca = t.dev < c->sb.nr_devices
212  			? rcu_dereference(c->devs[t.dev])
213  			: NULL;
214  		devs = ca ? &ca->self : NULL;
215  		break;
216  	}
217  	case TARGET_GROUP: {
218  		struct bch_disk_groups_cpu *g = rcu_dereference(c->disk_groups);
219  
220  		devs = g && t.group < g->nr && !g->entries[t.group].deleted
221  			? &g->entries[t.group].devs
222  			: NULL;
223  		break;
224  	}
225  	default:
226  		BUG();
227  	}
228  
229  	rcu_read_unlock();
230  
231  	return devs;
232  }
233  
bch2_dev_in_target(struct bch_fs * c,unsigned dev,unsigned target)234  bool bch2_dev_in_target(struct bch_fs *c, unsigned dev, unsigned target)
235  {
236  	struct target t = target_decode(target);
237  
238  	switch (t.type) {
239  	case TARGET_NULL:
240  		return false;
241  	case TARGET_DEV:
242  		return dev == t.dev;
243  	case TARGET_GROUP: {
244  		struct bch_disk_groups_cpu *g;
245  		const struct bch_devs_mask *m;
246  		bool ret;
247  
248  		rcu_read_lock();
249  		g = rcu_dereference(c->disk_groups);
250  		m = g && t.group < g->nr && !g->entries[t.group].deleted
251  			? &g->entries[t.group].devs
252  			: NULL;
253  
254  		ret = m ? test_bit(dev, m->d) : false;
255  		rcu_read_unlock();
256  
257  		return ret;
258  	}
259  	default:
260  		BUG();
261  	}
262  }
263  
__bch2_disk_group_find(struct bch_sb_field_disk_groups * groups,unsigned parent,const char * name,unsigned namelen)264  static int __bch2_disk_group_find(struct bch_sb_field_disk_groups *groups,
265  				  unsigned parent,
266  				  const char *name, unsigned namelen)
267  {
268  	unsigned i, nr_groups = disk_groups_nr(groups);
269  
270  	if (!namelen || namelen > BCH_SB_LABEL_SIZE)
271  		return -EINVAL;
272  
273  	for (i = 0; i < nr_groups; i++) {
274  		struct bch_disk_group *g = groups->entries + i;
275  
276  		if (BCH_GROUP_DELETED(g))
277  			continue;
278  
279  		if (!BCH_GROUP_DELETED(g) &&
280  		    BCH_GROUP_PARENT(g) == parent &&
281  		    strnlen(g->label, sizeof(g->label)) == namelen &&
282  		    !memcmp(name, g->label, namelen))
283  			return i;
284  	}
285  
286  	return -1;
287  }
288  
__bch2_disk_group_add(struct bch_sb_handle * sb,unsigned parent,const char * name,unsigned namelen)289  static int __bch2_disk_group_add(struct bch_sb_handle *sb, unsigned parent,
290  				 const char *name, unsigned namelen)
291  {
292  	struct bch_sb_field_disk_groups *groups =
293  		bch2_sb_field_get(sb->sb, disk_groups);
294  	unsigned i, nr_groups = disk_groups_nr(groups);
295  	struct bch_disk_group *g;
296  
297  	if (!namelen || namelen > BCH_SB_LABEL_SIZE)
298  		return -EINVAL;
299  
300  	for (i = 0;
301  	     i < nr_groups && !BCH_GROUP_DELETED(&groups->entries[i]);
302  	     i++)
303  		;
304  
305  	if (i == nr_groups) {
306  		unsigned u64s =
307  			(sizeof(struct bch_sb_field_disk_groups) +
308  			 sizeof(struct bch_disk_group) * (nr_groups + 1)) /
309  			sizeof(u64);
310  
311  		groups = bch2_sb_field_resize(sb, disk_groups, u64s);
312  		if (!groups)
313  			return -BCH_ERR_ENOSPC_disk_label_add;
314  
315  		nr_groups = disk_groups_nr(groups);
316  	}
317  
318  	BUG_ON(i >= nr_groups);
319  
320  	g = &groups->entries[i];
321  
322  	memcpy(g->label, name, namelen);
323  	if (namelen < sizeof(g->label))
324  		g->label[namelen] = '\0';
325  	SET_BCH_GROUP_DELETED(g, 0);
326  	SET_BCH_GROUP_PARENT(g, parent);
327  	SET_BCH_GROUP_DATA_ALLOWED(g, ~0);
328  
329  	return i;
330  }
331  
bch2_disk_path_find(struct bch_sb_handle * sb,const char * name)332  int bch2_disk_path_find(struct bch_sb_handle *sb, const char *name)
333  {
334  	struct bch_sb_field_disk_groups *groups =
335  		bch2_sb_field_get(sb->sb, disk_groups);
336  	int v = -1;
337  
338  	do {
339  		const char *next = strchrnul(name, '.');
340  		unsigned len = next - name;
341  
342  		if (*next == '.')
343  			next++;
344  
345  		v = __bch2_disk_group_find(groups, v + 1, name, len);
346  		name = next;
347  	} while (*name && v >= 0);
348  
349  	return v;
350  }
351  
bch2_disk_path_find_or_create(struct bch_sb_handle * sb,const char * name)352  int bch2_disk_path_find_or_create(struct bch_sb_handle *sb, const char *name)
353  {
354  	struct bch_sb_field_disk_groups *groups;
355  	unsigned parent = 0;
356  	int v = -1;
357  
358  	do {
359  		const char *next = strchrnul(name, '.');
360  		unsigned len = next - name;
361  
362  		if (*next == '.')
363  			next++;
364  
365  		groups = bch2_sb_field_get(sb->sb, disk_groups);
366  
367  		v = __bch2_disk_group_find(groups, parent, name, len);
368  		if (v < 0)
369  			v = __bch2_disk_group_add(sb, parent, name, len);
370  		if (v < 0)
371  			return v;
372  
373  		parent = v + 1;
374  		name = next;
375  	} while (*name && v >= 0);
376  
377  	return v;
378  }
379  
bch2_disk_path_to_text(struct printbuf * out,struct bch_fs * c,unsigned v)380  void bch2_disk_path_to_text(struct printbuf *out, struct bch_fs *c, unsigned v)
381  {
382  	struct bch_disk_groups_cpu *groups;
383  	struct bch_disk_group_cpu *g;
384  	unsigned nr = 0;
385  	u16 path[32];
386  
387  	out->atomic++;
388  	rcu_read_lock();
389  	groups = rcu_dereference(c->disk_groups);
390  	if (!groups)
391  		goto invalid;
392  
393  	while (1) {
394  		if (nr == ARRAY_SIZE(path))
395  			goto invalid;
396  
397  		if (v >= groups->nr)
398  			goto invalid;
399  
400  		g = groups->entries + v;
401  
402  		if (g->deleted)
403  			goto invalid;
404  
405  		path[nr++] = v;
406  
407  		if (!g->parent)
408  			break;
409  
410  		v = g->parent - 1;
411  	}
412  
413  	while (nr) {
414  		v = path[--nr];
415  		g = groups->entries + v;
416  
417  		prt_printf(out, "%.*s", (int) sizeof(g->label), g->label);
418  		if (nr)
419  			prt_printf(out, ".");
420  	}
421  out:
422  	rcu_read_unlock();
423  	out->atomic--;
424  	return;
425  invalid:
426  	prt_printf(out, "invalid label %u", v);
427  	goto out;
428  }
429  
bch2_disk_path_to_text_sb(struct printbuf * out,struct bch_sb * sb,unsigned v)430  void bch2_disk_path_to_text_sb(struct printbuf *out, struct bch_sb *sb, unsigned v)
431  {
432  	struct bch_sb_field_disk_groups *groups =
433  		bch2_sb_field_get(sb, disk_groups);
434  	struct bch_disk_group *g;
435  	unsigned nr = 0;
436  	u16 path[32];
437  
438  	while (1) {
439  		if (nr == ARRAY_SIZE(path))
440  			goto inval;
441  
442  		if (v >= disk_groups_nr(groups))
443  			goto inval;
444  
445  		g = groups->entries + v;
446  
447  		if (BCH_GROUP_DELETED(g))
448  			goto inval;
449  
450  		path[nr++] = v;
451  
452  		if (!BCH_GROUP_PARENT(g))
453  			break;
454  
455  		v = BCH_GROUP_PARENT(g) - 1;
456  	}
457  
458  	while (nr) {
459  		v = path[--nr];
460  		g = groups->entries + v;
461  
462  		prt_printf(out, "%.*s", (int) sizeof(g->label), g->label);
463  		if (nr)
464  			prt_printf(out, ".");
465  	}
466  	return;
467  inval:
468  	prt_printf(out, "invalid label %u", v);
469  }
470  
__bch2_dev_group_set(struct bch_fs * c,struct bch_dev * ca,const char * name)471  int __bch2_dev_group_set(struct bch_fs *c, struct bch_dev *ca, const char *name)
472  {
473  	struct bch_member *mi;
474  	int ret, v = -1;
475  
476  	if (!strlen(name) || !strcmp(name, "none"))
477  		return 0;
478  
479  	v = bch2_disk_path_find_or_create(&c->disk_sb, name);
480  	if (v < 0)
481  		return v;
482  
483  	ret = bch2_sb_disk_groups_to_cpu(c);
484  	if (ret)
485  		return ret;
486  
487  	mi = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
488  	SET_BCH_MEMBER_GROUP(mi, v + 1);
489  	return 0;
490  }
491  
bch2_dev_group_set(struct bch_fs * c,struct bch_dev * ca,const char * name)492  int bch2_dev_group_set(struct bch_fs *c, struct bch_dev *ca, const char *name)
493  {
494  	int ret;
495  
496  	mutex_lock(&c->sb_lock);
497  	ret = __bch2_dev_group_set(c, ca, name) ?:
498  		bch2_write_super(c);
499  	mutex_unlock(&c->sb_lock);
500  
501  	return ret;
502  }
503  
bch2_opt_target_parse(struct bch_fs * c,const char * val,u64 * res,struct printbuf * err)504  int bch2_opt_target_parse(struct bch_fs *c, const char *val, u64 *res,
505  			  struct printbuf *err)
506  {
507  	struct bch_dev *ca;
508  	int g;
509  
510  	if (!val)
511  		return -EINVAL;
512  
513  	if (!c)
514  		return -BCH_ERR_option_needs_open_fs;
515  
516  	if (!strlen(val) || !strcmp(val, "none")) {
517  		*res = 0;
518  		return 0;
519  	}
520  
521  	/* Is it a device? */
522  	ca = bch2_dev_lookup(c, val);
523  	if (!IS_ERR(ca)) {
524  		*res = dev_to_target(ca->dev_idx);
525  		bch2_dev_put(ca);
526  		return 0;
527  	}
528  
529  	mutex_lock(&c->sb_lock);
530  	g = bch2_disk_path_find(&c->disk_sb, val);
531  	mutex_unlock(&c->sb_lock);
532  
533  	if (g >= 0) {
534  		*res = group_to_target(g);
535  		return 0;
536  	}
537  
538  	return -EINVAL;
539  }
540  
bch2_target_to_text(struct printbuf * out,struct bch_fs * c,unsigned v)541  void bch2_target_to_text(struct printbuf *out, struct bch_fs *c, unsigned v)
542  {
543  	struct target t = target_decode(v);
544  
545  	switch (t.type) {
546  	case TARGET_NULL:
547  		prt_printf(out, "none");
548  		break;
549  	case TARGET_DEV: {
550  		struct bch_dev *ca;
551  
552  		out->atomic++;
553  		rcu_read_lock();
554  		ca = t.dev < c->sb.nr_devices
555  			? rcu_dereference(c->devs[t.dev])
556  			: NULL;
557  
558  		if (ca && percpu_ref_tryget(&ca->io_ref)) {
559  			prt_printf(out, "/dev/%s", ca->name);
560  			percpu_ref_put(&ca->io_ref);
561  		} else if (ca) {
562  			prt_printf(out, "offline device %u", t.dev);
563  		} else {
564  			prt_printf(out, "invalid device %u", t.dev);
565  		}
566  
567  		rcu_read_unlock();
568  		out->atomic--;
569  		break;
570  	}
571  	case TARGET_GROUP:
572  		bch2_disk_path_to_text(out, c, t.group);
573  		break;
574  	default:
575  		BUG();
576  	}
577  }
578  
bch2_target_to_text_sb(struct printbuf * out,struct bch_sb * sb,unsigned v)579  static void bch2_target_to_text_sb(struct printbuf *out, struct bch_sb *sb, unsigned v)
580  {
581  	struct target t = target_decode(v);
582  
583  	switch (t.type) {
584  	case TARGET_NULL:
585  		prt_printf(out, "none");
586  		break;
587  	case TARGET_DEV: {
588  		struct bch_member m = bch2_sb_member_get(sb, t.dev);
589  
590  		if (bch2_member_exists(sb, t.dev)) {
591  			prt_printf(out, "Device ");
592  			pr_uuid(out, m.uuid.b);
593  			prt_printf(out, " (%u)", t.dev);
594  		} else {
595  			prt_printf(out, "Bad device %u", t.dev);
596  		}
597  		break;
598  	}
599  	case TARGET_GROUP:
600  		bch2_disk_path_to_text_sb(out, sb, t.group);
601  		break;
602  	default:
603  		BUG();
604  	}
605  }
606  
bch2_opt_target_to_text(struct printbuf * out,struct bch_fs * c,struct bch_sb * sb,u64 v)607  void bch2_opt_target_to_text(struct printbuf *out,
608  			     struct bch_fs *c,
609  			     struct bch_sb *sb,
610  			     u64 v)
611  {
612  	if (c)
613  		bch2_target_to_text(out, c, v);
614  	else
615  		bch2_target_to_text_sb(out, sb, v);
616  }
617