From f3a8d548376295279d2d27fda5764adbe377c55b Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Tue, 4 Oct 2016 01:10:24 -0800 Subject: [PATCH] bcache device_show now dumps superblocks --- Makefile | 2 +- bcache-device.c | 18 ++++ bcache-key.c | 12 +-- bcache-ondisk.h | 21 ++--- bcache.c | 52 ----------- bcache.h | 8 -- libbcache.c | 223 ++++++++++++++++++++++++++++++++++++++++++------ libbcache.h | 13 ++- util.c | 30 +++++++ util.h | 37 ++++++++ 10 files changed, 312 insertions(+), 104 deletions(-) diff --git a/Makefile b/Makefile index 9f2773ec..9b3bdcc2 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ LDFLAGS+=-static PKGCONFIG_LIBS="blkid uuid libnih" CFLAGS+=`pkg-config --cflags ${PKGCONFIG_LIBS}` -LDLIBS+=`pkg-config --libs ${PKGCONFIG_LIBS}` -lscrypt -lsodium -lkeyutils +LDLIBS+=`pkg-config --libs ${PKGCONFIG_LIBS}` -lscrypt -lsodium -lkeyutils -lm ifeq ($(PREFIX),/usr) ROOT_SBINDIR=/sbin diff --git a/bcache-device.c b/bcache-device.c index 1f6f1574..a349e790 100644 --- a/bcache-device.c +++ b/bcache-device.c @@ -16,6 +16,10 @@ #include #include "bcache.h" +#include "libbcache.h" + +/* This code belongs under show_fs */ +#if 0 struct bcache_dev { unsigned nr; @@ -162,6 +166,20 @@ int cmd_device_show(int argc, char *argv[]) return 0; } +#endif + +int cmd_device_show(int argc, char *argv[]) +{ + struct cache_sb *sb; + + if (argc != 2) + die("please supply a single device"); + + sb = bcache_super_read(argv[1]); + bcache_super_print(sb, HUMAN_READABLE); + + return 0; +} int cmd_device_add(int argc, char *argv[]) { diff --git a/bcache-key.c b/bcache-key.c index 34005454..cac09482 100644 --- a/bcache-key.c +++ b/bcache-key.c @@ -18,7 +18,7 @@ int cmd_unlock(int argc, char *argv[]) struct bcache_disk_key disk_key; struct bcache_key key; - struct cache_sb sb; + struct cache_sb *sb; char *passphrase; char uuid[40]; char description[60]; @@ -26,12 +26,12 @@ int cmd_unlock(int argc, char *argv[]) if (!args[0] || args[1]) die("please supply a single device"); - bcache_super_read(args[0], &sb); + sb = bcache_super_read(args[0]); - if (!CACHE_SET_ENCRYPTION_KEY(&sb)) + if (!CACHE_SET_ENCRYPTION_KEY(sb)) die("filesystem is not encrypted"); - memcpy(&disk_key, sb.encryption_key, sizeof(disk_key)); + memcpy(&disk_key, sb->encryption_key, sizeof(disk_key)); if (!memcmp(&disk_key, bch_key_header, sizeof(bch_key_header))) die("filesystem does not have encryption key"); @@ -39,12 +39,12 @@ int cmd_unlock(int argc, char *argv[]) passphrase = read_passphrase("Enter passphrase: "); derive_passphrase(&key, passphrase); - disk_key_encrypt(&sb, &disk_key, &key); + disk_key_encrypt(sb, &disk_key, &key); if (memcmp(&disk_key, bch_key_header, sizeof(bch_key_header))) die("incorrect passphrase"); - uuid_unparse_lower(sb.user_uuid.b, uuid); + uuid_unparse_lower(sb->user_uuid.b, uuid); sprintf(description, "bcache:%s", uuid); if (add_key("logon", description, &key, sizeof(key), diff --git a/bcache-ondisk.h b/bcache-ondisk.h index 4ceb10bb..f737511f 100644 --- a/bcache-ondisk.h +++ b/bcache-ondisk.h @@ -670,6 +670,7 @@ LE64_BITMASK(CACHE_STATE, struct cache_member, f1, 0, 4) #define CACHE_RO 1U #define CACHE_FAILED 2U #define CACHE_SPARE 3U +#define CACHE_STATE_NR 4U LE64_BITMASK(CACHE_TIER, struct cache_member, f1, 4, 8) #define CACHE_TIERS 4U @@ -683,6 +684,7 @@ LE64_BITMASK(CACHE_REPLACEMENT, struct cache_member, f1, 26, 30) #define CACHE_REPLACEMENT_LRU 0U #define CACHE_REPLACEMENT_FIFO 1U #define CACHE_REPLACEMENT_RANDOM 2U +#define CACHE_REPLACEMENT_NR 3U LE64_BITMASK(CACHE_DISCARD, struct cache_member, f1, 30, 31); @@ -770,18 +772,7 @@ LE64_BITMASK(CACHE_SET_META_CSUM_TYPE,struct cache_sb, flags, 16, 20); #define BCH_CSUM_NONE 0U #define BCH_CSUM_CRC32C 1U #define BCH_CSUM_CRC64 2U -#define BCH_CSUM_CHACHA20_POLY1305 3U -#define BCH_CSUM_NR 4U - -static inline _Bool bch_csum_type_is_encryption(unsigned type) -{ - switch (type) { - case BCH_CSUM_CHACHA20_POLY1305: - return 1; - default: - return 0; - } -} +#define BCH_CSUM_NR 3U LE64_BITMASK(CACHE_SET_BTREE_NODE_SIZE, struct cache_sb, flags, 20, 36); @@ -816,6 +807,12 @@ LE64_BITMASK(CACHE_SET_GC_RESERVE, struct cache_sb, flags, 57, 63); LE64_BITMASK(CACHE_SET_ROOT_RESERVE, struct cache_sb, flags2, 0, 6); +/* + * Did we shut down cleanly? Just a hint, doesn't affect behaviour of + * mount/recovery path: + */ +LE64_BITMASK(CACHE_SET_CLEAN, struct cache_sb, flags2, 6, 7); + /* * If nonzero, encryption is enabled; overrides DATA/META_CSUM_TYPE. Also * indicates encryption algorithm in use, if/when we get more than one: diff --git a/bcache.c b/bcache.c index 532194d1..04955b34 100644 --- a/bcache.c +++ b/bcache.c @@ -23,58 +23,6 @@ #include "bcache.h" -const char * const cache_state[] = { - "active", - "ro", - "failed", - "spare", - NULL -}; - -const char * const replacement_policies[] = { - "lru", - "fifo", - "random", - NULL -}; - -const char * const csum_types[] = { - "none", - "crc32c", - "crc64", - NULL -}; - -const char * const compression_types[] = { - "none", - "lz4", - "gzip", - NULL -}; - -const char * const error_actions[] = { - "continue", - "readonly", - "panic", - NULL -}; - -const char * const bdev_cache_mode[] = { - "writethrough", - "writeback", - "writearound", - "none", - NULL -}; - -const char * const bdev_state[] = { - "detached", - "clean", - "dirty", - "inconsistent", - NULL -}; - static void usage(void) { puts("bcache - tool for managing bcache volumes/filesystems\n" diff --git a/bcache.h b/bcache.h index 69d3edc3..949f6094 100644 --- a/bcache.h +++ b/bcache.h @@ -9,14 +9,6 @@ #include "util.h" -extern const char * const cache_state[]; -extern const char * const replacement_policies[]; -extern const char * const csum_types[]; -extern const char * const compression_types[]; -extern const char * const error_actions[]; -extern const char * const bdev_cache_mode[]; -extern const char * const bdev_state[]; - int cmd_format(int argc, char *argv[]); int cmd_unlock(int argc, char *argv[]); diff --git a/libbcache.c b/libbcache.c index f17bd4ad..865b780e 100644 --- a/libbcache.c +++ b/libbcache.c @@ -17,6 +17,74 @@ #include "libbcache.h" #include "crypto.h" +const char * const cache_state[] = { + "active", + "ro", + "failed", + "spare", + NULL +}; + +const char * const replacement_policies[] = { + "lru", + "fifo", + "random", + NULL +}; + +const char * const csum_types[] = { + "none", + "crc32c", + "crc64", + NULL +}; + +const char * const compression_types[] = { + "none", + "lz4", + "gzip", + NULL +}; + +const char * const str_hash_types[] = { + "crc32c", + "crc64", + "siphash", + "sha1", + NULL +}; + +const char * const error_actions[] = { + "continue", + "readonly", + "panic", + NULL +}; + +const char * const member_states[] = { + "active", + "ro", + "failed", + "spare", + NULL +}; + +const char * const bdev_cache_mode[] = { + "writethrough", + "writeback", + "writearound", + "none", + NULL +}; + +const char * const bdev_state[] = { + "detached", + "clean", + "dirty", + "inconsistent", + NULL +}; + #define BCH_MIN_NR_NBUCKETS (1 << 10) /* first bucket should start 1 mb in, in sectors: */ @@ -187,48 +255,155 @@ void bcache_format(struct dev_opts *devs, size_t nr_devs, for (i = devs; i < devs + nr_devs; i++) { struct cache_member *m = sb->members + (i - devs); - char uuid_str[40], set_uuid_str[40]; sb->disk_uuid = m->uuid; sb->nr_this_dev = i - devs; sb->csum = __cpu_to_le64(__csum_set(sb, __le16_to_cpu(sb->u64s), CACHE_SB_CSUM_TYPE(sb))); - uuid_unparse(sb->disk_uuid.b, uuid_str); - uuid_unparse(sb->user_uuid.b, set_uuid_str); - printf("UUID: %s\n" - "Set UUID: %s\n" - "version: %u\n" - "nbuckets: %llu\n" - "block_size: %u\n" - "bucket_size: %u\n" - "nr_in_set: %u\n" - "nr_this_dev: %u\n" - "first_bucket: %u\n", - uuid_str, set_uuid_str, - (unsigned) sb->version, - __le64_to_cpu(m->nbuckets), - __le16_to_cpu(sb->block_size), - __le16_to_cpu(m->bucket_size), - sb->nr_in_set, - sb->nr_this_dev, - __le16_to_cpu(m->first_bucket)); - do_write_sb(i->fd, sb); } + bcache_super_print(sb, HUMAN_READABLE); + free(sb); } -void bcache_super_read(const char *path, struct cache_sb *sb) +void bcache_super_print(struct cache_sb *sb, int units) { + unsigned i; + char user_uuid_str[40], internal_uuid_str[40], member_uuid_str[40]; + char label[SB_LABEL_SIZE + 1]; + + memset(label, 0, sizeof(label)); + memcpy(label, sb->label, sizeof(sb->label)); + uuid_unparse(sb->user_uuid.b, user_uuid_str); + uuid_unparse(sb->set_uuid.b, internal_uuid_str); + + printf("External UUID: %s\n" + "Internal UUID: %s\n" + "Label: %s\n" + "Version: %llu\n" + "Block_size: %s\n" + "Btree node size: %s\n" + "Error action: %s\n" + "Clean: %llu\n" + + "Metadata replicas: have %llu, want %llu\n" + "Data replicas: have %llu, want %llu\n" + + "Metadata checksum type: %s\n" + "Data checksum type: %s\n" + "Compression type: %s\n" + + "String hash type: %s\n" + "32 bit inodes: %llu\n" + "GC reserve percentage: %llu%%\n" + "Root reserve percentage: %llu%%\n" + + "Devices: %u\n", + user_uuid_str, + internal_uuid_str, + label, + le64_to_cpu(sb->version), + pr_units(le16_to_cpu(sb->block_size), units).b, + pr_units(CACHE_SET_BTREE_NODE_SIZE(sb), units).b, + + CACHE_SET_ERROR_ACTION(sb) < BCH_NR_ERROR_ACTIONS + ? error_actions[CACHE_SET_ERROR_ACTION(sb)] + : "unknown", + + CACHE_SET_CLEAN(sb), + + CACHE_SET_META_REPLICAS_HAVE(sb), + CACHE_SET_META_REPLICAS_WANT(sb), + CACHE_SET_DATA_REPLICAS_HAVE(sb), + CACHE_SET_DATA_REPLICAS_WANT(sb), + + CACHE_SET_META_CSUM_TYPE(sb) < BCH_CSUM_NR + ? csum_types[CACHE_SET_META_CSUM_TYPE(sb)] + : "unknown", + + CACHE_SET_DATA_CSUM_TYPE(sb) < BCH_CSUM_NR + ? csum_types[CACHE_SET_DATA_CSUM_TYPE(sb)] + : "unknown", + + CACHE_SET_COMPRESSION_TYPE(sb) < BCH_COMPRESSION_NR + ? compression_types[CACHE_SET_COMPRESSION_TYPE(sb)] + : "unknown", + + CACHE_SET_STR_HASH_TYPE(sb) < BCH_STR_HASH_NR + ? str_hash_types[CACHE_SET_STR_HASH_TYPE(sb)] + : "unknown", + + CACHE_INODE_32BIT(sb), + CACHE_SET_GC_RESERVE(sb), + CACHE_SET_ROOT_RESERVE(sb), + + sb->nr_in_set); + + for (i = 0; i < sb->nr_in_set; i++) { + struct cache_member *m = sb->members + i; + time_t last_mount = le64_to_cpu(m->last_mount); + + uuid_unparse(m->uuid.b, member_uuid_str); + + printf("\n" + "Device %u:\n" + " UUID: %s\n" + " bucket_size: %s\n" + " first_bucket: %u\n" + " nbuckets: %llu\n" + " Last mount: %s\n" + " State: %s\n" + " Tier: %llu\n" + " Has metadata: %llu\n" + " Has data: %llu\n" + " Replacement policy: %s\n" + " Discard: %llu\n", + i, member_uuid_str, + pr_units(le16_to_cpu(m->bucket_size), units).b, + le16_to_cpu(m->first_bucket), + le64_to_cpu(m->nbuckets), + last_mount ? ctime(&last_mount) : "(never)", + + CACHE_STATE(m) < CACHE_STATE_NR + ? member_states[CACHE_STATE(m)] + : "unknown", + + CACHE_TIER(m), + CACHE_HAS_METADATA(m), + CACHE_HAS_DATA(m), + + CACHE_REPLACEMENT(m) < CACHE_REPLACEMENT_NR + ? replacement_policies[CACHE_REPLACEMENT(m)] + : "unknown", + + CACHE_DISCARD(m)); + } +} + +struct cache_sb *bcache_super_read(const char *path) +{ + struct cache_sb sb, *ret; + size_t bytes; + int fd = open(path, O_RDONLY); if (fd < 0) die("couldn't open %s", path); - if (pread(fd, sb, sizeof(*sb), SB_SECTOR << 9) != sizeof(*sb)) + if (pread(fd, &sb, sizeof(sb), SB_SECTOR << 9) != sizeof(sb)) die("error reading superblock"); - if (memcmp(&sb->magic, &BCACHE_MAGIC, sizeof(sb->magic))) + if (memcmp(&sb.magic, &BCACHE_MAGIC, sizeof(sb.magic))) die("not a bcache superblock"); + + bytes = sizeof(sb) + le16_to_cpu(sb.u64s) * sizeof(u64); + + ret = calloc(1, bytes); + + if (pread(fd, ret, bytes, SB_SECTOR << 9) != bytes) + die("error reading superblock"); + + return ret; } diff --git a/libbcache.h b/libbcache.h index ccfa37cb..920a9c51 100644 --- a/libbcache.h +++ b/libbcache.h @@ -4,6 +4,15 @@ #include "util.h" #include "stdbool.h" +extern const char * const cache_state[]; +extern const char * const replacement_policies[]; +extern const char * const csum_types[]; +extern const char * const compression_types[]; +extern const char * const str_hash_types[]; +extern const char * const error_actions[]; +extern const char * const bdev_cache_mode[]; +extern const char * const bdev_state[]; + struct dev_opts { int fd; const char *path; @@ -29,6 +38,8 @@ void bcache_format(struct dev_opts *devs, size_t nr_devs, char *label, uuid_le uuid); -void bcache_super_read(const char *, struct cache_sb *); +void bcache_super_print(struct cache_sb *, int); + +struct cache_sb *bcache_super_read(const char *); #endif /* _LIBBCACHE_H */ diff --git a/util.c b/util.c index bd332b5b..d30693c1 100644 --- a/util.c +++ b/util.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -69,6 +70,35 @@ char *strim(char *s) return s; } +struct units_buf pr_units(u64 v, enum units units) +{ + struct units_buf ret; + + switch (units) { + case BYTES: + snprintf(ret.b, sizeof(ret.b), "%llu", v << 9); + break; + case SECTORS: + snprintf(ret.b, sizeof(ret.b), "%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", + v / pow(1024, exp), + "KMGTPE"[exp-1]); + } else { + snprintf(ret.b, sizeof(ret.b), "%llu", v); + } + + break; + } + + return ret; +} + /* Argument parsing stuff: */ long strtoul_or_die(const char *p, size_t max, const char *msg) diff --git a/util.h b/util.h index 463416a9..a8e18f90 100644 --- a/util.h +++ b/util.h @@ -9,6 +9,7 @@ /* linux kernel style types: */ #include +#include typedef __u8 u8; typedef __u16 u16; @@ -20,6 +21,29 @@ typedef __s16 s16; typedef __s32 s32; typedef __s64 s64; +#define cpu_to_le16 __cpu_to_le16 +#define cpu_to_le32 __cpu_to_le32 +#define cpu_to_le64 __cpu_to_le64 + +#define le16_to_cpu __le16_to_cpu +#define le32_to_cpu __le32_to_cpu +#define le64_to_cpu __le64_to_cpu + +static inline void le16_add_cpu(__le16 *var, u16 val) +{ + *var = cpu_to_le16(le16_to_cpu(*var) + val); +} + +static inline void le32_add_cpu(__le32 *var, u32 val) +{ + *var = cpu_to_le32(le32_to_cpu(*var) + val); +} + +static inline void le64_add_cpu(__le64 *var, u64 val) +{ + *var = cpu_to_le64(le64_to_cpu(*var) + val); +} + #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) #define min(x, y) ({ \ @@ -46,7 +70,20 @@ unsigned ilog2(u64); char *skip_spaces(const char *str); char *strim(char *s); +enum units { + BYTES, + SECTORS, + HUMAN_READABLE, +}; + +struct units_buf pr_units(u64, enum units); + +struct units_buf { + char b[20]; +}; + long strtoul_or_die(const char *, size_t, const char *); + u64 hatoi(const char *); unsigned hatoi_validate(const char *, const char *); unsigned nr_args(char * const *);