From 30caf69540dfb3913e8b5c0359f7714dd52a08cb Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Sat, 23 Dec 2017 00:50:55 -0500 Subject: [PATCH] Add bcachefs fs usage --- bcachefs.c | 9 ++-- cmd_fs.c | 146 ++++++++++++++++++++++++++++++++++++++++----------- cmds.h | 3 +- tools-util.c | 67 ++++++++++++++++++++--- tools-util.h | 8 ++- 5 files changed, 185 insertions(+), 48 deletions(-) diff --git a/bcachefs.c b/bcachefs.c index 5dae387d..79533411 100644 --- a/bcachefs.c +++ b/bcachefs.c @@ -42,8 +42,7 @@ static void usage(void) " stop Stop a running filesystem\n" "\n" "Commands for managing a running filesystem:\n" - " fs show Show various information about a filesystem\n" - " fs set Modify filesystem options\n" + " fs usage Show disk usage\n" "\n" "Commands for managing devices within a running filesystem:\n" " device add Add a new device to an existing filesystem\n" @@ -90,10 +89,8 @@ static int fs_cmds(int argc, char *argv[]) { char *cmd = pop_cmd(&argc, argv); - if (!strcmp(cmd, "show")) - return cmd_fs_show(argc, argv); - if (!strcmp(cmd, "set")) - return cmd_fs_set(argc, argv); + if (!strcmp(cmd, "usage")) + return cmd_fs_usage(argc, argv); usage(); return 0; diff --git a/cmd_fs.c b/cmd_fs.c index a332db3d..65ee539e 100644 --- a/cmd_fs.c +++ b/cmd_fs.c @@ -1,43 +1,125 @@ +#include +#include + +#include + +#include "libbcachefs/bcachefs_ioctl.h" +#include "libbcachefs/opts.h" + #include "cmds.h" -struct bcache_fs { - /* options... */ - - u64 capacity; - - /* XXX: dirty != used, it doesn't count metadata */ - u64 bytes_dirty; -}; - -#if 0 -static struct bcache_fs fill_fs(struct bcache_handle fs) +static inline int printf_pad(unsigned pad, const char * fmt, ...) { - return (struct bcache_fs) { - }; + va_list args; + int ret; + + va_start(args, fmt); + ret = vprintf(fmt, args); + va_end(args); + + while (ret++ < pad) + putchar(' '); + + return ret; } -#endif -int cmd_fs_show(int argc, char *argv[]) +static void print_fs_usage(const char *path, enum units units) { - if (argc != 2) - die("Please supply a filesystem"); + unsigned i, j, nr_devices = 4; + struct bcache_handle fs = bcache_fs_open(path); + struct bch_ioctl_usage *u = NULL; + char uuid[40]; -#if 0 - struct bcache_handle fs = bcache_fs_open(argv[1]); -#endif - - return 0; -} - -int cmd_fs_set(int argc, char *argv[]) -{ - if (argc != 2) - die("Please supply a filesystem"); - -#if 0 - struct bcache_handle fs = bcache_fs_open(argv[1]); -#endif + while (1) { + u = xrealloc(u, sizeof(*u) + sizeof(u->devs[0]) * nr_devices); + u->nr_devices = nr_devices; + + if (!ioctl(fs.ioctl_fd, BCH_IOCTL_USAGE, u)) + break; + if (errno != ENOSPC) + die("BCH_IOCTL_USAGE error: %m"); + nr_devices *= 2; + } + + uuid_unparse(fs.uuid.b, uuid); + printf("Filesystem %s:\n", uuid); + + printf("%-20s%12s\n", "Size:", pr_units(u->fs.capacity, units)); + printf("%-20s%12s\n", "Used:", pr_units(u->fs.used, units)); + + printf("%-20s%12s%12s%12s%12s\n", + "By replicas:", "1x", "2x", "3x", "4x"); + + for (j = BCH_DATA_BTREE; j < BCH_DATA_NR; j++) { + printf_pad(20, " %s:", bch2_data_types[j]); + + for (i = 0; i < BCH_REPLICAS_MAX; i++) + printf("%12s", pr_units(u->fs.sectors[j][i], units)); + printf("\n"); + } + + printf_pad(20, " %s:", "reserved"); + for (i = 0; i < BCH_REPLICAS_MAX; i++) + printf("%12s", pr_units(u->fs.persistent_reserved[i], units)); + printf("\n"); + + printf("%-20s%12s\n", " online reserved:", pr_units(u->fs.online_reserved, units)); + + for (i = 0; i < u->nr_devices; i++) { + struct bch_ioctl_dev_usage *d = u->devs + i; + char *name = NULL; + + if (!d->alive) + continue; + + printf("\n"); + printf_pad(20, "Device %u usage:", i); + name = !d->dev ? strdup("(offline)") + : dev_to_path(d->dev) + ?: strdup("(device not found)"); + + printf("%24s%12s\n", name, bch2_dev_state[d->state]); + free(name); + + printf("%-20s%12s%12s%12s\n", + "", "data", "buckets", "fragmented"); + + for (j = BCH_DATA_SB; j < BCH_DATA_NR; j++) { + u64 frag = max((s64) d->buckets[j] * d->bucket_size - + (s64) d->sectors[j], 0LL); + + printf_pad(20, " %s:", bch2_data_types[j]); + printf("%12s%12llu%12s\n", + pr_units(d->sectors[j], units), + d->buckets[j], + pr_units(frag, units)); + } + } + + free(u); + bcache_fs_close(fs); +} + +int cmd_fs_usage(int argc, char *argv[]) +{ + enum units units = BYTES; + unsigned i; + int opt; + + while ((opt = getopt(argc, argv, "h")) != -1) + switch (opt) { + case 'h': + units = HUMAN_READABLE; + break; + } + + if (argc - optind < 1) { + print_fs_usage(".", units); + } else { + for (i = optind; i < argc; i++) + print_fs_usage(argv[i], units); + } return 0; } diff --git a/cmds.h b/cmds.h index fa28904c..1c07e072 100644 --- a/cmds.h +++ b/cmds.h @@ -17,8 +17,7 @@ int cmd_incremental(int argc, char *argv[]); int cmd_run(int argc, char *argv[]); int cmd_stop(int argc, char *argv[]); -int cmd_fs_show(int argc, char *argv[]); -int cmd_fs_set(int argc, char *argv[]); +int cmd_fs_usage(int argc, char *argv[]); int cmd_device_add(int argc, char *argv[]); int cmd_device_remove(int argc, char *argv[]); diff --git a/tools-util.c b/tools-util.c index 90bbda2a..70f5558b 100644 --- a/tools-util.c +++ b/tools-util.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -70,6 +71,15 @@ void *xmalloc(size_t size) return p; } +void *xrealloc(void *p, size_t size) +{ + p = realloc(p, size); + if (!p) + die("insufficient memory"); + + return p; +} + void xpread(int fd, void *buf, size_t count, off_t offset) { ssize_t r = pread(fd, buf, count, offset); @@ -104,27 +114,34 @@ struct stat xfstat(int fd) /* Integer stuff: */ -struct units_buf __pr_units(u64 v, enum units units) +struct units_buf __pr_units(s64 _v, enum units units) { struct units_buf ret; + char *out = ret.b, *end = out + sizeof(ret.b); + u64 v = _v; + + if (_v < 0) { + out += scnprintf(out, end - out, "-"); + v = -_v; + } switch (units) { case BYTES: - snprintf(ret.b, sizeof(ret.b), "%llu", v << 9); + snprintf(out, end - out, "%llu", v << 9); break; case SECTORS: - snprintf(ret.b, sizeof(ret.b), "%llu", v); + snprintf(out, end - out, "%llu", v); break; case HUMAN_READABLE: v <<= 9; if (v >= 1024) { int exp = log(v) / log(1024); - snprintf(ret.b, sizeof(ret.b), "%.1f%c", + snprintf(out, end - out, "%.1f%c", v / pow(1024, exp), "KMGTPE"[exp-1]); } else { - snprintf(ret.b, sizeof(ret.b), "%llu", v); + snprintf(out, end - out, "%llu", v); } break; @@ -255,12 +272,17 @@ int bcachectl_open(void) #define SYSFS_BASE "/sys/fs/bcachefs/" +void bcache_fs_close(struct bcache_handle fs) +{ + close(fs.ioctl_fd); + close(fs.sysfs_fd); +} + struct bcache_handle bcache_fs_open(const char *path) { struct bcache_handle ret; - uuid_t tmp; - if (!uuid_parse(path, tmp)) { + if (!uuid_parse(path, ret.uuid.b)) { /* It's a UUID, look it up in sysfs: */ char *sysfs = mprintf("%s%s", SYSFS_BASE, path); ret.sysfs_fd = xopen(sysfs, O_RDONLY); @@ -279,6 +301,8 @@ struct bcache_handle bcache_fs_open(const char *path) struct bch_ioctl_query_uuid uuid; xioctl(ret.ioctl_fd, BCH_IOCTL_QUERY_UUID, &uuid); + ret.uuid = uuid.uuid; + char uuid_str[40]; uuid_unparse(uuid.uuid.b, uuid_str); @@ -562,4 +586,33 @@ u32 crc32c(u32 crc, const void *buf, size_t size) #endif /* HAVE_WORKING_IFUNC */ +char *dev_to_path(dev_t dev) +{ + char *line = NULL, *name = NULL, *path = NULL; + size_t n = 0; + + FILE *f = fopen("/proc/partitions", "r"); + if (!f) + die("error opening /proc/partitions: %m"); + + while (getline(&line, &n, f) != -1) { + unsigned ma, mi; + u64 sectors; + + name = realloc(name, n + 1); + + if (sscanf(line, " %u %u %llu %s", &ma, &mi, §ors, name) == 4 && + ma == major(dev) && mi == minor(dev)) { + path = mprintf("/dev/%s", name); + break; + } + + } + + fclose(f); + free(line); + free(name); + return path; +} + #endif diff --git a/tools-util.h b/tools-util.h index c8ece0c8..649ea9bb 100644 --- a/tools-util.h +++ b/tools-util.h @@ -15,12 +15,14 @@ #include #include #include +#include #include "ccan/darray/darray.h" void die(const char *, ...); char *mprintf(const char *, ...); void *xcalloc(size_t, size_t); void *xmalloc(size_t); +void *xrealloc(void *, size_t); void xpread(int, void *, size_t, off_t); void xpwrite(int, const void *, size_t, off_t); struct stat xfstatat(int, const char *, int); @@ -48,7 +50,7 @@ enum units { HUMAN_READABLE, }; -struct units_buf __pr_units(u64, enum units); +struct units_buf __pr_units(s64, enum units); struct units_buf { char b[20]; @@ -69,10 +71,12 @@ int open_for_format(const char *, bool); int bcachectl_open(void); struct bcache_handle { + uuid_le uuid; int ioctl_fd; int sysfs_fd; }; +void bcache_fs_close(struct bcache_handle); struct bcache_handle bcache_fs_open(const char *); bool ask_yn(void); @@ -151,4 +155,6 @@ unsigned hatoi_validate(const char *, const char *); u32 crc32c(u32, const void *, size_t); +char *dev_to_path(dev_t); + #endif /* _TOOLS_UTIL_H */