]> git.sesse.net Git - bcachefs-tools-debian/blob - cmd_fs.c
f0b67b668ec982c1d21b5e7e79c3757163050947
[bcachefs-tools-debian] / cmd_fs.c
1
2 #include <stdio.h>
3 #include <sys/ioctl.h>
4
5 #include <uuid/uuid.h>
6
7 #include "ccan/darray/darray.h"
8
9 #include "linux/sort.h"
10
11 #include "libbcachefs/bcachefs_ioctl.h"
12 #include "libbcachefs/opts.h"
13
14 #include "cmds.h"
15 #include "libbcachefs.h"
16
17 static void print_dev_usage_type(const char *type,
18                                  unsigned bucket_size,
19                                  u64 buckets, u64 sectors,
20                                  enum units units)
21 {
22         u64 frag = max((s64) buckets * bucket_size - (s64) sectors, 0LL);
23
24         printf_pad(20, "  %s:", type);
25         printf("%12s%12llu%12s\n",
26                pr_units(sectors, units),
27                buckets,
28                pr_units(frag, units));
29 }
30
31 static void print_dev_usage(struct bchfs_handle fs,
32                             struct dev_name *d,
33                             enum units units)
34 {
35         struct bch_ioctl_dev_usage u = bchu_dev_usage(fs, d->idx);
36         unsigned i;
37
38         printf("\n");
39         printf_pad(20, "%s (device %u):", d->label ?: "(no label)", d->idx);
40         printf("%24s%12s\n", d->dev ?: "(device not found)", bch2_dev_state[u.state]);
41
42         printf("%-20s%12s%12s%12s\n",
43                "", "data", "buckets", "fragmented");
44
45         for (i = BCH_DATA_sb; i < BCH_DATA_NR; i++) {
46                 print_dev_usage_type(bch2_data_types[i],
47                                      u.bucket_size,
48                                      u.buckets[i],
49                                      u.sectors[i],
50                                      units);
51         }
52
53         print_dev_usage_type("erasure coded",
54                              u.bucket_size,
55                              u.ec_buckets,
56                              u.ec_sectors,
57                              units);
58
59         printf_pad(20, "  available:");
60         printf("%12s%12llu\n",
61                pr_units(u.available_buckets * u.bucket_size, units),
62                u.available_buckets);
63
64         printf_pad(20, "  capacity:");
65         printf("%12s%12llu\n",
66                pr_units(u.nr_buckets * u.bucket_size, units),
67                u.nr_buckets);
68 }
69
70 static int dev_by_label_cmp(const void *_l, const void *_r)
71 {
72         const struct dev_name *l = _l, *r = _r;
73
74         return  (l->label && r->label
75                  ? strcmp(l->label, r->label) : 0) ?:
76                 (l->dev && r->dev
77                  ? strcmp(l->dev, r->dev) : 0) ?:
78                 cmp_int(l->idx, r->idx);
79 }
80
81 static struct dev_name *dev_idx_to_name(dev_names *dev_names, unsigned idx)
82 {
83         struct dev_name *dev;
84
85         darray_foreach(dev, *dev_names)
86                 if (dev->idx == idx)
87                         return dev;
88
89         return NULL;
90 }
91
92 static void print_replicas_usage(const struct bch_replicas_usage *r,
93                                  dev_names *dev_names, enum units units)
94 {
95         unsigned i;
96
97         if (!r->sectors)
98                 return;
99
100         char devs[4096], *d = devs;
101         *d++ = '[';
102
103         for (i = 0; i < r->r.nr_devs; i++) {
104                 unsigned dev_idx = r->r.devs[i];
105                 struct dev_name *dev = dev_idx_to_name(dev_names, dev_idx);
106
107                 if (i)
108                         *d++ = ' ';
109
110                 d += dev && dev->dev
111                         ? sprintf(d, "%s", dev->dev)
112                         : sprintf(d, "%u", dev_idx);
113         }
114         *d++ = ']';
115         *d++ = '\0';
116
117         printf_pad(16, "%s: ", bch2_data_types[r->r.data_type]);
118         printf_pad(16, "%u/%u ", r->r.nr_required, r->r.nr_devs);
119         printf_pad(32, "%s ", devs);
120         printf(" %s\n", pr_units(r->sectors, units));
121 }
122
123 #define for_each_usage_replica(_u, _r)                                  \
124         for (_r = (_u)->replicas;                                       \
125              _r != (void *) (_u)->replicas + (_u)->replica_entries_bytes;\
126              _r = replicas_usage_next(_r),                              \
127              BUG_ON((void *) _r > (void *) (_u)->replicas + (_u)->replica_entries_bytes))
128
129 static void print_fs_usage(const char *path, enum units units)
130 {
131         unsigned i;
132         char uuid[40];
133
134         struct bchfs_handle fs = bcache_fs_open(path);
135
136         struct dev_name *dev;
137         dev_names dev_names = bchu_fs_get_devices(fs);
138
139         struct bch_ioctl_fs_usage *u = bchu_fs_usage(fs);
140
141         uuid_unparse(fs.uuid.b, uuid);
142         printf("Filesystem %s:\n", uuid);
143
144         printf("%-20s%12s\n", "Size:", pr_units(u->capacity, units));
145         printf("%-20s%12s\n", "Used:", pr_units(u->used, units));
146
147         printf("%-20s%12s\n", "Online reserved:", pr_units(u->online_reserved, units));
148
149         printf("\n");
150         printf("%-16s%-16s%s\n", "Data type", "Required/total", "Devices");
151
152         for (i = 0; i < BCH_REPLICAS_MAX; i++) {
153                 if (!u->persistent_reserved[i])
154                         continue;
155
156                 printf_pad(16, "%s: ", "reserved");
157                 printf_pad(16, "%u/%u ", 1, i);
158                 printf_pad(32, "[] ");
159                 printf("%s\n", pr_units(u->persistent_reserved[i], units));
160         }
161
162         struct bch_replicas_usage *r;
163
164         for_each_usage_replica(u, r)
165                 if (r->r.data_type < BCH_DATA_user)
166                         print_replicas_usage(r, &dev_names, units);
167
168         for_each_usage_replica(u, r)
169                 if (r->r.data_type == BCH_DATA_user &&
170                     r->r.nr_required <= 1)
171                         print_replicas_usage(r, &dev_names, units);
172
173         for_each_usage_replica(u, r)
174                 if (r->r.data_type == BCH_DATA_user &&
175                     r->r.nr_required > 1)
176                         print_replicas_usage(r, &dev_names, units);
177
178         for_each_usage_replica(u, r)
179                 if (r->r.data_type > BCH_DATA_user)
180                         print_replicas_usage(r, &dev_names, units);
181
182         free(u);
183
184         sort(&darray_item(dev_names, 0), darray_size(dev_names),
185              sizeof(darray_item(dev_names, 0)), dev_by_label_cmp, NULL);
186
187         darray_foreach(dev, dev_names)
188                 print_dev_usage(fs, dev, units);
189
190         darray_foreach(dev, dev_names) {
191                 free(dev->dev);
192                 free(dev->label);
193         }
194         darray_free(dev_names);
195
196         bcache_fs_close(fs);
197 }
198
199 int cmd_fs_usage(int argc, char *argv[])
200 {
201         enum units units = BYTES;
202         char *fs;
203         int opt;
204
205         while ((opt = getopt(argc, argv, "h")) != -1)
206                 switch (opt) {
207                 case 'h':
208                         units = HUMAN_READABLE;
209                         break;
210                 }
211         args_shift(optind);
212
213         if (!argc) {
214                 print_fs_usage(".", units);
215         } else {
216                 while ((fs = arg_pop()))
217                         print_fs_usage(fs, units);
218         }
219
220         return 0;
221 }