diff options
Diffstat (limited to 'c_src')
-rw-r--r-- | c_src/cmd_format.c | 3 | ||||
-rw-r--r-- | c_src/cmd_fs.c | 317 | ||||
-rw-r--r-- | c_src/cmd_super.c | 93 | ||||
-rw-r--r-- | c_src/cmd_super.h | 8 |
4 files changed, 231 insertions, 190 deletions
diff --git a/c_src/cmd_format.c b/c_src/cmd_format.c index 740b0e81..841a7913 100644 --- a/c_src/cmd_format.c +++ b/c_src/cmd_format.c @@ -21,6 +21,7 @@ #include <uuid/uuid.h> #include "cmds.h" +#include "cmd_super.h" #include "tools-util.h" #include "posix_to_bcachefs.h" #include "libbcachefs.h" @@ -293,7 +294,7 @@ int cmd_format(int argc, char *argv[]) struct printbuf buf = PRINTBUF; buf.human_readable_units = true; - bch2_sb_to_text(&buf, sb, false, 1 << BCH_SB_FIELD_members_v2); + bch2_sb_to_text_with_names(&buf, sb, false, 1 << BCH_SB_FIELD_members_v2, -1); printf("%s", buf.buf); printbuf_exit(&buf); } diff --git a/c_src/cmd_fs.c b/c_src/cmd_fs.c index aa825e90..4eca866a 100644 --- a/c_src/cmd_fs.c +++ b/c_src/cmd_fs.c @@ -18,96 +18,85 @@ #include "libbcachefs/darray.h" -static void __dev_usage_type_to_text(struct printbuf *out, - enum bch_data_type type, - unsigned bucket_size, - u64 buckets, u64 sectors, u64 frag) -{ - bch2_prt_data_type(out, type); - prt_char(out, ':'); - 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, type, - u->bucket_size, - u->d[type].buckets, - sectors, - u->d[type].fragmented); -} +#define FS_USAGE_FIELDS() \ + x(replicas) \ + x(btree) \ + x(compression) \ + x(rebalance_work) \ + x(devices) + +enum __fs_usage_fields { +#define x(n) __FS_USAGE_##n, + FS_USAGE_FIELDS() +#undef x +}; + +enum fs_usage_fields { +#define x(n) FS_USAGE_##n = BIT(__FS_USAGE_##n), + FS_USAGE_FIELDS() +#undef x +}; + +const char * const fs_usage_field_strs[] = { +#define x(n) [__FS_USAGE_##n] = #n, + FS_USAGE_FIELDS() +#undef x + NULL +}; static void dev_usage_to_text(struct printbuf *out, struct bchfs_handle fs, - struct dev_name *d) + struct dev_name *d, + bool full) { 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); + u64 used = 0, capacity = u->nr_buckets * u->bucket_size; + for (unsigned type = 0; type < u->nr_data_types; type++) { + if (!data_type_is_empty(type)) + used += u->d[type].sectors; + } - printbuf_indent_add(out, 2); - prt_tab(out); + prt_printf(out, "%s (device %u):\t%s\r%s\r %02u%%\n", + d->label ?: "(no label)", d->idx, + d->dev ?: "(device not found)", + bch2_member_states[u->state], + (unsigned) (used * 100 / capacity)); - prt_str(out, "data"); - prt_tab_rjust(out); + if (full) { + printbuf_indent_add(out, 2); + prt_printf(out, "\tdata\rbuckets\rfragmented\r\n"); - prt_str(out, "buckets"); - prt_tab_rjust(out); + for (unsigned type = 0; type < u->nr_data_types; type++) { + bch2_prt_data_type(out, type); + prt_printf(out, ":\t"); - prt_str(out, "fragmented"); - prt_tab_rjust(out); + /* sectors are 0 for empty bucket data types, so calculate sectors for them */ + u64 sectors = data_type_is_empty(type) + ? u->d[type].buckets * u->bucket_size + : u->d[type].sectors; + prt_units_u64(out, sectors << 9); - prt_newline(out); + prt_printf(out, "\r%llu\r", u->d[type].buckets); - for (unsigned i = 0; i < u->nr_data_types; i++) - dev_usage_type_to_text(out, u, i); + u64 fragmented = u->d[type].buckets * u->bucket_size - sectors; + if (fragmented) + prt_units_u64(out, fragmented << 9); + prt_printf(out, "\r\n"); + } - prt_str(out, "capacity:"); - prt_tab(out); + prt_printf(out, "capacity:\t"); + prt_units_u64(out, (u->nr_buckets * u->bucket_size) << 9); + prt_printf(out, "\r%llu\r\n", u->nr_buckets); - 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); + prt_printf(out, "bucket size:\t"); + prt_units_u64(out, u->bucket_size << 9); + prt_printf(out, "\r\n"); - printbuf_indent_sub(out, 2); + printbuf_indent_sub(out, 2); + prt_newline(out); + } - prt_newline(out); free(u); } @@ -124,19 +113,21 @@ static int dev_by_label_cmp(const void *_l, const void *_r) static void devs_usage_to_text(struct printbuf *out, struct bchfs_handle fs, - dev_names dev_names) + dev_names dev_names, + bool full) { sort(dev_names.data, dev_names.nr, sizeof(dev_names.data[0]), dev_by_label_cmp, NULL); printbuf_tabstops_reset(out); + prt_newline(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); + dev_usage_to_text(out, fs, dev, full); darray_for_each(dev_names, dev) { free(dev->dev); @@ -150,14 +141,9 @@ static void persistent_reserved_to_text(struct printbuf *out, if (!sectors) return; - prt_str(out, "reserved:"); - prt_tab(out); - prt_printf(out, "%u/%u ", 1, nr_replicas); - prt_tab(out); - prt_str(out, "[] "); + prt_printf(out, "reserved:\t%u/%u\t[] ", 1, nr_replicas); prt_units_u64(out, sectors << 9); - prt_tab_rjust(out); - prt_newline(out); + prt_printf(out, "\r\n"); } static void replicas_usage_to_text(struct printbuf *out, @@ -190,21 +176,12 @@ static void replicas_usage_to_text(struct printbuf *out, *d++ = '\0'; bch2_prt_data_type(out, r->data_type); - prt_char(out, ':'); - prt_tab(out); - - prt_printf(out, "%u/%u ", r->nr_required, r->nr_devs); - prt_tab(out); - - prt_printf(out, "%u ", durability); - prt_tab(out); - - prt_printf(out, "%s ", devs); - prt_tab(out); + prt_printf(out, ":\t%u/%u\t%u\t%s\t", + r->nr_required, r->nr_devs, + durability, devs); prt_units_u64(out, sectors << 9); - prt_tab_rjust(out); - prt_newline(out); + prt_printf(out, "\r\n"); } #define for_each_usage_replica(_u, _r) \ @@ -251,15 +228,27 @@ static void accounting_swab_if_old(struct bch_ioctl_query_accounting *in) static int fs_usage_v1_to_text(struct printbuf *out, struct bchfs_handle fs, - dev_names dev_names) + dev_names dev_names, + enum fs_usage_fields fields) { - struct bch_ioctl_query_accounting *a = - bchu_fs_accounting(fs, - BIT(BCH_DISK_ACCOUNTING_persistent_reserved)| + unsigned accounting_types = 0; + + if (fields & FS_USAGE_replicas) + accounting_types |= BIT(BCH_DISK_ACCOUNTING_replicas)| - BIT(BCH_DISK_ACCOUNTING_compression)| - BIT(BCH_DISK_ACCOUNTING_btree)| - BIT(BCH_DISK_ACCOUNTING_rebalance_work)); + BIT(BCH_DISK_ACCOUNTING_persistent_reserved); + + if (fields & FS_USAGE_compression) + accounting_types |= BIT(BCH_DISK_ACCOUNTING_compression); + + if (fields & FS_USAGE_btree) + accounting_types |= BIT(BCH_DISK_ACCOUNTING_btree); + + if (fields & FS_USAGE_rebalance_work) + accounting_types |= BIT(BCH_DISK_ACCOUNTING_rebalance_work); + + struct bch_ioctl_query_accounting *a = + bchu_fs_accounting(fs, accounting_types); if (!a) return -1; @@ -277,45 +266,27 @@ static int fs_usage_v1_to_text(struct printbuf *out, printbuf_tabstop_push(out, 20); printbuf_tabstop_push(out, 16); - prt_str(out, "Size:"); - prt_tab(out); + prt_printf(out, "Size:\t"); prt_units_u64(out, a->capacity << 9); - prt_tab_rjust(out); - prt_newline(out); + prt_printf(out, "\r\n"); - prt_str(out, "Used:"); - prt_tab(out); + prt_printf(out, "Used:\t"); prt_units_u64(out, a->used << 9); - prt_tab_rjust(out); - prt_newline(out); + prt_printf(out, "\r\n"); - prt_str(out, "Online reserved:"); - prt_tab(out); + prt_printf(out, "Online reserved:\t"); prt_units_u64(out, a->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); + prt_printf(out, "\r\n"); + + if (fields & FS_USAGE_replicas) { + printbuf_tabstops_reset(out); + printbuf_tabstop_push(out, 16); + printbuf_tabstop_push(out, 16); + printbuf_tabstop_push(out, 14); + printbuf_tabstop_push(out, 14); + printbuf_tabstop_push(out, 14); + prt_printf(out, "\nData type\tRequired/total\tDurability\tDevices\n"); + } unsigned prev_type = 0; @@ -364,8 +335,7 @@ static int fs_usage_v1_to_text(struct printbuf *out, prt_units_u64(out, nr_extents ? div_u64(sectors_uncompressed << 9, nr_extents) : 0); - prt_tab_rjust(out); - prt_newline(out); + prt_printf(out, "\r\n"); break; case BCH_DISK_ACCOUNTING_btree: if (new_type) { @@ -376,8 +346,7 @@ static int fs_usage_v1_to_text(struct printbuf *out, } prt_printf(out, "%s:\t", bch2_btree_id_str(acc_k.btree.id)); prt_units_u64(out, a->v.d[0] << 9); - prt_tab_rjust(out); - prt_newline(out); + prt_printf(out, "\r\n"); break; case BCH_DISK_ACCOUNTING_rebalance_work: if (new_type) @@ -395,7 +364,8 @@ static int fs_usage_v1_to_text(struct printbuf *out, static void fs_usage_v0_to_text(struct printbuf *out, struct bchfs_handle fs, - dev_names dev_names) + dev_names dev_names, + enum fs_usage_fields fields) { struct bch_ioctl_fs_usage *u = bchu_fs_usage(fs); @@ -410,20 +380,17 @@ static void fs_usage_v0_to_text(struct printbuf *out, prt_str(out, "Size:"); prt_tab(out); prt_units_u64(out, u->capacity << 9); - prt_tab_rjust(out); - prt_newline(out); + prt_printf(out, "\r\n"); prt_str(out, "Used:"); prt_tab(out); prt_units_u64(out, u->used << 9); - prt_tab_rjust(out); - prt_newline(out); + prt_printf(out, "\r\n"); prt_str(out, "Online reserved:"); prt_tab(out); prt_units_u64(out, u->online_reserved << 9); - prt_tab_rjust(out); - prt_newline(out); + prt_printf(out, "\r\n"); prt_newline(out); @@ -473,43 +440,34 @@ static void fs_usage_v0_to_text(struct printbuf *out, free(u); } -static void fs_usage_to_text(struct printbuf *out, const char *path) +static void fs_usage_to_text(struct printbuf *out, const char *path, + enum fs_usage_fields fields) { struct bchfs_handle fs = bcache_fs_open(path); dev_names dev_names = bchu_fs_get_devices(fs); - if (!fs_usage_v1_to_text(out, fs, dev_names)) + if (!fs_usage_v1_to_text(out, fs, dev_names, fields)) goto devs; - fs_usage_v0_to_text(out, fs, dev_names); + fs_usage_v0_to_text(out, fs, dev_names, fields); devs: - devs_usage_to_text(out, fs, dev_names); + devs_usage_to_text(out, fs, dev_names, fields & FS_USAGE_devices); darray_exit(&dev_names); bcache_fs_close(fs); } -int fs_usage(void) -{ - puts("bcachefs fs - manage a running filesystem\n" - "Usage: bcachefs fs <CMD> [OPTIONS]\n" - "\n" - "Commands:\n" - " usage Display detailed filesystem usage\n" - " top Show runtime performance information\n" - "\n" - "Report bugs to <linux-bcachefs@vger.kernel.org>"); - return 0; -} - 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" + " -f, --fields=FIELDS List of accounting sections to print\n" + " replicas,btree,compression,rebalance_work,devices" + " -a Print all accounting fields\n" " -h, --human-readable Human readable units\n" " -H, --help Display this help and exit\n" "Report bugs to <linux-bcachefs@vger.kernel.org>"); @@ -518,18 +476,26 @@ static void fs_usage_usage(void) int cmd_fs_usage(int argc, char *argv[]) { static const struct option longopts[] = { - { "help", no_argument, NULL, 'H' }, + { "fields", required_argument, NULL, 'f' }, + { "all", no_argument, NULL, 'a' }, { "human-readable", no_argument, NULL, 'h' }, + { "help", no_argument, NULL, 'H' }, { NULL } }; bool human_readable = false; + unsigned fields = 0; struct printbuf buf = PRINTBUF; char *fs; int opt; - while ((opt = getopt_long(argc, argv, "h", + while ((opt = getopt_long(argc, argv, "f:ahH", longopts, NULL)) != -1) switch (opt) { + case 'f': + fields |= read_flag_list_or_die(optarg, fs_usage_field_strs, "fields"); + break; + case 'a': + fields = ~0; case 'h': human_readable = true; break; @@ -545,13 +511,13 @@ int cmd_fs_usage(int argc, char *argv[]) if (!argc) { printbuf_reset(&buf); buf.human_readable_units = human_readable; - fs_usage_to_text(&buf, "."); + fs_usage_to_text(&buf, ".", fields); printf("%s", buf.buf); } else { while ((fs = arg_pop())) { printbuf_reset(&buf); buf.human_readable_units = human_readable; - fs_usage_to_text(&buf, fs); + fs_usage_to_text(&buf, fs, fields); printf("%s", buf.buf); } } @@ -560,6 +526,19 @@ int cmd_fs_usage(int argc, char *argv[]) return 0; } +int fs_usage(void) +{ + puts("bcachefs fs - manage a running filesystem\n" + "Usage: bcachefs fs <CMD> [OPTIONS]\n" + "\n" + "Commands:\n" + " usage Display detailed filesystem usage\n" + " top Show runtime performance information\n" + "\n" + "Report bugs to <linux-bcachefs@vger.kernel.org>"); + return 0; +} + int fs_cmds(int argc, char *argv[]) { char *cmd = pop_cmd(&argc, argv); diff --git a/c_src/cmd_super.c b/c_src/cmd_super.c index 3161205f..00776b1b 100644 --- a/c_src/cmd_super.c +++ b/c_src/cmd_super.c @@ -21,6 +21,7 @@ #include <uuid/uuid.h> #include "cmds.h" +#include "cmd_super.h" #include "libbcachefs.h" #include "libbcachefs/opts.h" #include "libbcachefs/super-io.h" @@ -28,6 +29,8 @@ #include "libbcachefs/darray.h" +#include "src/rust_to_c.h" + static void show_super_usage(void) { puts("bcachefs show-super \n" @@ -42,6 +45,72 @@ static void show_super_usage(void) exit(EXIT_SUCCESS); } +static struct sb_name *sb_dev_to_name(sb_names sb_names, unsigned idx) +{ + darray_for_each(sb_names, i) + if (i->sb.sb->dev_idx == idx) + return i; + return NULL; +} + +static void print_one_member(struct printbuf *out, sb_names sb_names, + struct bch_sb *sb, + struct bch_sb_field_disk_groups *gi, + struct bch_member m, unsigned idx) +{ + struct sb_name *name = sb_dev_to_name(sb_names, idx); + prt_printf(out, "Device %u:\t%s\t", idx, name ? name->name : "(not found)"); + + if (name) { + char *model = fd_to_dev_model(name->sb.bdev->bd_fd); + prt_str(out, model); + free(model); + } + prt_newline(out); + + printbuf_indent_add(out, 2); + bch2_member_to_text(out, &m, gi, sb, idx); + printbuf_indent_sub(out, 2); +} + +void bch2_sb_to_text_with_names(struct printbuf *out, struct bch_sb *sb, + bool print_layout, unsigned fields, int field_only) +{ + CLASS(printbuf, uuid_buf)(); + prt_str(&uuid_buf, "UUID="); + pr_uuid(&uuid_buf, sb->user_uuid.b); + + sb_names sb_names = {}; + bch2_scan_device_sbs(uuid_buf.buf, &sb_names); + + if (field_only >= 0) { + struct bch_sb_field *f = bch2_sb_field_get_id(sb, field_only); + + if (f) + __bch2_sb_field_to_text(out, sb, f); + } else { + printbuf_tabstop_push(out, 44); + + bch2_sb_to_text(out, sb, print_layout, + fields & ~(BIT(BCH_SB_FIELD_members_v1)| + BIT(BCH_SB_FIELD_members_v2))); + + struct bch_sb_field_disk_groups *gi = bch2_sb_field_get(sb, disk_groups); + + struct bch_sb_field_members_v1 *mi1; + if ((fields & BIT(BCH_SB_FIELD_members_v1)) && + (mi1 = bch2_sb_field_get(sb, members_v1))) + for (unsigned i = 0; i < sb->nr_devices; i++) + print_one_member(out, sb_names, sb, gi, bch2_members_v1_get(mi1, i), i); + + struct bch_sb_field_members_v2 *mi2; + if ((fields & BIT(BCH_SB_FIELD_members_v2)) && + (mi2 = bch2_sb_field_get(sb, members_v2))) + for (unsigned i = 0; i < sb->nr_devices; i++) + print_one_member(out, sb_names, sb, gi, bch2_members_v2_get(mi2, i), i); + } +} + int cmd_show_super(int argc, char *argv[]) { static const struct option longopts[] = { @@ -98,32 +167,16 @@ int cmd_show_super(int argc, char *argv[]) if (print_default_fields) { fields |= bch2_sb_field_get(sb.sb, members_v2) - ? 1 << BCH_SB_FIELD_members_v2 - : 1 << BCH_SB_FIELD_members_v1; - fields |= 1 << BCH_SB_FIELD_errors; + ? BIT(BCH_SB_FIELD_members_v2) + : BIT(BCH_SB_FIELD_members_v1); + fields |= BIT(BCH_SB_FIELD_errors); } struct printbuf buf = PRINTBUF; buf.human_readable_units = true; - if (field_only >= 0) { - struct bch_sb_field *f = bch2_sb_field_get_id(sb.sb, field_only); - - if (f) - __bch2_sb_field_to_text(&buf, sb.sb, f); - } else { - printbuf_tabstop_push(&buf, 44); - - char *model = fd_to_dev_model(sb.bdev->bd_fd); - prt_str(&buf, "Device:"); - prt_tab(&buf); - prt_str(&buf, model); - prt_newline(&buf); - free(model); - - bch2_sb_to_text(&buf, sb.sb, print_layout, fields); - } + bch2_sb_to_text_with_names(&buf, sb.sb, print_layout, fields, field_only); printf("%s", buf.buf); bch2_free_super(&sb); diff --git a/c_src/cmd_super.h b/c_src/cmd_super.h new file mode 100644 index 00000000..78f71967 --- /dev/null +++ b/c_src/cmd_super.h @@ -0,0 +1,8 @@ +#ifndef _TOOLS_CMD_SHOW_SUPER_H +#define _TOOLS_CMD_SHOW_SUPER_H + +#include "libbcachefs/super-io.h" + +void bch2_sb_to_text_with_names(struct printbuf *, struct bch_sb *, bool, unsigned, int); + +#endif /* _TOOLS_CMD_SHOW_SUPER_H */ |