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