From dbad1685bc2d3bad50c5e161b78d2b8fb9f4d8aa Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Fri, 29 Dec 2017 21:14:51 -0500 Subject: [PATCH] show-super can now print more stuff --- cmd_device.c | 37 ++++--- cmd_format.c | 61 +++++++++-- cmd_fs.c | 15 --- libbcachefs.c | 286 ++++++++++++++++++++++++++++++++++++++------------ libbcachefs.h | 2 +- tools-util.c | 17 ++- tools-util.h | 16 +++ 7 files changed, 327 insertions(+), 107 deletions(-) diff --git a/cmd_device.c b/cmd_device.c index f8e0cfbf..22ab016f 100644 --- a/cmd_device.c +++ b/cmd_device.c @@ -237,13 +237,14 @@ int cmd_device_add(int argc, char *argv[]) device_add_usage(); exit(EXIT_SUCCESS); } + args_shift(optind); - if (argc - optind != 2) + if (argc != 2) die("Please supply a filesystem and a device to add"); - struct bchfs_handle fs = bcache_fs_open(argv[optind]); + struct bchfs_handle fs = bcache_fs_open(arg_pop()); - dev_opts.path = argv[optind + 1]; + dev_opts.path = arg_pop(); dev_opts.fd = open_for_format(dev_opts.path, force); format_opts.block_size = @@ -296,12 +297,20 @@ int cmd_device_remove(int argc, char *argv[]) case 'h': device_remove_usage(); } + args_shift(optind); - if (argc - optind != 2) - die("Please supply a filesystem and at least one device to remove"); + char *fs = arg_pop(); + if (!fs) + die("Please supply a filesystem"); - disk_ioctl(argv[optind], argv[optind + 1], - BCH_IOCTL_DISK_REMOVE, flags); + char *dev = arg_pop(); + if (!dev) + die("Please supply a device to remove"); + + if (argc) + die("too many arguments"); + + disk_ioctl(fs, dev, BCH_IOCTL_DISK_REMOVE, flags); return 0; } @@ -469,21 +478,23 @@ int cmd_device_resize(int argc, char *argv[]) case 'h': device_resize_usage(); } + args_shift(optind); - if (argc < optind + 1) + char *dev = arg_pop(); + if (!dev) die("Please supply a device to resize"); - char *dev = argv[optind]; int dev_fd = xopen(dev, O_RDONLY); - if (argc == optind + 1) + char *size_arg = arg_pop(); + if (!size_arg) size = get_size(dev, dev_fd); - else if (bch2_strtoull_h(argv[optind + 1], &size)) + else if (bch2_strtoull_h(size_arg, &size)) die("invalid size"); size >>= 9; - if (argc > optind + 2) + if (argc) die("Too many arguments"); struct stat dev_stat = xfstat(dev_fd); @@ -521,7 +532,7 @@ int cmd_device_resize(int argc, char *argv[]) struct bch_opts opts = bch2_opts_empty(); const char *err = bch2_fs_open(&dev, 1, opts, &c); if (err) - die("error opening %s: %s", argv[optind], err); + die("error opening %s: %s", dev, err); struct bch_dev *ca, *resize = NULL; unsigned i; diff --git a/cmd_format.c b/cmd_format.c index b22fe946..47617660 100644 --- a/cmd_format.c +++ b/cmd_format.c @@ -269,7 +269,7 @@ int cmd_format(int argc, char *argv[]) bch2_format(opts, devices.item, darray_size(devices)); if (!quiet) - bch2_super_print(sb, HUMAN_READABLE); + bch2_sb_print(sb, false, 1 << BCH_SB_FIELD_members, HUMAN_READABLE); free(sb); if (opts.passphrase) { @@ -280,18 +280,61 @@ int cmd_format(int argc, char *argv[]) return 0; } +static void show_super_usage(void) +{ + puts("bcachefs show-super \n" + "Usage: bcachefs show-super [OPTION].. device\n" + "\n" + "Options:\n" + " -f, --fields=(fields) list of sections to print\n" + " -l, --layout print superblock layout\n" + " -h, --help display this help and exit\n" + "Report bugs to "); + exit(EXIT_SUCCESS); +} + int cmd_show_super(int argc, char *argv[]) { - struct bch_sb_handle sb; + static const struct option longopts[] = { + { "fields", 1, NULL, 'f' }, + { "layout", 0, NULL, 'l' }, + { "help", 0, NULL, 'h' }, + { NULL } + }; + unsigned fields = 1 << BCH_SB_FIELD_members; + bool print_layout = false; + int opt; + + while ((opt = getopt_long(argc, argv, "f:lh", longopts, NULL)) != -1) + switch (opt) { + case 'f': + fields = !strcmp(optarg, "all") + ? ~0 + : read_flag_list_or_die(optarg, + bch2_sb_fields, "superblock field"); + break; + case 'l': + print_layout = true; + break; + case 'h': + show_super_usage(); + break; + } + args_shift(optind); + + char *dev = arg_pop(); + if (!dev) + die("please supply a device"); + if (argc) + die("too many arguments"); + const char *err; - - if (argc != 2) - die("please supply a single device"); - - err = bch2_read_super(argv[1], bch2_opts_empty(), &sb); + struct bch_sb_handle sb; + err = bch2_read_super(dev, bch2_opts_empty(), &sb); if (err) - die("Error opening %s: %s", argv[1], err); + die("Error opening %s: %s", dev, err); - bch2_super_print(sb.sb, HUMAN_READABLE); + bch2_sb_print(sb.sb, print_layout, fields, HUMAN_READABLE); + bch2_free_super(&sb); return 0; } diff --git a/cmd_fs.c b/cmd_fs.c index 3f64161f..964d1b04 100644 --- a/cmd_fs.c +++ b/cmd_fs.c @@ -10,21 +10,6 @@ #include "cmds.h" #include "libbcachefs.h" -static inline int printf_pad(unsigned pad, const char * fmt, ...) -{ - va_list args; - int ret; - - va_start(args, fmt); - ret = vprintf(fmt, args); - va_end(args); - - while (ret++ < pad) - putchar(' '); - - return ret; -} - static void print_fs_usage(const char *path, enum units units) { unsigned i, j; diff --git a/libbcachefs.c b/libbcachefs.c index afbc8d7a..1481ef38 100644 --- a/libbcachefs.c +++ b/libbcachefs.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -310,18 +311,207 @@ static unsigned get_dev_has_data(struct bch_sb *sb, unsigned dev) return data_has; } -void bch2_super_print(struct bch_sb *sb, int units) +/* superblock printing: */ + +static void bch2_sb_print_layout(struct bch_sb *sb, enum units units) +{ + struct bch_sb_layout *l = &sb->layout; + unsigned i; + + printf(" type: %u\n" + " superblock max size: %s\n" + " nr superblocks: %u\n" + " Offsets: ", + l->layout_type, + pr_units(1 << l->sb_max_size_bits, units), + l->nr_superblocks); + + for (i = 0; i < l->nr_superblocks; i++) { + if (i) + printf(", "); + printf("%llu", le64_to_cpu(l->sb_offset[i])); + } + putchar('\n'); +} + +static void bch2_sb_print_journal(struct bch_sb *sb, struct bch_sb_field *f, + enum units units) +{ + struct bch_sb_field_journal *journal = field_to_type(f, journal); + unsigned i, nr = bch2_nr_journal_buckets(journal); + + printf(" Buckets: "); + for (i = 0; i < nr; i++) { + if (i) + putchar(' '); + printf("%llu", le64_to_cpu(journal->buckets[i])); + } + putchar('\n'); +} + +static void bch2_sb_print_members(struct bch_sb *sb, struct bch_sb_field *f, + enum units units) +{ + struct bch_sb_field_members *mi = field_to_type(f, members); + unsigned i; + + for (i = 0; i < sb->nr_devices; i++) { + struct bch_member *m = mi->members + i; + time_t last_mount = le64_to_cpu(m->last_mount); + char member_uuid_str[40]; + char data_allowed_str[100]; + char data_has_str[100]; + + if (!bch2_member_exists(m)) + continue; + + uuid_unparse(m->uuid.b, member_uuid_str); + bch2_scnprint_flag_list(data_allowed_str, + sizeof(data_allowed_str), + bch2_data_types, + BCH_MEMBER_DATA_ALLOWED(m)); + if (!data_allowed_str[0]) + strcpy(data_allowed_str, "(none)"); + + bch2_scnprint_flag_list(data_has_str, + sizeof(data_has_str), + bch2_data_types, + get_dev_has_data(sb, i)); + if (!data_has_str[0]) + strcpy(data_has_str, "(none)"); + + printf(" Device %u:\n" + " UUID: %s\n" + " Size: %s\n" + " Bucket size: %s\n" + " First bucket: %u\n" + " Buckets: %llu\n" + " Last mount: %s\n" + " State: %s\n" + " Tier: %llu\n" + " Data allowed: %s\n" + + " Has data: %s\n" + + " Replacement policy: %s\n" + " Discard: %llu\n", + i, member_uuid_str, + pr_units(le16_to_cpu(m->bucket_size) * + le64_to_cpu(m->nbuckets), units), + pr_units(le16_to_cpu(m->bucket_size), units), + le16_to_cpu(m->first_bucket), + le64_to_cpu(m->nbuckets), + last_mount ? ctime(&last_mount) : "(never)", + + BCH_MEMBER_STATE(m) < BCH_MEMBER_STATE_NR + ? bch2_dev_state[BCH_MEMBER_STATE(m)] + : "unknown", + + BCH_MEMBER_TIER(m), + data_allowed_str, + data_has_str, + + BCH_MEMBER_REPLACEMENT(m) < CACHE_REPLACEMENT_NR + ? bch2_cache_replacement_policies[BCH_MEMBER_REPLACEMENT(m)] + : "unknown", + + BCH_MEMBER_DISCARD(m)); + } +} + +static void bch2_sb_print_crypt(struct bch_sb *sb, struct bch_sb_field *f, + enum units units) +{ + struct bch_sb_field_crypt *crypt = field_to_type(f, crypt); + + printf(" KFD: %llu\n" + " scrypt n: %llu\n" + " scrypt r: %llu\n" + " scrypt p: %llu\n", + BCH_CRYPT_KDF_TYPE(crypt), + BCH_KDF_SCRYPT_N(crypt), + BCH_KDF_SCRYPT_R(crypt), + BCH_KDF_SCRYPT_P(crypt)); +} + +static void bch2_sb_print_replicas(struct bch_sb *sb, struct bch_sb_field *f, + enum units units) +{ + struct bch_sb_field_replicas *replicas = field_to_type(f, replicas); + struct bch_replicas_entry *e; + unsigned i; + + for_each_replicas_entry(replicas, e) { + printf_pad(32, " %s:", bch2_data_types[e->data_type]); + + putchar('['); + for (i = 0; i < e->nr; i++) { + if (i) + putchar(' '); + printf("%u", e->devs[i]); + } + printf("]\n"); + } +} + +typedef void (*sb_field_print_fn)(struct bch_sb *, struct bch_sb_field *, enum units); + +struct bch_sb_field_ops { + sb_field_print_fn print; +}; + +static const struct bch_sb_field_ops bch2_sb_field_ops[] = { +#define x(f, nr) \ + [BCH_SB_FIELD_##f] = { \ + .print = bch2_sb_print_##f, \ + }, + BCH_SB_FIELDS() +#undef x +}; + +static inline void bch2_sb_field_print(struct bch_sb *sb, + struct bch_sb_field *f, + enum units units) +{ + unsigned type = le32_to_cpu(f->type); + + if (type < BCH_SB_FIELD_NR) + bch2_sb_field_ops[type].print(sb, f, units); + else + printf("(unknown field %u)\n", type); +} + +void bch2_sb_print(struct bch_sb *sb, bool print_layout, + unsigned fields, enum units units) { struct bch_sb_field_members *mi; char user_uuid_str[40], internal_uuid_str[40]; + char fields_have_str[200]; char label[BCH_SB_LABEL_SIZE + 1]; - unsigned i; + struct bch_sb_field *f; + u64 fields_have = 0; + unsigned nr_devices = 0; memset(label, 0, sizeof(label)); memcpy(label, sb->label, sizeof(sb->label)); uuid_unparse(sb->user_uuid.b, user_uuid_str); uuid_unparse(sb->uuid.b, internal_uuid_str); + mi = bch2_sb_get_members(sb); + if (mi) { + struct bch_member *m; + + for (m = mi->members; + m < mi->members + sb->nr_devices; + m++) + nr_devices += bch2_member_exists(m); + } + + vstruct_for_each(sb, f) + fields_have |= 1 << le32_to_cpu(f->type); + bch2_scnprint_flag_list(fields_have_str, sizeof(fields_have_str), + bch2_sb_fields, fields_have); + printf("External UUID: %s\n" "Internal UUID: %s\n" "Label: %s\n" @@ -331,8 +521,8 @@ void bch2_super_print(struct bch_sb *sb, int units) "Error action: %s\n" "Clean: %llu\n" - "Metadata replicas: have %llu, want %llu\n" - "Data replicas: have %llu, want %llu\n" + "Metadata replicas: %llu\n" + "Data replicas: %llu\n" "Metadata checksum type: %s (%llu)\n" "Data checksum type: %s (%llu)\n" @@ -343,7 +533,9 @@ void bch2_super_print(struct bch_sb *sb, int units) "GC reserve percentage: %llu%%\n" "Root reserve percentage: %llu%%\n" - "Devices: %u\n", + "Devices: %u live, %u total\n" + "Sections: %s\n" + "Superblock size: %llu\n", user_uuid_str, internal_uuid_str, label, @@ -357,9 +549,7 @@ void bch2_super_print(struct bch_sb *sb, int units) BCH_SB_CLEAN(sb), - 0LLU, //BCH_SB_META_REPLICAS_HAVE(sb), BCH_SB_META_REPLICAS_WANT(sb), - 0LLU, //BCH_SB_DATA_REPLICAS_HAVE(sb), BCH_SB_DATA_REPLICAS_WANT(sb), BCH_SB_META_CSUM_TYPE(sb) < BCH_CSUM_OPT_NR @@ -386,73 +576,33 @@ void bch2_super_print(struct bch_sb *sb, int units) BCH_SB_GC_RESERVE(sb), BCH_SB_ROOT_RESERVE(sb), - sb->nr_devices); + nr_devices, sb->nr_devices, + fields_have_str, + vstruct_bytes(sb)); - mi = bch2_sb_get_members(sb); - if (!mi) { - printf("Member info section missing\n"); - return; + if (print_layout) { + printf("\n" + "Layout:\n"); + bch2_sb_print_layout(sb, units); } - for (i = 0; i < sb->nr_devices; i++) { - struct bch_member *m = mi->members + i; - time_t last_mount = le64_to_cpu(m->last_mount); - char member_uuid_str[40]; - char data_allowed_str[100]; - char data_has_str[100]; + vstruct_for_each(sb, f) { + unsigned type = le32_to_cpu(f->type); + char name[60]; - uuid_unparse(m->uuid.b, member_uuid_str); - bch2_scnprint_flag_list(data_allowed_str, - sizeof(data_allowed_str), - bch2_data_types, - BCH_MEMBER_DATA_ALLOWED(m)); - if (!data_allowed_str[0]) - strcpy(data_allowed_str, "(none)"); + if (!(fields & (1 << type))) + continue; - bch2_scnprint_flag_list(data_has_str, - sizeof(data_has_str), - bch2_data_types, - get_dev_has_data(sb, i)); - if (!data_has_str[0]) - strcpy(data_has_str, "(none)"); + if (type < BCH_SB_FIELD_NR) { + scnprintf(name, sizeof(name), "%s", bch2_sb_fields[type]); + name[0] = toupper(name[0]); + } else { + scnprintf(name, sizeof(name), "(unknown field %u)", type); + } - printf("\n" - "Device %u:\n" - " UUID: %s\n" - " Size: %s\n" - " Bucket size: %s\n" - " First bucket: %u\n" - " Buckets: %llu\n" - " Last mount: %s\n" - " State: %s\n" - " Tier: %llu\n" - " Data allowed: %s\n" - - " Has data: %s\n" - - " Replacement policy: %s\n" - " Discard: %llu\n", - i, member_uuid_str, - pr_units(le16_to_cpu(m->bucket_size) * - le64_to_cpu(m->nbuckets), units), - pr_units(le16_to_cpu(m->bucket_size), units), - le16_to_cpu(m->first_bucket), - le64_to_cpu(m->nbuckets), - last_mount ? ctime(&last_mount) : "(never)", - - BCH_MEMBER_STATE(m) < BCH_MEMBER_STATE_NR - ? bch2_dev_state[BCH_MEMBER_STATE(m)] - : "unknown", - - BCH_MEMBER_TIER(m), - data_allowed_str, - data_has_str, - - BCH_MEMBER_REPLACEMENT(m) < CACHE_REPLACEMENT_NR - ? bch2_cache_replacement_policies[BCH_MEMBER_REPLACEMENT(m)] - : "unknown", - - BCH_MEMBER_DISCARD(m)); + printf("\n%s (size %llu):\n", name, vstruct_bytes(f)); + if (type < BCH_SB_FIELD_NR) + bch2_sb_field_print(sb, f, units); } } diff --git a/libbcachefs.h b/libbcachefs.h index 97f4b2d8..dc509833 100644 --- a/libbcachefs.h +++ b/libbcachefs.h @@ -75,7 +75,7 @@ struct bch_sb *bch2_format(struct format_opts, struct dev_opts *, size_t); void bch2_super_write(int, struct bch_sb *); struct bch_sb *__bch2_super_read(int, u64); -void bch2_super_print(struct bch_sb *, int); +void bch2_sb_print(struct bch_sb *, bool, unsigned, enum units); /* ioctl interface: */ diff --git a/tools-util.c b/tools-util.c index d5450495..04bc6bd2 100644 --- a/tools-util.c +++ b/tools-util.c @@ -112,7 +112,22 @@ struct stat xfstat(int fd) return stat; } -/* Integer stuff: */ +/* Formatting: */ + +int printf_pad(unsigned pad, const char * fmt, ...) +{ + va_list args; + int ret; + + va_start(args, fmt); + ret = vprintf(fmt, args); + va_end(args); + + while (ret++ < pad) + putchar(' '); + + return ret; +} struct units_buf __pr_units(s64 _v, enum units units) { diff --git a/tools-util.h b/tools-util.h index dcca376b..dca9be29 100644 --- a/tools-util.h +++ b/tools-util.h @@ -47,6 +47,8 @@ struct stat xfstat(int); _ret; \ }) +int printf_pad(unsigned pad, const char * fmt, ...); + enum units { BYTES, SECTORS, @@ -151,4 +153,18 @@ char *dev_to_name(dev_t); char *dev_to_path(dev_t); char *dev_to_mount(char *); +#define args_shift(_nr) \ +do { \ + argc -= (_nr); \ + argv += (_nr); \ +} while (0) + +#define arg_pop() \ +({ \ + char *_ret = argc ? argv[0] : NULL; \ + if (_ret) \ + args_shift(1); \ + _ret; \ +}) + #endif /* _TOOLS_UTIL_H */