]>
Commit | Line | Data |
---|---|---|
fb8e5b4c KO |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | ||
3 | #include "bcachefs.h" | |
4 | #include "disk_groups.h" | |
5 | #include "replicas.h" | |
6 | #include "sb-members.h" | |
7 | #include "super-io.h" | |
8 | ||
9 | /* Code for bch_sb_field_members: */ | |
10 | ||
11 | static int bch2_sb_members_validate(struct bch_sb *sb, | |
12 | struct bch_sb_field *f, | |
13 | struct printbuf *err) | |
14 | { | |
15 | struct bch_sb_field_members *mi = field_to_type(f, members); | |
16 | unsigned i; | |
17 | ||
18 | if ((void *) (mi->members + sb->nr_devices) > | |
19 | vstruct_end(&mi->field)) { | |
20 | prt_printf(err, "too many devices for section size"); | |
21 | return -BCH_ERR_invalid_sb_members; | |
22 | } | |
23 | ||
24 | for (i = 0; i < sb->nr_devices; i++) { | |
25 | struct bch_member *m = mi->members + i; | |
26 | ||
27 | if (!bch2_member_exists(m)) | |
28 | continue; | |
29 | ||
30 | if (le64_to_cpu(m->nbuckets) > LONG_MAX) { | |
31 | prt_printf(err, "device %u: too many buckets (got %llu, max %lu)", | |
32 | i, le64_to_cpu(m->nbuckets), LONG_MAX); | |
33 | return -BCH_ERR_invalid_sb_members; | |
34 | } | |
35 | ||
36 | if (le64_to_cpu(m->nbuckets) - | |
37 | le16_to_cpu(m->first_bucket) < BCH_MIN_NR_NBUCKETS) { | |
38 | prt_printf(err, "device %u: not enough buckets (got %llu, max %u)", | |
39 | i, le64_to_cpu(m->nbuckets), BCH_MIN_NR_NBUCKETS); | |
40 | return -BCH_ERR_invalid_sb_members; | |
41 | } | |
42 | ||
43 | if (le16_to_cpu(m->bucket_size) < | |
44 | le16_to_cpu(sb->block_size)) { | |
45 | prt_printf(err, "device %u: bucket size %u smaller than block size %u", | |
46 | i, le16_to_cpu(m->bucket_size), le16_to_cpu(sb->block_size)); | |
47 | return -BCH_ERR_invalid_sb_members; | |
48 | } | |
49 | ||
50 | if (le16_to_cpu(m->bucket_size) < | |
51 | BCH_SB_BTREE_NODE_SIZE(sb)) { | |
52 | prt_printf(err, "device %u: bucket size %u smaller than btree node size %llu", | |
53 | i, le16_to_cpu(m->bucket_size), BCH_SB_BTREE_NODE_SIZE(sb)); | |
54 | return -BCH_ERR_invalid_sb_members; | |
55 | } | |
56 | } | |
57 | ||
58 | return 0; | |
59 | } | |
60 | ||
61 | static void bch2_sb_members_to_text(struct printbuf *out, struct bch_sb *sb, | |
62 | struct bch_sb_field *f) | |
63 | { | |
64 | struct bch_sb_field_members *mi = field_to_type(f, members); | |
65 | struct bch_sb_field_disk_groups *gi = bch2_sb_get_disk_groups(sb); | |
66 | unsigned i; | |
67 | ||
68 | for (i = 0; i < sb->nr_devices; i++) { | |
69 | struct bch_member *m = mi->members + i; | |
70 | unsigned data_have = bch2_sb_dev_has_data(sb, i); | |
71 | u64 bucket_size = le16_to_cpu(m->bucket_size); | |
72 | u64 device_size = le64_to_cpu(m->nbuckets) * bucket_size; | |
73 | ||
74 | if (!bch2_member_exists(m)) | |
75 | continue; | |
76 | ||
77 | prt_printf(out, "Device:"); | |
78 | prt_tab(out); | |
79 | prt_printf(out, "%u", i); | |
80 | prt_newline(out); | |
81 | ||
82 | printbuf_indent_add(out, 2); | |
83 | ||
84 | prt_printf(out, "UUID:"); | |
85 | prt_tab(out); | |
86 | pr_uuid(out, m->uuid.b); | |
87 | prt_newline(out); | |
88 | ||
89 | prt_printf(out, "Size:"); | |
90 | prt_tab(out); | |
91 | prt_units_u64(out, device_size << 9); | |
92 | prt_newline(out); | |
93 | ||
94 | prt_printf(out, "Bucket size:"); | |
95 | prt_tab(out); | |
96 | prt_units_u64(out, bucket_size << 9); | |
97 | prt_newline(out); | |
98 | ||
99 | prt_printf(out, "First bucket:"); | |
100 | prt_tab(out); | |
101 | prt_printf(out, "%u", le16_to_cpu(m->first_bucket)); | |
102 | prt_newline(out); | |
103 | ||
104 | prt_printf(out, "Buckets:"); | |
105 | prt_tab(out); | |
106 | prt_printf(out, "%llu", le64_to_cpu(m->nbuckets)); | |
107 | prt_newline(out); | |
108 | ||
109 | prt_printf(out, "Last mount:"); | |
110 | prt_tab(out); | |
111 | if (m->last_mount) | |
112 | pr_time(out, le64_to_cpu(m->last_mount)); | |
113 | else | |
114 | prt_printf(out, "(never)"); | |
115 | prt_newline(out); | |
116 | ||
117 | prt_printf(out, "State:"); | |
118 | prt_tab(out); | |
119 | prt_printf(out, "%s", | |
120 | BCH_MEMBER_STATE(m) < BCH_MEMBER_STATE_NR | |
121 | ? bch2_member_states[BCH_MEMBER_STATE(m)] | |
122 | : "unknown"); | |
123 | prt_newline(out); | |
124 | ||
125 | prt_printf(out, "Label:"); | |
126 | prt_tab(out); | |
127 | if (BCH_MEMBER_GROUP(m)) { | |
128 | unsigned idx = BCH_MEMBER_GROUP(m) - 1; | |
129 | ||
130 | if (idx < disk_groups_nr(gi)) | |
131 | prt_printf(out, "%s (%u)", | |
132 | gi->entries[idx].label, idx); | |
133 | else | |
134 | prt_printf(out, "(bad disk labels section)"); | |
135 | } else { | |
136 | prt_printf(out, "(none)"); | |
137 | } | |
138 | prt_newline(out); | |
139 | ||
140 | prt_printf(out, "Data allowed:"); | |
141 | prt_tab(out); | |
142 | if (BCH_MEMBER_DATA_ALLOWED(m)) | |
143 | prt_bitflags(out, bch2_data_types, BCH_MEMBER_DATA_ALLOWED(m)); | |
144 | else | |
145 | prt_printf(out, "(none)"); | |
146 | prt_newline(out); | |
147 | ||
148 | prt_printf(out, "Has data:"); | |
149 | prt_tab(out); | |
150 | if (data_have) | |
151 | prt_bitflags(out, bch2_data_types, data_have); | |
152 | else | |
153 | prt_printf(out, "(none)"); | |
154 | prt_newline(out); | |
155 | ||
156 | prt_printf(out, "Discard:"); | |
157 | prt_tab(out); | |
158 | prt_printf(out, "%llu", BCH_MEMBER_DISCARD(m)); | |
159 | prt_newline(out); | |
160 | ||
161 | prt_printf(out, "Freespace initialized:"); | |
162 | prt_tab(out); | |
163 | prt_printf(out, "%llu", BCH_MEMBER_FREESPACE_INITIALIZED(m)); | |
164 | prt_newline(out); | |
165 | ||
166 | printbuf_indent_sub(out, 2); | |
167 | } | |
168 | } | |
169 | ||
170 | const struct bch_sb_field_ops bch_sb_field_ops_members = { | |
171 | .validate = bch2_sb_members_validate, | |
172 | .to_text = bch2_sb_members_to_text, | |
173 | }; |