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 =
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;
}
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);
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;
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) {
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;
}
+#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
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"
"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"
"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,
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
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);
}
}