]> git.sesse.net Git - bcachefs-tools-debian/commitdiff
show-super can now print more stuff
authorKent Overstreet <kent.overstreet@gmail.com>
Sat, 30 Dec 2017 02:14:51 +0000 (21:14 -0500)
committerKent Overstreet <kent.overstreet@gmail.com>
Sat, 30 Dec 2017 02:15:47 +0000 (21:15 -0500)
cmd_device.c
cmd_format.c
cmd_fs.c
libbcachefs.c
libbcachefs.h
tools-util.c
tools-util.h

index f8e0cfbfb75494bb18254034e9dabbb323d97019..22ab016f63d8ee358d0efdedeeb65d76d1b9af6d 100644 (file)
@@ -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;
index b22fe9461b6080c56c5c8a55d806256c3c56de46..476176605695ad8cd6a258b7b55c154be8a9c174 100644 (file)
@@ -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 <linux-bcache@vger.kernel.org>");
+       exit(EXIT_SUCCESS);
+}
+
 int cmd_show_super(int argc, char *argv[])
 {
-       struct bch_sb_handle sb;
-       const char *err;
+       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;
 
-       if (argc != 2)
-               die("please supply a single device");
+       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");
 
-       err = bch2_read_super(argv[1], bch2_opts_empty(), &sb);
+       const char *err;
+       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;
 }
index 3f64161f70a530a6e4469dabdadd01becd48fd24..964d1b04f9dda080a83303e20539452f3a4f1dd2 100644 (file)
--- a/cmd_fs.c
+++ b/cmd_fs.c
 #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;
index afbc8d7afa596796c225c179bfd695fa4e874146..1481ef382583ab0e899e1f726234742ff4a57e8c 100644 (file)
@@ -1,3 +1,4 @@
+#include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdbool.h>
@@ -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);
-
-       mi = bch2_sb_get_members(sb);
-       if (!mi) {
-               printf("Member info section missing\n");
-               return;
-       }
-
-       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];
-
-               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)");
+              nr_devices, sb->nr_devices,
+              fields_have_str,
+              vstruct_bytes(sb));
 
+       if (print_layout) {
                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)",
+                      "Layout:\n");
+               bch2_sb_print_layout(sb, units);
+       }
 
-                      BCH_MEMBER_STATE(m) < BCH_MEMBER_STATE_NR
-                      ? bch2_dev_state[BCH_MEMBER_STATE(m)]
-                      : "unknown",
+       vstruct_for_each(sb, f) {
+               unsigned type = le32_to_cpu(f->type);
+               char name[60];
 
-                      BCH_MEMBER_TIER(m),
-                      data_allowed_str,
-                      data_has_str,
+               if (!(fields & (1 << type)))
+                       continue;
 
-                      BCH_MEMBER_REPLACEMENT(m) < CACHE_REPLACEMENT_NR
-                      ? bch2_cache_replacement_policies[BCH_MEMBER_REPLACEMENT(m)]
-                      : "unknown",
+               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);
+               }
 
-                      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);
        }
 }
 
index 97f4b2d8346088b4eaa19da88f82f56497db89df..dc5098339eb22bdb1eeddd0c70faa15e0d4d4390 100644 (file)
@@ -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: */
 
index d545049552ced523a80c20e8d86262a1b48f0320..04bc6bd2a8c26c600646370204dc1c8ee9a316e7 100644 (file)
@@ -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)
 {
index dcca376b8e4a80925514eda482d6e1c0041d20df..dca9be292f311785588c391557f9abd0754bee3a 100644 (file)
@@ -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 */