]> git.sesse.net Git - bcachefs-tools-debian/blob - cmd_fs.c
Upload to unstable
[bcachefs-tools-debian] / cmd_fs.c
1 #include <getopt.h>
2 #include <stdio.h>
3 #include <sys/ioctl.h>
4
5 #include <uuid/uuid.h>
6
7 #include "linux/sort.h"
8
9 #include "libbcachefs/bcachefs_ioctl.h"
10 #include "libbcachefs/darray.h"
11 #include "libbcachefs/opts.h"
12
13 #include "cmds.h"
14 #include "libbcachefs.h"
15
16 static void __dev_usage_type_to_text(struct printbuf *out,
17                                      const char *type,
18                                      unsigned bucket_size,
19                                      u64 buckets, u64 sectors, u64 frag)
20 {
21         prt_printf(out, "%s:", type);
22         prt_tab(out);
23
24         prt_units_u64(out, sectors << 9);
25         prt_tab_rjust(out);
26
27         prt_printf(out, "%llu", buckets);
28         prt_tab_rjust(out);
29
30         if (frag) {
31                 prt_units_u64(out, frag << 9);
32                 prt_tab_rjust(out);
33         }
34         prt_newline(out);
35 }
36
37 static void dev_usage_type_to_text(struct printbuf *out,
38                                    struct bch_ioctl_dev_usage *u,
39                                    enum bch_data_type type)
40 {
41         __dev_usage_type_to_text(out, bch2_data_types[type],
42                         u->bucket_size,
43                         u->d[type].buckets,
44                         u->d[type].sectors,
45                         u->d[type].fragmented);
46 }
47
48 static void dev_usage_to_text(struct printbuf *out,
49                               struct bchfs_handle fs,
50                               struct dev_name *d)
51 {
52         struct bch_ioctl_dev_usage u = bchu_dev_usage(fs, d->idx);
53         unsigned i;
54
55         prt_newline(out);
56         prt_printf(out, "%s (device %u):", d->label ?: "(no label)", d->idx);
57         prt_tab(out);
58         prt_str(out, d->dev ?: "(device not found)");
59         prt_tab_rjust(out);
60
61         prt_str(out, bch2_member_states[u.state]);
62         prt_tab_rjust(out);
63
64         prt_newline(out);
65
66         printbuf_indent_add(out, 2);
67         prt_tab(out);
68
69         prt_str(out, "data");
70         prt_tab_rjust(out);
71
72         prt_str(out, "buckets");
73         prt_tab_rjust(out);
74
75         prt_str(out, "fragmented");
76         prt_tab_rjust(out);
77
78         prt_newline(out);
79
80         for (i = 0; i < BCH_DATA_NR; i++)
81                 dev_usage_type_to_text(out, &u, i);
82         __dev_usage_type_to_text(out, "erasure coded",
83                                  u.bucket_size,
84                                  u.buckets_ec, u.buckets_ec * u.bucket_size, 0);
85
86         prt_str(out, "capacity:");
87         prt_tab(out);
88
89         prt_units_u64(out, (u.nr_buckets * u.bucket_size) << 9);
90         prt_tab_rjust(out);
91         prt_printf(out, "%llu", u.nr_buckets);
92         prt_tab_rjust(out);
93
94         printbuf_indent_sub(out, 2);
95
96         prt_newline(out);
97 }
98
99 static int dev_by_label_cmp(const void *_l, const void *_r)
100 {
101         const struct dev_name *l = _l, *r = _r;
102
103         return  (l->label && r->label
104                  ? strcmp(l->label, r->label) : 0) ?:
105                 (l->dev && r->dev
106                  ? strcmp(l->dev, r->dev) : 0) ?:
107                 cmp_int(l->idx, r->idx);
108 }
109
110 static struct dev_name *dev_idx_to_name(dev_names *dev_names, unsigned idx)
111 {
112         struct dev_name *dev;
113
114         darray_for_each(*dev_names, dev)
115                 if (dev->idx == idx)
116                         return dev;
117
118         return NULL;
119 }
120
121 static void replicas_usage_to_text(struct printbuf *out,
122                                    const struct bch_replicas_usage *r,
123                                    dev_names *dev_names)
124 {
125         unsigned i;
126
127         if (!r->sectors)
128                 return;
129
130         char devs[4096], *d = devs;
131         *d++ = '[';
132
133         for (i = 0; i < r->r.nr_devs; i++) {
134                 unsigned dev_idx = r->r.devs[i];
135                 struct dev_name *dev = dev_idx_to_name(dev_names, dev_idx);
136
137                 if (i)
138                         *d++ = ' ';
139
140                 d += dev && dev->dev
141                         ? sprintf(d, "%s", dev->dev)
142                         : sprintf(d, "%u", dev_idx);
143         }
144         *d++ = ']';
145         *d++ = '\0';
146
147         prt_printf(out, "%s: ", bch2_data_types[r->r.data_type]);
148         prt_tab(out);
149
150         prt_printf(out, "%u/%u ", r->r.nr_required, r->r.nr_devs);
151         prt_tab(out);
152
153         prt_printf(out, "%s ", devs);
154         prt_tab(out);
155
156         prt_units_u64(out, r->sectors << 9);
157         prt_tab_rjust(out);
158         prt_newline(out);
159 }
160
161 #define for_each_usage_replica(_u, _r)                                  \
162         for (_r = (_u)->replicas;                                       \
163              _r != (void *) (_u)->replicas + (_u)->replica_entries_bytes;\
164              _r = replicas_usage_next(_r),                              \
165              BUG_ON((void *) _r > (void *) (_u)->replicas + (_u)->replica_entries_bytes))
166
167 static void fs_usage_to_text(struct printbuf *out, const char *path)
168 {
169         unsigned i;
170
171         struct bchfs_handle fs = bcache_fs_open(path);
172
173         struct dev_name *dev;
174         dev_names dev_names = bchu_fs_get_devices(fs);
175
176         struct bch_ioctl_fs_usage *u = bchu_fs_usage(fs);
177
178         prt_str(out, "Filesystem: ");
179         pr_uuid(out, fs.uuid.b);
180         prt_newline(out);
181
182         printbuf_tabstops_reset(out);
183         printbuf_tabstop_push(out, 20);
184         printbuf_tabstop_push(out, 16);
185
186         prt_str(out, "Size:");
187         prt_tab(out);
188         prt_units_u64(out, u->capacity << 9);
189         prt_tab_rjust(out);
190         prt_newline(out);
191
192         prt_str(out, "Used:");
193         prt_tab(out);
194         prt_units_u64(out, u->used << 9);
195         prt_tab_rjust(out);
196         prt_newline(out);
197
198         prt_str(out, "Online reserved:");
199         prt_tab(out);
200         prt_units_u64(out, u->online_reserved << 9);
201         prt_tab_rjust(out);
202         prt_newline(out);
203
204         prt_newline(out);
205
206         printbuf_tabstops_reset(out);
207         printbuf_tabstop_push(out, 16);
208         printbuf_tabstop_push(out, 16);
209         printbuf_tabstop_push(out, 18);
210         printbuf_tabstop_push(out, 18);
211
212         prt_str(out, "Data type");
213         prt_tab(out);
214
215         prt_str(out, "Required/total");
216         prt_tab(out);
217
218         prt_str(out, "Devices");
219         prt_newline(out);
220
221         for (i = 0; i < BCH_REPLICAS_MAX; i++) {
222                 if (!u->persistent_reserved[i])
223                         continue;
224
225                 prt_str(out, "reserved:");
226                 prt_tab(out);
227                 prt_printf(out, "%u/%u ", 1, i);
228                 prt_tab(out);
229                 prt_str(out, "[] ");
230                 prt_units_u64(out, u->persistent_reserved[i] << 9);
231                 prt_tab_rjust(out);
232                 prt_newline(out);
233         }
234
235         struct bch_replicas_usage *r;
236
237         for_each_usage_replica(u, r)
238                 if (r->r.data_type < BCH_DATA_user)
239                         replicas_usage_to_text(out, r, &dev_names);
240
241         for_each_usage_replica(u, r)
242                 if (r->r.data_type == BCH_DATA_user &&
243                     r->r.nr_required <= 1)
244                         replicas_usage_to_text(out, r, &dev_names);
245
246         for_each_usage_replica(u, r)
247                 if (r->r.data_type == BCH_DATA_user &&
248                     r->r.nr_required > 1)
249                         replicas_usage_to_text(out, r, &dev_names);
250
251         for_each_usage_replica(u, r)
252                 if (r->r.data_type > BCH_DATA_user)
253                         replicas_usage_to_text(out, r, &dev_names);
254
255         free(u);
256
257         sort(dev_names.data, dev_names.nr,
258              sizeof(dev_names.data[0]), dev_by_label_cmp, NULL);
259
260         printbuf_tabstops_reset(out);
261         printbuf_tabstop_push(out, 16);
262         printbuf_tabstop_push(out, 20);
263         printbuf_tabstop_push(out, 16);
264         printbuf_tabstop_push(out, 14);
265
266         darray_for_each(dev_names, dev)
267                 dev_usage_to_text(out, fs, dev);
268
269         darray_for_each(dev_names, dev) {
270                 free(dev->dev);
271                 free(dev->label);
272         }
273         darray_exit(&dev_names);
274
275         bcache_fs_close(fs);
276 }
277
278 static void fs_usage_usage(void)
279 {
280         puts("bcachefs fs usage - display detailed filesystem usage\n"
281              "Usage: bcachefs fs usage [OPTION]... <mountpoint>\n"
282              "\n"
283              "Options:\n"
284              "  -h, --human-readable              Human readable units\n"
285              "      --help                        Display this help and exit\n"
286              "Report bugs to <linux-bcachefs@vger.kernel.org>");
287 }
288
289 int cmd_fs_usage(int argc, char *argv[])
290 {
291         static const struct option longopts[] = {
292                 { "help",               no_argument,            NULL, 'H' },
293                 { NULL }
294         };
295         bool human_readable = false;
296         struct printbuf buf = PRINTBUF;
297         char *fs;
298         int opt;
299
300         while ((opt = getopt_long(argc, argv, "h",
301                                   longopts, NULL)) != -1)
302                 switch (opt) {
303                 case 'h':
304                         human_readable = true;
305                         break;
306                 case 'H':
307                         fs_usage_usage();
308                         exit(EXIT_SUCCESS);
309                 default:
310                         fs_usage_usage();
311                         exit(EXIT_FAILURE);
312                 }
313         args_shift(optind);
314
315         if (!argc) {
316                 printbuf_reset(&buf);
317                 buf.human_readable_units = human_readable;
318                 fs_usage_to_text(&buf, ".");
319                 printf("%s", buf.buf);
320         } else {
321                 while ((fs = arg_pop())) {
322                         printbuf_reset(&buf);
323                         buf.human_readable_units = human_readable;
324                         fs_usage_to_text(&buf, fs);
325                         printf("%s", buf.buf);
326                 }
327         }
328
329         printbuf_exit(&buf);
330         return 0;
331 }