summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2016-10-04 01:10:24 -0800
committerKent Overstreet <kent.overstreet@gmail.com>2016-10-06 06:52:54 -0800
commitf3a8d548376295279d2d27fda5764adbe377c55b (patch)
treeb3cb6b8e547fe419427d0490aa88c62bbfa454ae
parent837a476cc139167fc483016f0a2635a048f7709e (diff)
bcache device_show now dumps superblocks
-rw-r--r--Makefile2
-rw-r--r--bcache-device.c18
-rw-r--r--bcache-key.c12
-rw-r--r--bcache-ondisk.h21
-rw-r--r--bcache.c52
-rw-r--r--bcache.h8
-rw-r--r--libbcache.c223
-rw-r--r--libbcache.h13
-rw-r--r--util.c30
-rw-r--r--util.h37
10 files changed, 312 insertions, 104 deletions
diff --git a/Makefile b/Makefile
index 9f2773e..9b3bdcc 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 1f6f157..a349e79 100644
--- a/bcache-device.c
+++ b/bcache-device.c
@@ -16,6 +16,10 @@
#include <nih/option.h>
#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 3400545..cac0948 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 4ceb10b..f737511 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);
@@ -817,6 +808,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 532194d..04955b3 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 69d3edc..949f609 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 f17bd4a..865b780 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 ccfa37c..920a9c5 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 bd332b5..d30693c 100644
--- a/util.c
+++ b/util.c
@@ -4,6 +4,7 @@
#include <fcntl.h>
#include <limits.h>
#include <linux/fs.h>
+#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@@ -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 463416a..a8e18f9 100644
--- a/util.h
+++ b/util.h
@@ -9,6 +9,7 @@
/* linux kernel style types: */
#include <asm/types.h>
+#include <asm/byteorder.h>
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 *);