diff options
author | Thomas Bertschinger <tahbertschinger@gmail.com> | 2024-01-15 23:41:02 -0700 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2024-01-16 01:47:05 -0500 |
commit | f5baaf48e3e82b1caf9f5cd1207d4d6feba3a2e5 (patch) | |
tree | 59f7b0e4667df7a9d3d5a45725f2aaab3e79b4c5 /c_src/cmd_fs.c | |
parent | fb35dbfdc5a9446fbb856dae5542b23963e28b89 (diff) |
move Rust sources to top level, C sources into c_src
This moves the Rust sources out of rust_src/ and into the top level.
Running the bcachefs executable out of the development tree is now:
$ ./target/release/bcachefs command
or
$ cargo run --profile release -- command
instead of "./bcachefs command".
Building and installing is still:
$ make && make install
Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'c_src/cmd_fs.c')
-rw-r--r-- | c_src/cmd_fs.c | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/c_src/cmd_fs.c b/c_src/cmd_fs.c new file mode 100644 index 00000000..67c38af6 --- /dev/null +++ b/c_src/cmd_fs.c @@ -0,0 +1,348 @@ +#include <getopt.h> +#include <stdio.h> +#include <sys/ioctl.h> + +#include <uuid/uuid.h> + +#include "linux/sort.h" + +#include "libbcachefs/bcachefs_ioctl.h" +#include "libbcachefs/darray.h" +#include "libbcachefs/opts.h" +#include "libbcachefs/super-io.h" + +#include "cmds.h" +#include "libbcachefs.h" + +static void __dev_usage_type_to_text(struct printbuf *out, + const char *type, + unsigned bucket_size, + u64 buckets, u64 sectors, u64 frag) +{ + prt_printf(out, "%s:", type); + prt_tab(out); + + prt_units_u64(out, sectors << 9); + prt_tab_rjust(out); + + prt_printf(out, "%llu", buckets); + prt_tab_rjust(out); + + if (frag) { + prt_units_u64(out, frag << 9); + prt_tab_rjust(out); + } + prt_newline(out); +} + +static void dev_usage_type_to_text(struct printbuf *out, + struct bch_ioctl_dev_usage_v2 *u, + enum bch_data_type type) +{ + u64 sectors = 0; + switch (type) { + case BCH_DATA_free: + case BCH_DATA_need_discard: + case BCH_DATA_need_gc_gens: + /* sectors are 0 for these types so calculate sectors for them */ + sectors = u->d[type].buckets * u->bucket_size; + break; + default: + sectors = u->d[type].sectors; + } + + __dev_usage_type_to_text(out, bch2_data_types[type], + u->bucket_size, + u->d[type].buckets, + sectors, + u->d[type].fragmented); +} + +static void dev_usage_to_text(struct printbuf *out, + struct bchfs_handle fs, + struct dev_name *d) +{ + struct bch_ioctl_dev_usage_v2 *u = bchu_dev_usage(fs, d->idx); + + prt_newline(out); + prt_printf(out, "%s (device %u):", d->label ?: "(no label)", d->idx); + prt_tab(out); + prt_str(out, d->dev ?: "(device not found)"); + prt_tab_rjust(out); + + prt_str(out, bch2_member_states[u->state]); + prt_tab_rjust(out); + + prt_newline(out); + + printbuf_indent_add(out, 2); + prt_tab(out); + + prt_str(out, "data"); + prt_tab_rjust(out); + + prt_str(out, "buckets"); + prt_tab_rjust(out); + + prt_str(out, "fragmented"); + prt_tab_rjust(out); + + prt_newline(out); + + for (unsigned i = 0; i < u->nr_data_types; i++) + dev_usage_type_to_text(out, u, i); + + prt_str(out, "capacity:"); + prt_tab(out); + + prt_units_u64(out, (u->nr_buckets * u->bucket_size) << 9); + prt_tab_rjust(out); + prt_printf(out, "%llu", u->nr_buckets); + prt_tab_rjust(out); + + printbuf_indent_sub(out, 2); + + prt_newline(out); + free(u); +} + +static int dev_by_label_cmp(const void *_l, const void *_r) +{ + const struct dev_name *l = _l, *r = _r; + + return (l->label && r->label + ? strcmp(l->label, r->label) : 0) ?: + (l->dev && r->dev + ? strcmp(l->dev, r->dev) : 0) ?: + cmp_int(l->idx, r->idx); +} + +static struct dev_name *dev_idx_to_name(dev_names *dev_names, unsigned idx) +{ + darray_for_each(*dev_names, dev) + if (dev->idx == idx) + return dev; + return NULL; +} + +static void replicas_usage_to_text(struct printbuf *out, + const struct bch_replicas_usage *r, + dev_names *dev_names) +{ + if (!r->sectors) + return; + + char devs[4096], *d = devs; + *d++ = '['; + + unsigned durability = 0; + + for (unsigned i = 0; i < r->r.nr_devs; i++) { + unsigned dev_idx = r->r.devs[i]; + struct dev_name *dev = dev_idx_to_name(dev_names, dev_idx); + + durability += dev->durability; + + if (i) + *d++ = ' '; + + d += dev && dev->dev + ? sprintf(d, "%s", dev->dev) + : sprintf(d, "%u", dev_idx); + } + *d++ = ']'; + *d++ = '\0'; + + prt_printf(out, "%s: ", bch2_data_types[r->r.data_type]); + prt_tab(out); + + prt_printf(out, "%u/%u ", r->r.nr_required, r->r.nr_devs); + prt_tab(out); + + prt_printf(out, "%u ", durability); + prt_tab(out); + + prt_printf(out, "%s ", devs); + prt_tab(out); + + prt_units_u64(out, r->sectors << 9); + prt_tab_rjust(out); + prt_newline(out); +} + +#define for_each_usage_replica(_u, _r) \ + for (_r = (_u)->replicas; \ + _r != (void *) (_u)->replicas + (_u)->replica_entries_bytes;\ + _r = replicas_usage_next(_r), \ + BUG_ON((void *) _r > (void *) (_u)->replicas + (_u)->replica_entries_bytes)) + +static void fs_usage_to_text(struct printbuf *out, const char *path) +{ + unsigned i; + + struct bchfs_handle fs = bcache_fs_open(path); + + dev_names dev_names = bchu_fs_get_devices(fs); + + struct bch_ioctl_fs_usage *u = bchu_fs_usage(fs); + + prt_str(out, "Filesystem: "); + pr_uuid(out, fs.uuid.b); + prt_newline(out); + + printbuf_tabstops_reset(out); + printbuf_tabstop_push(out, 20); + printbuf_tabstop_push(out, 16); + + prt_str(out, "Size:"); + prt_tab(out); + prt_units_u64(out, u->capacity << 9); + prt_tab_rjust(out); + prt_newline(out); + + prt_str(out, "Used:"); + prt_tab(out); + prt_units_u64(out, u->used << 9); + prt_tab_rjust(out); + prt_newline(out); + + prt_str(out, "Online reserved:"); + prt_tab(out); + prt_units_u64(out, u->online_reserved << 9); + prt_tab_rjust(out); + prt_newline(out); + + prt_newline(out); + + printbuf_tabstops_reset(out); + + printbuf_tabstop_push(out, 16); + prt_str(out, "Data type"); + prt_tab(out); + + printbuf_tabstop_push(out, 16); + prt_str(out, "Required/total"); + prt_tab(out); + + printbuf_tabstop_push(out, 14); + prt_str(out, "Durability"); + prt_tab(out); + + printbuf_tabstop_push(out, 14); + prt_str(out, "Devices"); + prt_newline(out); + + printbuf_tabstop_push(out, 14); + + for (i = 0; i < BCH_REPLICAS_MAX; i++) { + if (!u->persistent_reserved[i]) + continue; + + prt_str(out, "reserved:"); + prt_tab(out); + prt_printf(out, "%u/%u ", 1, i); + prt_tab(out); + prt_str(out, "[] "); + prt_units_u64(out, u->persistent_reserved[i] << 9); + prt_tab_rjust(out); + prt_newline(out); + } + + struct bch_replicas_usage *r; + + for_each_usage_replica(u, r) + if (r->r.data_type < BCH_DATA_user) + replicas_usage_to_text(out, r, &dev_names); + + for_each_usage_replica(u, r) + if (r->r.data_type == BCH_DATA_user && + r->r.nr_required <= 1) + replicas_usage_to_text(out, r, &dev_names); + + for_each_usage_replica(u, r) + if (r->r.data_type == BCH_DATA_user && + r->r.nr_required > 1) + replicas_usage_to_text(out, r, &dev_names); + + for_each_usage_replica(u, r) + if (r->r.data_type > BCH_DATA_user) + replicas_usage_to_text(out, r, &dev_names); + + free(u); + + sort(dev_names.data, dev_names.nr, + sizeof(dev_names.data[0]), dev_by_label_cmp, NULL); + + printbuf_tabstops_reset(out); + printbuf_tabstop_push(out, 16); + printbuf_tabstop_push(out, 20); + printbuf_tabstop_push(out, 16); + printbuf_tabstop_push(out, 14); + + darray_for_each(dev_names, dev) + dev_usage_to_text(out, fs, dev); + + darray_for_each(dev_names, dev) { + free(dev->dev); + free(dev->label); + } + darray_exit(&dev_names); + + bcache_fs_close(fs); +} + +static void fs_usage_usage(void) +{ + puts("bcachefs fs usage - display detailed filesystem usage\n" + "Usage: bcachefs fs usage [OPTION]... <mountpoint>\n" + "\n" + "Options:\n" + " -h, --human-readable Human readable units\n" + " -H, --help Display this help and exit\n" + "Report bugs to <linux-bcachefs@vger.kernel.org>"); +} + +int cmd_fs_usage(int argc, char *argv[]) +{ + static const struct option longopts[] = { + { "help", no_argument, NULL, 'H' }, + { "human-readable", no_argument, NULL, 'h' }, + { NULL } + }; + bool human_readable = false; + struct printbuf buf = PRINTBUF; + char *fs; + int opt; + + while ((opt = getopt_long(argc, argv, "h", + longopts, NULL)) != -1) + switch (opt) { + case 'h': + human_readable = true; + break; + case 'H': + fs_usage_usage(); + exit(EXIT_SUCCESS); + default: + fs_usage_usage(); + exit(EXIT_FAILURE); + } + args_shift(optind); + + if (!argc) { + printbuf_reset(&buf); + buf.human_readable_units = human_readable; + fs_usage_to_text(&buf, "."); + printf("%s", buf.buf); + } else { + while ((fs = arg_pop())) { + printbuf_reset(&buf); + buf.human_readable_units = human_readable; + fs_usage_to_text(&buf, fs); + printf("%s", buf.buf); + } + } + + printbuf_exit(&buf); + return 0; +} |