summaryrefslogtreecommitdiff
path: root/bcacheadm-format.c
diff options
context:
space:
mode:
Diffstat (limited to 'bcacheadm-format.c')
-rw-r--r--bcacheadm-format.c318
1 files changed, 229 insertions, 89 deletions
diff --git a/bcacheadm-format.c b/bcacheadm-format.c
index 52acc09..a8d4fc3 100644
--- a/bcacheadm-format.c
+++ b/bcacheadm-format.c
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
+#include <unistd.h>
#include <uuid/uuid.h>
@@ -44,7 +45,10 @@ static struct cache_opts {
unsigned tier;
unsigned replacement_policy;
unsigned replication_set;
- uint64_t filesystem_size;
+ u64 filesystem_size;
+
+ u64 first_bucket;
+ u64 nbuckets;
} cache_devices[MAX_DEVS];
static struct backingdev_opts {
@@ -59,16 +63,17 @@ static char *label = NULL;
/* All in units of 512 byte sectors */
static unsigned block_size, bucket_size, btree_node_size;
-static uint64_t filesystem_size;
+static u64 filesystem_size;
static unsigned tier, replacement_policy;
-static uuid_t cache_set_uuid;
+static uuid_le set_uuid, user_uuid;
static unsigned csum_type = BCH_CSUM_CRC32C;
static unsigned replication_set, meta_replicas = 1, data_replicas = 1;
static unsigned on_error_action;
static int discard;
+static unsigned version = 1;
-static uint64_t data_offset = BDEV_DATA_START_DEFAULT;
+static u64 data_offset = BDEV_DATA_START_DEFAULT;
static unsigned cache_mode = CACHE_MODE_WRITEBACK;
static int set_cache(NihOption *option, const char *arg)
@@ -90,14 +95,14 @@ static int set_bdev(NihOption *option, const char *arg)
backing_devices[nr_backing_devices++] = (struct backingdev_opts) {
.fd = dev_open(arg),
.dev = strdup(arg),
- .label = strdup(label),
+ .label = label ? strdup(label) : NULL,
};
return 0;
}
static int set_cache_set_uuid(NihOption *option, const char *arg)
{
- if (uuid_parse(arg, cache_set_uuid))
+ if (uuid_parse(arg, user_uuid.b))
die("Bad uuid");
return 0;
}
@@ -180,6 +185,12 @@ static int set_cache_mode(NihOption *option, const char *arg)
return 0;
}
+static int set_version(NihOption *option, const char *arg)
+{
+ version = strtoul_or_die(arg, 2, "version");
+ return 0;
+}
+
NihOption opts_format[] = {
// { int shortoption, char *longoption, char *help, NihOptionGroup, char *argname, void *value, NihOptionSetter}
@@ -232,6 +243,9 @@ NihOption opts_format[] = {
{ 'o', "data_offset", N_("data offset in sectors"),
NULL, "offset", &data_offset, NULL},
+ { 'v', "version", N_("superblock version"),
+ NULL, "#", NULL, set_version},
+
NIH_OPTION_LAST
};
@@ -247,7 +261,7 @@ static unsigned rounddown_pow_of_two(unsigned n)
return ret;
}
-static unsigned ilog2(uint64_t n)
+static unsigned ilog2(u64 n)
{
unsigned ret = 0;
@@ -259,95 +273,163 @@ static unsigned ilog2(uint64_t n)
return ret;
}
-static int format_v0(void)
+void __do_write_sb(int fd, void *sb, size_t bytes)
{
- return 0;
+ char zeroes[SB_START] = {0};
+
+ /* Zero start of disk */
+ if (pwrite(fd, zeroes, SB_START, 0) != SB_START) {
+ perror("write error trying to zero start of disk\n");
+ exit(EXIT_FAILURE);
+ }
+ /* Write superblock */
+ if (pwrite(fd, sb, bytes, SB_START) != bytes) {
+ perror("write error trying to write superblock\n");
+ exit(EXIT_FAILURE);
+ }
+
+ fsync(fd);
+ close(fd);
}
-static int format_v1(void)
+#define do_write_sb(_fd, _sb) \
+ __do_write_sb(_fd, _sb, ((void *) __bset_bkey_last(_sb)) - (void *) _sb);
+
+void write_backingdev_sb(int fd, unsigned block_size, unsigned mode,
+ u64 data_offset, const char *label,
+ uuid_le set_uuid)
{
- struct cache_sb *cache_set_sb;
+ char uuid_str[40];
+ struct cache_sb sb;
- if (!block_size) {
- for (struct cache_opts *i = cache_devices;
- i < cache_devices + nr_cache_devices;
- i++)
- block_size = max(block_size, get_blocksize(i->dev, i->fd));
+ memset(&sb, 0, sizeof(struct cache_sb));
- for (struct backingdev_opts *i = backing_devices;
- i < backing_devices + nr_backing_devices;
- i++)
- block_size = max(block_size, get_blocksize(i->dev, i->fd));
+ sb.offset = SB_SECTOR;
+ sb.version = BCACHE_SB_VERSION_BDEV;
+ sb.magic = BCACHE_MAGIC;
+ uuid_generate(sb.disk_uuid.b);
+ sb.set_uuid = set_uuid;
+ sb.block_size = block_size;
+
+ uuid_unparse(sb.disk_uuid.b, uuid_str);
+ if (label)
+ memcpy(sb.label, label, SB_LABEL_SIZE);
+
+ SET_BDEV_CACHE_MODE(&sb, mode);
+
+ if (data_offset != BDEV_DATA_START_DEFAULT) {
+ sb.version = BCACHE_SB_VERSION_BDEV_WITH_OFFSET;
+ sb.bdev_data_offset = data_offset;
}
+ sb.csum = csum_set(&sb, BCH_CSUM_CRC64);
+
+ printf("UUID: %s\n"
+ "version: %u\n"
+ "block_size: %u\n"
+ "data_offset: %llu\n",
+ uuid_str, (unsigned) sb.version,
+ sb.block_size, data_offset);
+
+ do_write_sb(fd, &sb);
+}
+
+static void format_v0(void)
+{
+ set_uuid = user_uuid;
+
for (struct cache_opts *i = cache_devices;
i < cache_devices + nr_cache_devices;
i++)
- if (!i->bucket_size) {
- uint64_t size = (i->filesystem_size ?:
- getblocks(i->fd)) << 9;
+ bucket_size = min(bucket_size, i->bucket_size);
- if (size < 1 << 20) /* 1M device - 256 4k buckets*/
- i->bucket_size = rounddown_pow_of_two(size >> 17);
- else
- /* Max 1M bucket at around 256G */
- i->bucket_size = 8 << min((ilog2(size >> 20) / 2), 9U);
- }
+ struct cache_sb_v0 *sb = calloc(1, sizeof(*sb));
- if (!btree_node_size) {
- /* 256k default btree node size */
- btree_node_size = 512;
+ sb->offset = SB_SECTOR;
+ sb->version = BCACHE_SB_VERSION_CDEV_WITH_UUID;
+ sb->magic = BCACHE_MAGIC;
+ sb->block_size = block_size;
+ sb->bucket_size = bucket_size;
+ sb->set_uuid = set_uuid;
+ sb->nr_in_set = nr_cache_devices;
- for (struct cache_opts *i = cache_devices;
- i < cache_devices + nr_cache_devices;
- i++)
- btree_node_size = min(btree_node_size, i->bucket_size);
+ if (label)
+ memcpy(sb->label, label, sizeof(sb->label));
+
+ for (struct cache_opts *i = cache_devices;
+ i < cache_devices + nr_cache_devices;
+ i++) {
+ char uuid_str[40], set_uuid_str[40];
+
+ uuid_generate(sb->uuid.b);
+ sb->nbuckets = i->nbuckets;
+ sb->first_bucket = i->first_bucket;
+ sb->nr_this_dev = i - cache_devices;
+ sb->csum = csum_set(sb, BCH_CSUM_CRC64);
+
+ uuid_unparse(sb->uuid.b, uuid_str);
+ uuid_unparse(sb->set_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,
+ sb->nbuckets,
+ sb->block_size,
+ sb->bucket_size,
+ sb->nr_in_set,
+ sb->nr_this_dev,
+ sb->first_bucket);
+
+ do_write_sb(i->fd, sb);
}
+}
- cache_set_sb = calloc(1, sizeof(*cache_set_sb) +
- sizeof(struct cache_member) * nr_cache_devices);
+static void format_v1(void)
+{
+ struct cache_sb *sb;
- cache_set_sb->offset = SB_SECTOR;
- cache_set_sb->version = BCACHE_SB_VERSION_CDEV_V3;
- cache_set_sb->magic = BCACHE_MAGIC;
- cache_set_sb->block_size = block_size;
- uuid_generate(cache_set_sb->set_uuid.b);
+ sb = calloc(1, sizeof(*sb) + sizeof(struct cache_member) *
+ nr_cache_devices);
- if (uuid_is_null(cache_set_uuid))
- uuid_generate(cache_set_sb->user_uuid.b);
- else
- memcpy(cache_set_sb->user_uuid.b, cache_set_uuid,
- sizeof(cache_set_sb->user_uuid));
+ sb->offset = SB_SECTOR;
+ sb->version = BCACHE_SB_VERSION_CDEV_V3;
+ sb->magic = BCACHE_MAGIC;
+ sb->block_size = block_size;
+ sb->set_uuid = set_uuid;
+ sb->user_uuid = user_uuid;
if (label)
- memcpy(cache_set_sb->label, label, sizeof(cache_set_sb->label));
+ memcpy(sb->label, label, sizeof(sb->label));
/*
* don't have a userspace crc32c implementation handy, just always use
* crc64
*/
- SET_CACHE_SB_CSUM_TYPE(cache_set_sb, BCH_CSUM_CRC64);
- SET_CACHE_PREFERRED_CSUM_TYPE(cache_set_sb, csum_type);
+ SET_CACHE_SB_CSUM_TYPE(sb, BCH_CSUM_CRC64);
+ SET_CACHE_PREFERRED_CSUM_TYPE(sb, csum_type);
- SET_CACHE_BTREE_NODE_SIZE(cache_set_sb, btree_node_size);
- SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb, meta_replicas);
- SET_CACHE_SET_META_REPLICAS_HAVE(cache_set_sb, meta_replicas);
- SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb, data_replicas);
- SET_CACHE_SET_DATA_REPLICAS_HAVE(cache_set_sb, data_replicas);
- SET_CACHE_ERROR_ACTION(cache_set_sb, on_error_action);
+ SET_CACHE_BTREE_NODE_SIZE(sb, btree_node_size);
+ SET_CACHE_SET_META_REPLICAS_WANT(sb, meta_replicas);
+ SET_CACHE_SET_META_REPLICAS_HAVE(sb, meta_replicas);
+ SET_CACHE_SET_DATA_REPLICAS_WANT(sb, data_replicas);
+ SET_CACHE_SET_DATA_REPLICAS_HAVE(sb, data_replicas);
+ SET_CACHE_ERROR_ACTION(sb, on_error_action);
for (struct cache_opts *i = cache_devices;
i < cache_devices + nr_cache_devices;
i++) {
- if (i->bucket_size < block_size)
- die("Bucket size cannot be smaller than block size");
-
- struct cache_member *m = cache_set_sb->members + cache_set_sb->nr_in_set++;
+ struct cache_member *m = sb->members + sb->nr_in_set++;
uuid_generate(m->uuid.b);
- m->nbuckets = (i->filesystem_size ?:
- getblocks(i->fd)) / i->bucket_size;
- m->first_bucket = (23 / i->bucket_size) + 3;
+ m->nbuckets = i->nbuckets;
+ m->first_bucket = i->first_bucket;
m->bucket_size = i->bucket_size;
if (m->nbuckets < 1 << 7)
@@ -360,19 +442,19 @@ static int format_v1(void)
SET_CACHE_DISCARD(m, discard);
}
- cache_set_sb->u64s = bch_journal_buckets_offset(cache_set_sb);
+ sb->u64s = bch_journal_buckets_offset(sb);
- for (unsigned i = 0; i < cache_set_sb->nr_in_set; i++) {
+ for (unsigned i = 0; i < sb->nr_in_set; i++) {
char uuid_str[40], set_uuid_str[40];
- struct cache_member *m = cache_set_sb->members + i;
+ struct cache_member *m = sb->members + i;
- cache_set_sb->disk_uuid = m->uuid;
- cache_set_sb->nr_this_dev = i;
- cache_set_sb->csum = csum_set(cache_set_sb,
- CACHE_SB_CSUM_TYPE(cache_set_sb));
+ sb->disk_uuid = m->uuid;
+ sb->nr_this_dev = i;
+ sb->csum = csum_set(sb,
+ CACHE_SB_CSUM_TYPE(sb));
- uuid_unparse(cache_set_sb->disk_uuid.b, uuid_str);
- uuid_unparse(cache_set_sb->user_uuid.b, set_uuid_str);
+ 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"
@@ -383,15 +465,83 @@ static int format_v1(void)
"nr_this_dev: %u\n"
"first_bucket: %u\n",
uuid_str, set_uuid_str,
- (unsigned) cache_set_sb->version,
+ (unsigned) sb->version,
m->nbuckets,
- cache_set_sb->block_size,
+ sb->block_size,
m->bucket_size,
- cache_set_sb->nr_in_set,
- cache_set_sb->nr_this_dev,
+ sb->nr_in_set,
+ sb->nr_this_dev,
m->first_bucket);
- do_write_sb(cache_devices[i].fd, cache_set_sb);
+ do_write_sb(cache_devices[i].fd, sb);
+ }
+}
+
+int cmd_format(NihCommand *command, char *const *args)
+{
+ if (!nr_cache_devices && !nr_backing_devices)
+ die("Please supply a device");
+
+ if (uuid_is_null(user_uuid.b))
+ uuid_generate(user_uuid.b);
+
+ uuid_generate(set_uuid.b);
+
+ if (!block_size) {
+ for (struct cache_opts *i = cache_devices;
+ i < cache_devices + nr_cache_devices;
+ i++)
+ block_size = max(block_size, get_blocksize(i->dev, i->fd));
+
+ for (struct backingdev_opts *i = backing_devices;
+ i < backing_devices + nr_backing_devices;
+ i++)
+ block_size = max(block_size, get_blocksize(i->dev, i->fd));
+ }
+
+ for (struct cache_opts *i = cache_devices;
+ i < cache_devices + nr_cache_devices;
+ i++) {
+ if (!i->bucket_size) {
+ u64 size = (i->filesystem_size ?:
+ getblocks(i->fd)) << 9;
+
+ if (size < 1 << 20) /* 1M device - 256 4k buckets*/
+ i->bucket_size = rounddown_pow_of_two(size >> 17);
+ else
+ /* Max 1M bucket at around 256G */
+ i->bucket_size = 8 << min((ilog2(size >> 20) / 2), 9U);
+ }
+
+ if (i->bucket_size < block_size)
+ die("Bucket size cannot be smaller than block size");
+
+ i->nbuckets = (i->filesystem_size ?:
+ getblocks(i->fd)) / i->bucket_size;
+ i->first_bucket = (23 / i->bucket_size) + 3;
+
+ if (i->nbuckets < 1 << 7)
+ die("Not enough buckets: %llu, need %u",
+ i->nbuckets, 1 << 7);
+ }
+
+ if (!btree_node_size) {
+ /* 256k default btree node size */
+ btree_node_size = 512;
+
+ for (struct cache_opts *i = cache_devices;
+ i < cache_devices + nr_cache_devices;
+ i++)
+ btree_node_size = min(btree_node_size, i->bucket_size);
+ }
+
+ switch (version) {
+ case 0:
+ format_v0();
+ break;
+ case 1:
+ format_v1();
+ break;
}
for (struct backingdev_opts *i = backing_devices;
@@ -399,17 +549,7 @@ static int format_v1(void)
i++)
write_backingdev_sb(i->fd, block_size, cache_mode,
data_offset, i->label,
- cache_set_sb->user_uuid,
- cache_set_sb->set_uuid);
-
+ set_uuid);
return 0;
}
-
-int cmd_format(NihCommand *command, char *const *args)
-{
- if (!nr_cache_devices && !nr_backing_devices)
- die("Please supply a device");
-
- return format_v1();
-}