7 #include "linux/sort.h"
8 #include "linux/rcupdate.h"
10 #include "libbcachefs/bcachefs_ioctl.h"
11 #include "libbcachefs/buckets.h"
12 #include "libbcachefs/darray.h"
13 #include "libbcachefs/opts.h"
14 #include "libbcachefs/super-io.h"
17 #include "libbcachefs.h"
19 static void __dev_usage_type_to_text(struct printbuf *out,
20 enum bch_data_type type,
22 u64 buckets, u64 sectors, u64 frag)
24 bch2_prt_data_type(out, type);
28 prt_units_u64(out, sectors << 9);
31 prt_printf(out, "%llu", buckets);
35 prt_units_u64(out, frag << 9);
41 static void dev_usage_type_to_text(struct printbuf *out,
42 struct bch_ioctl_dev_usage_v2 *u,
43 enum bch_data_type type)
48 case BCH_DATA_need_discard:
49 case BCH_DATA_need_gc_gens:
50 /* sectors are 0 for these types so calculate sectors for them */
51 sectors = u->d[type].buckets * u->bucket_size;
54 sectors = u->d[type].sectors;
57 __dev_usage_type_to_text(out, type,
61 u->d[type].fragmented);
64 static void dev_usage_to_text(struct printbuf *out,
65 struct bchfs_handle fs,
68 struct bch_ioctl_dev_usage_v2 *u = bchu_dev_usage(fs, d->idx);
71 prt_printf(out, "%s (device %u):", d->label ?: "(no label)", d->idx);
73 prt_str(out, d->dev ?: "(device not found)");
76 prt_str(out, bch2_member_states[u->state]);
81 printbuf_indent_add(out, 2);
87 prt_str(out, "buckets");
90 prt_str(out, "fragmented");
95 for (unsigned i = 0; i < u->nr_data_types; i++)
96 dev_usage_type_to_text(out, u, i);
98 prt_str(out, "capacity:");
101 prt_units_u64(out, (u->nr_buckets * u->bucket_size) << 9);
103 prt_printf(out, "%llu", u->nr_buckets);
106 printbuf_indent_sub(out, 2);
112 static int dev_by_label_cmp(const void *_l, const void *_r)
114 const struct dev_name *l = _l, *r = _r;
116 return (l->label && r->label
117 ? strcmp(l->label, r->label) : 0) ?:
119 ? strcmp(l->dev, r->dev) : 0) ?:
120 cmp_int(l->idx, r->idx);
123 static struct dev_name *dev_idx_to_name(dev_names *dev_names, unsigned idx)
125 darray_for_each(*dev_names, dev)
131 static void replicas_usage_to_text(struct printbuf *out,
132 const struct bch_replicas_usage *r,
133 dev_names *dev_names)
138 char devs[4096], *d = devs;
141 unsigned durability = 0;
143 for (unsigned i = 0; i < r->r.nr_devs; i++) {
144 unsigned dev_idx = r->r.devs[i];
145 struct dev_name *dev = dev_idx_to_name(dev_names, dev_idx);
147 durability += dev->durability;
153 ? sprintf(d, "%s", dev->dev)
154 : sprintf(d, "%u", dev_idx);
159 bch2_prt_data_type(out, r->r.data_type);
163 prt_printf(out, "%u/%u ", r->r.nr_required, r->r.nr_devs);
166 prt_printf(out, "%u ", durability);
169 prt_printf(out, "%s ", devs);
172 prt_units_u64(out, r->sectors << 9);
177 #define for_each_usage_replica(_u, _r) \
178 for (_r = (_u)->replicas; \
179 _r != (void *) (_u)->replicas + (_u)->replica_entries_bytes;\
180 _r = replicas_usage_next(_r), \
181 BUG_ON((void *) _r > (void *) (_u)->replicas + (_u)->replica_entries_bytes))
183 static void fs_usage_to_text(struct printbuf *out, const char *path)
187 struct bchfs_handle fs = bcache_fs_open(path);
189 dev_names dev_names = bchu_fs_get_devices(fs);
191 struct bch_ioctl_fs_usage *u = bchu_fs_usage(fs);
193 prt_str(out, "Filesystem: ");
194 pr_uuid(out, fs.uuid.b);
197 printbuf_tabstops_reset(out);
198 printbuf_tabstop_push(out, 20);
199 printbuf_tabstop_push(out, 16);
201 prt_str(out, "Size:");
203 prt_units_u64(out, u->capacity << 9);
207 prt_str(out, "Used:");
209 prt_units_u64(out, u->used << 9);
213 prt_str(out, "Online reserved:");
215 prt_units_u64(out, u->online_reserved << 9);
221 printbuf_tabstops_reset(out);
223 printbuf_tabstop_push(out, 16);
224 prt_str(out, "Data type");
227 printbuf_tabstop_push(out, 16);
228 prt_str(out, "Required/total");
231 printbuf_tabstop_push(out, 14);
232 prt_str(out, "Durability");
235 printbuf_tabstop_push(out, 14);
236 prt_str(out, "Devices");
239 printbuf_tabstop_push(out, 14);
241 for (i = 0; i < BCH_REPLICAS_MAX; i++) {
242 if (!u->persistent_reserved[i])
245 prt_str(out, "reserved:");
247 prt_printf(out, "%u/%u ", 1, i);
250 prt_units_u64(out, u->persistent_reserved[i] << 9);
255 struct bch_replicas_usage *r;
257 for_each_usage_replica(u, r)
258 if (r->r.data_type < BCH_DATA_user)
259 replicas_usage_to_text(out, r, &dev_names);
261 for_each_usage_replica(u, r)
262 if (r->r.data_type == BCH_DATA_user &&
263 r->r.nr_required <= 1)
264 replicas_usage_to_text(out, r, &dev_names);
266 for_each_usage_replica(u, r)
267 if (r->r.data_type == BCH_DATA_user &&
268 r->r.nr_required > 1)
269 replicas_usage_to_text(out, r, &dev_names);
271 for_each_usage_replica(u, r)
272 if (r->r.data_type > BCH_DATA_user)
273 replicas_usage_to_text(out, r, &dev_names);
277 sort(dev_names.data, dev_names.nr,
278 sizeof(dev_names.data[0]), dev_by_label_cmp, NULL);
280 printbuf_tabstops_reset(out);
281 printbuf_tabstop_push(out, 16);
282 printbuf_tabstop_push(out, 20);
283 printbuf_tabstop_push(out, 16);
284 printbuf_tabstop_push(out, 14);
286 darray_for_each(dev_names, dev)
287 dev_usage_to_text(out, fs, dev);
289 darray_for_each(dev_names, dev) {
293 darray_exit(&dev_names);
298 static void fs_usage_usage(void)
300 puts("bcachefs fs usage - display detailed filesystem usage\n"
301 "Usage: bcachefs fs usage [OPTION]... <mountpoint>\n"
304 " -h, --human-readable Human readable units\n"
305 " -H, --help Display this help and exit\n"
306 "Report bugs to <linux-bcachefs@vger.kernel.org>");
309 int cmd_fs_usage(int argc, char *argv[])
311 static const struct option longopts[] = {
312 { "help", no_argument, NULL, 'H' },
313 { "human-readable", no_argument, NULL, 'h' },
316 bool human_readable = false;
317 struct printbuf buf = PRINTBUF;
321 while ((opt = getopt_long(argc, argv, "h",
322 longopts, NULL)) != -1)
325 human_readable = true;
337 printbuf_reset(&buf);
338 buf.human_readable_units = human_readable;
339 fs_usage_to_text(&buf, ".");
340 printf("%s", buf.buf);
342 while ((fs = arg_pop())) {
343 printbuf_reset(&buf);
344 buf.human_readable_units = human_readable;
345 fs_usage_to_text(&buf, fs);
346 printf("%s", buf.buf);