show-super can now print more stuff

This commit is contained in:
Kent Overstreet 2017-12-29 21:14:51 -05:00
parent 88242ec7a3
commit dbad1685bc
7 changed files with 327 additions and 107 deletions

View 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;

View 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;
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;
}

View File

@ -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;

View 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);
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);
}
}

View 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: */

View 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)
{

View 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 */