From e8c1cee578e3911ea95c3f063234f7bf271b17dd Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Thu, 25 Sep 2014 18:34:24 -0700 Subject: [PATCH 01/21] Create libbcache.a. Move make-bcache, probe-bcache, and bcache-super-show functions into a static library called libbcache. Change-Id: Ieed626225e08507a8ccd12f6bb0c07f64480de9b Signed-off-by: Jacob Malevich --- Makefile.am | 24 +-- bcache-super-show.c | 164 +--------------- bcache.c | 470 ++++++++++++++++++++++++++++++++++++++++++++ bcache.h | 23 +++ make-bcache.c | 308 +---------------------------- 5 files changed, 511 insertions(+), 478 deletions(-) diff --git a/Makefile.am b/Makefile.am index fdfe1a53..06631cbf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,8 @@ AUTOMAKE_OPTIONS=subdir-objects PREFIX=/usr -AM_CFLAGS=-O2 -Wall -g -std=gnu99 +AM_CFLAGS=-std=gnu99 `pkg-config --cflags uuid blkid` +AM_LDFLAGS=`pkg-config --libs uuid blkid` -L$(top_builddir) bin_PROGRAMS=make-bcache \ @@ -12,21 +13,22 @@ bin_PROGRAMS=make-bcache \ noinst_PROGRAMS=bcache-test -make_bcache_SOURCES=make-bcache.c bcache.c -make_bcache_LDFLAGS=`pkg-config --libs uuid blkid` -make_bcache_CFLAGS=$(AM_CFLAGS) `pkg-config --cflags uuid blkid` +lib_LIBRARIES=libbcache.a +libbcache_a_SOURCES=bcache.c +bcache_LDADD=libbcache.a -probe_bcache_SOURCES=probe-bcache.c bcache.c -probe_bcache_LDFLAGS=`pkg-config --libs uuid blkid` -probe_bcache_CFLAGS=$(AM_CFLAGS) `pkg-config --cflags uuid blkid` +make_bcache_SOURCES=make-bcache.c +make_bcache_LDADD=libbcache.a -bcache_super_show_SOURCES=bcache-super-show.c bcache.c -bcache_super_show_LDFLAGS=`pkg-config --libs uuid` -bcache_super_show_CFLAGS=$(AM_CFLAGS) `pkg-config --cflags uuid` +probe_bcache_SOURCES=probe-bcache.c +probe_bcache_LDADD=libbcache.a + +bcache_super_show_SOURCES=bcache-super-show.c +bcache_super_show_LDADD=libbcache.a bcachectl_SOURCES=bcachectl.c -bcache_test_SOURCE=bcache-test.c +bcache_test_SOURCES=bcache-test.c bcache_test_LDFLAGS=-lm `pkg-config --libs openssl` bcache_test_CFLAGS=$(AM_CFLAGS) `pkg-config --cflags openssl` diff --git a/bcache-super-show.c b/bcache-super-show.c index 76d8b0a8..f645af68 100644 --- a/bcache-super-show.c +++ b/bcache-super-show.c @@ -27,174 +27,18 @@ #include "bcache.h" -static bool force_csum = false; - -static void usage() +void usage() { fprintf(stderr, "Usage: bcache-super-show [-f] \n"); } -static void print_encode(char *in) -{ - for (char *pos = in; *pos; pos++) - if (isalnum(*pos) || strchr(".-_", *pos)) - putchar(*pos); - else - printf("%%%x", *pos); -} - -static void show_super_common(struct cache_sb *sb) -{ - char uuid[40]; - char label[SB_LABEL_SIZE + 1]; - uint64_t expected_csum; - - printf("sb.magic\t\t"); - if (!memcmp(&sb->magic, &BCACHE_MAGIC, sizeof(sb->magic))) { - printf("ok\n"); - } else { - printf("bad magic\n"); - fprintf(stderr, "Invalid superblock (bad magic)\n"); - exit(2); - } - - printf("sb.first_sector\t\t%ju", (uint64_t) sb->offset); - if (sb->offset == SB_SECTOR) { - printf(" [match]\n"); - } else { - printf(" [expected %ds]\n", SB_SECTOR); - fprintf(stderr, "Invalid superblock (bad sector)\n"); - exit(2); - } - - printf("sb.csum\t\t\t%ju", (uint64_t) sb->csum); - expected_csum = csum_set(sb, - sb->version < BCACHE_SB_VERSION_CDEV_V3 - ? BCH_CSUM_CRC64 - : CACHE_SB_CSUM_TYPE(sb)); - if (sb->csum == expected_csum) { - printf(" [match]\n"); - } else { - printf(" [expected %" PRIX64 "]\n", expected_csum); - if (!force_csum) { - fprintf(stderr, "Corrupt superblock (bad csum)\n"); - exit(2); - } - } - - printf("sb.version\t\t%ju", (uint64_t) sb->version); - switch (sb->version) { - // These are handled the same by the kernel - case BCACHE_SB_VERSION_CDEV: - case BCACHE_SB_VERSION_CDEV_WITH_UUID: - printf(" [cache device]\n"); - break; - - // The second adds data offset support - case BCACHE_SB_VERSION_BDEV: - case BCACHE_SB_VERSION_BDEV_WITH_OFFSET: - printf(" [backing device]\n"); - break; - - default: - printf(" [unknown]\n"); - // exit code? - exit(EXIT_SUCCESS); - } - - putchar('\n'); - - strncpy(label, (char *) sb->label, SB_LABEL_SIZE); - label[SB_LABEL_SIZE] = '\0'; - printf("dev.label\t\t"); - if (*label) - print_encode(label); - else - printf("(empty)"); - putchar('\n'); - - uuid_unparse(sb->uuid.b, uuid); - printf("dev.uuid\t\t%s\n", uuid); - - uuid_unparse(sb->set_uuid.b, uuid); - printf("cset.uuid\t\t%s\n", uuid); -} - -static void show_super_backingdev(struct cache_sb *sb) -{ - uint64_t first_sector; - - show_super_common(sb); - - if (sb->version == BCACHE_SB_VERSION_BDEV) { - first_sector = BDEV_DATA_START_DEFAULT; - } else { - if (sb->keys == 1 || sb->d[0]) { - fprintf(stderr, - "Possible experimental format detected, bailing\n"); - exit(3); - } - first_sector = sb->data_offset; - } - - printf("dev.data.first_sector\t%ju\n" - "dev.data.cache_mode\t%s" - "dev.data.cache_state\t%s\n", - first_sector, - bdev_cache_mode[BDEV_CACHE_MODE(sb)], - bdev_state[BDEV_STATE(sb)]); -} - -static void show_cache_member(struct cache_sb *sb, unsigned i) -{ - struct cache_member *m = ((struct cache_member *) sb->d) + i; - - printf("cache.state\t%s\n", cache_state[CACHE_STATE(m)]); - printf("cache.tier\t%llu\n", CACHE_TIER(m)); - - printf("cache.replication_set\t%llu\n", CACHE_REPLICATION_SET(m)); - printf("cache.cur_meta_replicas\t%llu\n", REPLICATION_SET_CUR_META_REPLICAS(m)); - printf("cache.cur_data_replicas\t%llu\n", REPLICATION_SET_CUR_DATA_REPLICAS(m)); - - printf("cache.has_metadata\t%llu\n", CACHE_HAS_METADATA(m)); - printf("cache.has_data\t%llu\n", CACHE_HAS_DATA(m)); - - printf("cache.replacement\t%s\n", replacement_policies[CACHE_REPLACEMENT(m)]); - printf("cache.discard\t%llu\n", CACHE_DISCARD(m)); -} - -static void show_super_cache(struct cache_sb *sb) -{ - show_super_common(sb); - - printf("dev.sectors_per_block\t%u\n" - "dev.sectors_per_bucket\t%u\n", - sb->block_size, - sb->bucket_size); - - // total_sectors includes the superblock; - printf("dev.cache.first_sector\t%u\n" - "dev.cache.cache_sectors\t%llu\n" - "dev.cache.total_sectors\t%llu\n" - "dev.cache.ordered\t%s\n" - "dev.cache.pos\t\t%u\n" - "dev.cache.setsize\t\t%u\n", - sb->bucket_size * sb->first_bucket, - sb->bucket_size * (sb->nbuckets - sb->first_bucket), - sb->bucket_size * sb->nbuckets, - CACHE_SYNC(sb) ? "yes" : "no", - sb->nr_this_dev, - sb->nr_in_set); - - show_cache_member(sb, sb->nr_this_dev); -} - int main(int argc, char **argv) { int o; extern char *optarg; struct cache_sb sb_stack, *sb = &sb_stack; size_t bytes = sizeof(*sb); + bool force_csum = false; while ((o = getopt(argc, argv, "f")) != EOF) switch (o) { @@ -237,9 +81,9 @@ int main(int argc, char **argv) } if (!SB_IS_BDEV(sb)) - show_super_cache(sb); + show_super_cache(sb, force_csum); else - show_super_backingdev(sb); + show_super_backingdev(sb, force_csum); return 0; } diff --git a/bcache.c b/bcache.c index 2c5a1060..fbaaa0ef 100644 --- a/bcache.c +++ b/bcache.c @@ -5,7 +5,19 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include #include "bcache.h" @@ -351,3 +363,461 @@ uint64_t bch_checksum(unsigned type, const void *data, size_t len) return crc ^ 0xffffffffffffffffULL; } + +uint64_t getblocks(int fd) +{ + uint64_t ret; + struct stat statbuf; + if (fstat(fd, &statbuf)) { + perror("stat error\n"); + exit(EXIT_FAILURE); + } + ret = statbuf.st_size / 512; + if (S_ISBLK(statbuf.st_mode)) + if (ioctl(fd, BLKGETSIZE, &ret)) { + perror("ioctl error"); + exit(EXIT_FAILURE); + } + return ret; +} + +uint64_t hatoi(const char *s) +{ + char *e; + long long i = strtoll(s, &e, 10); + switch (*e) { + case 't': + case 'T': + i *= 1024; + case 'g': + case 'G': + i *= 1024; + case 'm': + case 'M': + i *= 1024; + case 'k': + case 'K': + i *= 1024; + } + return i; +} + +unsigned hatoi_validate(const char *s, const char *msg) +{ + uint64_t v = hatoi(s); + + if (v & (v - 1)) { + fprintf(stderr, "%s must be a power of two\n", msg); + exit(EXIT_FAILURE); + } + + v /= 512; + + if (v > USHRT_MAX) { + fprintf(stderr, "%s too large\n", msg); + exit(EXIT_FAILURE); + } + + if (!v) { + fprintf(stderr, "%s too small\n", msg); + exit(EXIT_FAILURE); + } + + return v; +} + +static void do_write_sb(int fd, struct cache_sb *sb) +{ + char zeroes[SB_START] = {0}; + size_t bytes = ((void *) bset_bkey_last(sb)) - (void *) sb; + + /* Zero start of disk */ + if (pwrite(fd, zeroes, SB_START, 0) != SB_START) { + perror("write error\n"); + exit(EXIT_FAILURE); + } + /* Write superblock */ + if (pwrite(fd, sb, bytes, SB_START) != bytes) { + perror("write error\n"); + exit(EXIT_FAILURE); + } + + fsync(fd); + close(fd); +} + +void write_backingdev_sb(int fd, unsigned block_size, unsigned *bucket_sizes, + bool writeback, uint64_t data_offset, + const char *label, + uuid_le set_uuid) +{ + char uuid_str[40], set_uuid_str[40]; + struct cache_sb sb; + + memset(&sb, 0, sizeof(struct cache_sb)); + + sb.offset = SB_SECTOR; + sb.version = BCACHE_SB_VERSION_BDEV; + sb.magic = BCACHE_MAGIC; + uuid_generate(sb.uuid.b); + sb.set_uuid = set_uuid; + sb.bucket_size = bucket_sizes[0]; + sb.block_size = block_size; + + uuid_unparse(sb.uuid.b, uuid_str); + uuid_unparse(sb.set_uuid.b, set_uuid_str); + if (label) + memcpy(sb.label, label, SB_LABEL_SIZE); + + SET_BDEV_CACHE_MODE(&sb, writeback + ? CACHE_MODE_WRITEBACK + : CACHE_MODE_WRITETHROUGH); + + if (data_offset != BDEV_DATA_START_DEFAULT) { + sb.version = BCACHE_SB_VERSION_BDEV_WITH_OFFSET; + sb.data_offset = data_offset; + } + + sb.csum = csum_set(&sb, BCH_CSUM_CRC64); + + printf("UUID: %s\n" + "Set UUID: %s\n" + "version: %u\n" + "block_size: %u\n" + "data_offset: %ju\n", + uuid_str, set_uuid_str, + (unsigned) sb.version, + sb.block_size, + data_offset); + + do_write_sb(fd, &sb); +} + +int dev_open(const char *dev, bool wipe_bcache) +{ + struct cache_sb sb; + blkid_probe pr; + int fd; + + if ((fd = open(dev, O_RDWR|O_EXCL)) == -1) { + fprintf(stderr, "Can't open dev %s: %s\n", dev, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) + exit(EXIT_FAILURE); + + if (!memcmp(&sb.magic, &BCACHE_MAGIC, 16) && !wipe_bcache) { + fprintf(stderr, "Already a bcache device on %s, " + "overwrite with --wipe-bcache\n", dev); + exit(EXIT_FAILURE); + } + + if (!(pr = blkid_new_probe())) + exit(EXIT_FAILURE); + if (blkid_probe_set_device(pr, fd, 0, 0)) + exit(EXIT_FAILURE); + /* enable ptable probing; superblock probing is enabled by default */ + if (blkid_probe_enable_partitions(pr, true)) + exit(EXIT_FAILURE); + if (!blkid_do_probe(pr)) { + /* XXX wipefs doesn't know how to remove partition tables */ + fprintf(stderr, "Device %s already has a non-bcache superblock, " + "remove it using wipefs and wipefs -a\n", dev); + exit(EXIT_FAILURE); + } + + return fd; +} + +void write_cache_sbs(int *fds, struct cache_sb *sb, + unsigned block_size, unsigned *bucket_sizes, + int num_bucket_sizes) +{ + char uuid_str[40], set_uuid_str[40]; + size_t i; + + sb->offset = SB_SECTOR; + sb->version = BCACHE_SB_VERSION_CDEV_V3; + sb->magic = BCACHE_MAGIC; + sb->block_size = block_size; + sb->keys = bch_journal_buckets_offset(sb); + + /* + * don't have a userspace crc32c implementation handy, just always use + * crc64 + */ + SET_CACHE_SB_CSUM_TYPE(sb, BCH_CSUM_CRC64); + + for (i = 0; i < sb->nr_in_set; i++) { + struct cache_member *m = sb->members + i; + + sb->uuid = m->uuid; + if(num_bucket_sizes <= 1) + sb->bucket_size = bucket_sizes[0]; + else + sb->bucket_size = bucket_sizes[i]; + sb->nbuckets = getblocks(fds[i]) / sb->bucket_size; + sb->nr_this_dev = i; + sb->first_bucket = (23 / sb->bucket_size) + 1; + + if (sb->nbuckets < 1 << 7) { + fprintf(stderr, "Not enough buckets: %llu, need %u\n", + sb->nbuckets, 1 << 7); + exit(EXIT_FAILURE); + } + + sb->csum = csum_set(sb, CACHE_SB_CSUM_TYPE(sb)); + + 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(fds[i], sb); + } +} + +void next_cache_device(struct cache_sb *sb, + unsigned replication_set, + unsigned tier, + unsigned replacement_policy, + bool discard) +{ + struct cache_member *m = sb->members + sb->nr_in_set; + + SET_CACHE_REPLICATION_SET(m, replication_set); + SET_CACHE_TIER(m, tier); + SET_CACHE_REPLACEMENT(m, replacement_policy); + SET_CACHE_DISCARD(m, discard); + uuid_generate(m->uuid.b); + + sb->nr_in_set++; +} + +unsigned get_blocksize(const char *path) +{ + struct stat statbuf; + + if (stat(path, &statbuf)) { + fprintf(stderr, "Error statting %s: %s\n", + path, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (S_ISBLK(statbuf.st_mode)) { + /* check IO limits: + * BLKALIGNOFF: alignment_offset + * BLKPBSZGET: physical_block_size + * BLKSSZGET: logical_block_size + * BLKIOMIN: minimum_io_size + * BLKIOOPT: optimal_io_size + * + * It may be tempting to use physical_block_size, + * or even minimum_io_size. + * But to be as transparent as possible, + * we want to use logical_block_size. + */ + unsigned int logical_block_size; + int fd = open(path, O_RDONLY); + + if (fd < 0) { + fprintf(stderr, "open(%s) failed: %m\n", path); + exit(EXIT_FAILURE); + } + if (ioctl(fd, BLKSSZGET, &logical_block_size)) { + fprintf(stderr, "ioctl(%s, BLKSSZGET) failed: %m\n", path); + exit(EXIT_FAILURE); + } + close(fd); + return logical_block_size / 512; + + } + /* else: not a block device. + * Why would we even want to write a bcache super block there? */ + + return statbuf.st_blksize / 512; +} + +long strtoul_or_die(const char *p, size_t max, const char *msg) +{ + errno = 0; + long v = strtol(optarg, NULL, 10); + if (errno || v < 0 || v >= max) { + fprintf(stderr, "Invalid %s %zi\n", msg, v); + exit(EXIT_FAILURE); + } + + return v; +} + +static void print_encode(char *in) +{ + char *pos; + for (pos = in; *pos; pos++) + if (isalnum(*pos) || strchr(".-_", *pos)) + putchar(*pos); + else + printf("%%%x", *pos); +} + +static void show_super_common(struct cache_sb *sb, bool force_csum) +{ + char uuid[40]; + char label[SB_LABEL_SIZE + 1]; + uint64_t expected_csum; + + printf("sb.magic\t\t"); + if (!memcmp(&sb->magic, &BCACHE_MAGIC, sizeof(sb->magic))) { + printf("ok\n"); + } else { + printf("bad magic\n"); + fprintf(stderr, "Invalid superblock (bad magic)\n"); + exit(2); + } + + printf("sb.first_sector\t\t%ju", (uint64_t) sb->offset); + if (sb->offset == SB_SECTOR) { + printf(" [match]\n"); + } else { + printf(" [expected %ds]\n", SB_SECTOR); + fprintf(stderr, "Invalid superblock (bad sector)\n"); + exit(2); + } + + printf("sb.csum\t\t\t%ju", (uint64_t) sb->csum); + expected_csum = csum_set(sb, + sb->version < BCACHE_SB_VERSION_CDEV_V3 + ? BCH_CSUM_CRC64 + : CACHE_SB_CSUM_TYPE(sb)); + if (sb->csum == expected_csum) { + printf(" [match]\n"); + } else { + printf(" [expected %" PRIX64 "]\n", expected_csum); + if (!force_csum) { + fprintf(stderr, "Corrupt superblock (bad csum)\n"); + exit(2); + } + } + + printf("sb.version\t\t%ju", (uint64_t) sb->version); + switch (sb->version) { + // These are handled the same by the kernel + case BCACHE_SB_VERSION_CDEV: + case BCACHE_SB_VERSION_CDEV_WITH_UUID: + printf(" [cache device]\n"); + break; + + // The second adds data offset support + case BCACHE_SB_VERSION_BDEV: + case BCACHE_SB_VERSION_BDEV_WITH_OFFSET: + printf(" [backing device]\n"); + break; + + default: + printf(" [unknown]\n"); + // exit code? + exit(EXIT_SUCCESS); + } + + putchar('\n'); + + strncpy(label, (char *) sb->label, SB_LABEL_SIZE); + label[SB_LABEL_SIZE] = '\0'; + printf("dev.label\t\t"); + if (*label) + print_encode(label); + else + printf("(empty)"); + putchar('\n'); + + uuid_unparse(sb->uuid.b, uuid); + printf("dev.uuid\t\t%s\n", uuid); + + uuid_unparse(sb->set_uuid.b, uuid); + printf("cset.uuid\t\t%s\n", uuid); +} + +void show_super_backingdev(struct cache_sb *sb, bool force_csum) +{ + uint64_t first_sector; + + show_super_common(sb, force_csum); + + if (sb->version == BCACHE_SB_VERSION_BDEV) { + first_sector = BDEV_DATA_START_DEFAULT; + } else { + if (sb->keys == 1 || sb->d[0]) { + fprintf(stderr, + "Possible experimental format detected, bailing\n"); + exit(3); + } + first_sector = sb->data_offset; + } + + printf("dev.data.first_sector\t%ju\n" + "dev.data.cache_mode\t%s" + "dev.data.cache_state\t%s\n", + first_sector, + bdev_cache_mode[BDEV_CACHE_MODE(sb)], + bdev_state[BDEV_STATE(sb)]); +} + +void show_cache_member(struct cache_sb *sb, unsigned i) +{ + struct cache_member *m = ((struct cache_member *) sb->d) + i; + + printf("cache.state\t%s\n", cache_state[CACHE_STATE(m)]); + printf("cache.tier\t%llu\n", CACHE_TIER(m)); + + printf("cache.replication_set\t%llu\n", CACHE_REPLICATION_SET(m)); + printf("cache.cur_meta_replicas\t%llu\n", REPLICATION_SET_CUR_META_REPLICAS(m)); + printf("cache.cur_data_replicas\t%llu\n", REPLICATION_SET_CUR_DATA_REPLICAS(m)); + + printf("cache.has_metadata\t%llu\n", CACHE_HAS_METADATA(m)); + printf("cache.has_data\t%llu\n", CACHE_HAS_DATA(m)); + + printf("cache.replacement\t%s\n", replacement_policies[CACHE_REPLACEMENT(m)]); + printf("cache.discard\t%llu\n", CACHE_DISCARD(m)); +} + +void show_super_cache(struct cache_sb *sb, bool force_csum) +{ + show_super_common(sb, force_csum); + + printf("dev.sectors_per_block\t%u\n" + "dev.sectors_per_bucket\t%u\n", + sb->block_size, + sb->bucket_size); + + // total_sectors includes the superblock; + printf("dev.cache.first_sector\t%u\n" + "dev.cache.cache_sectors\t%llu\n" + "dev.cache.total_sectors\t%llu\n" + "dev.cache.ordered\t%s\n" + "dev.cache.pos\t\t%u\n" + "dev.cache.setsize\t\t%u\n", + sb->bucket_size * sb->first_bucket, + sb->bucket_size * (sb->nbuckets - sb->first_bucket), + sb->bucket_size * sb->nbuckets, + CACHE_SYNC(sb) ? "yes" : "no", + sb->nr_this_dev, + sb->nr_in_set); + + show_cache_member(sb, sb->nr_this_dev); +} diff --git a/bcache.h b/bcache.h index f743739a..7f61a0e7 100644 --- a/bcache.h +++ b/bcache.h @@ -21,6 +21,14 @@ typedef __s64 s64; #define SB_START (SB_SECTOR * 512) + +#define max(x, y) ({ \ + typeof(x) _max1 = (x); \ + typeof(y) _max2 = (y); \ + (void) (&_max1 == &_max2); \ + _max1 > _max2 ? _max1 : _max2; }) + + extern const char * const cache_state[]; extern const char * const replacement_policies[]; extern const char * const csum_types[]; @@ -34,6 +42,21 @@ void print_string_list(const char * const[], size_t); uint64_t bch_checksum(unsigned, const void *, size_t); +uint64_t getblocks(int); +uint64_t hatoi(const char *); +unsigned hatoi_validate(const char *, const char *); +void write_backingdev_sb(int, unsigned, unsigned *, bool, uint64_t, + const char *, uuid_le); +int dev_open(const char *, bool); +void write_cache_sbs(int *, struct cache_sb *, unsigned, unsigned *, int); +void next_cache_device(struct cache_sb *, unsigned, unsigned, unsigned, bool); +unsigned get_blocksize(const char *); +long strtoul_or_die(const char *, size_t, const char *); + +void show_super_backingdev(struct cache_sb *, bool); +void show_cache_member(struct cache_sb *, unsigned); +void show_super_cache(struct cache_sb *, bool); + #define csum_set(i, type) \ ({ \ void *start = ((void *) (i)) + sizeof(uint64_t); \ diff --git a/make-bcache.c b/make-bcache.c index 450ba99d..b47cd9fb 100644 --- a/make-bcache.c +++ b/make-bcache.c @@ -5,10 +5,9 @@ */ #define _FILE_OFFSET_BITS 64 -#define __USE_FILE_OFFSET64 +#define __USE_FILE_OFFSET 64 #define _XOPEN_SOURCE 600 -#include #include #include #include @@ -28,74 +27,6 @@ #include "bcache.h" -#define max(x, y) ({ \ - typeof(x) _max1 = (x); \ - typeof(y) _max2 = (y); \ - (void) (&_max1 == &_max2); \ - _max1 > _max2 ? _max1 : _max2; }) - -uint64_t getblocks(int fd) -{ - uint64_t ret; - struct stat statbuf; - if (fstat(fd, &statbuf)) { - perror("stat error\n"); - exit(EXIT_FAILURE); - } - ret = statbuf.st_size / 512; - if (S_ISBLK(statbuf.st_mode)) - if (ioctl(fd, BLKGETSIZE, &ret)) { - perror("ioctl error"); - exit(EXIT_FAILURE); - } - return ret; -} - -uint64_t hatoi(const char *s) -{ - char *e; - long long i = strtoll(s, &e, 10); - switch (*e) { - case 't': - case 'T': - i *= 1024; - case 'g': - case 'G': - i *= 1024; - case 'm': - case 'M': - i *= 1024; - case 'k': - case 'K': - i *= 1024; - } - return i; -} - -unsigned hatoi_validate(const char *s, const char *msg) -{ - uint64_t v = hatoi(s); - - if (v & (v - 1)) { - fprintf(stderr, "%s must be a power of two\n", msg); - exit(EXIT_FAILURE); - } - - v /= 512; - - if (v > USHRT_MAX) { - fprintf(stderr, "%s too large\n", msg); - exit(EXIT_FAILURE); - } - - if (!v) { - fprintf(stderr, "%s too small\n", msg); - exit(EXIT_FAILURE); - } - - return v; -} - void usage() { fprintf(stderr, @@ -123,243 +54,6 @@ void usage() exit(EXIT_FAILURE); } -static void do_write_sb(int fd, struct cache_sb *sb) -{ - char zeroes[SB_START] = {0}; - size_t bytes = ((void *) bset_bkey_last(sb)) - (void *) sb; - - /* Zero start of disk */ - if (pwrite(fd, zeroes, SB_START, 0) != SB_START) { - perror("write error\n"); - exit(EXIT_FAILURE); - } - /* Write superblock */ - if (pwrite(fd, sb, bytes, SB_START) != bytes) { - perror("write error\n"); - exit(EXIT_FAILURE); - } - - fsync(fd); - close(fd); -} - -static void write_backingdev_sb(int fd, unsigned block_size, unsigned bucket_size, - bool writeback, uint64_t data_offset, - const char *label, - uuid_le set_uuid) -{ - char uuid_str[40], set_uuid_str[40]; - struct cache_sb sb; - - memset(&sb, 0, sizeof(struct cache_sb)); - - sb.offset = SB_SECTOR; - sb.version = BCACHE_SB_VERSION_BDEV; - sb.magic = BCACHE_MAGIC; - uuid_generate(sb.uuid.b); - sb.set_uuid = set_uuid; - sb.bucket_size = bucket_size; - sb.block_size = block_size; - - uuid_unparse(sb.uuid.b, uuid_str); - uuid_unparse(sb.set_uuid.b, set_uuid_str); - if (label) - memcpy(sb.label, label, SB_LABEL_SIZE); - - SET_BDEV_CACHE_MODE(&sb, writeback - ? CACHE_MODE_WRITEBACK - : CACHE_MODE_WRITETHROUGH); - - if (data_offset != BDEV_DATA_START_DEFAULT) { - sb.version = BCACHE_SB_VERSION_BDEV_WITH_OFFSET; - sb.data_offset = data_offset; - } - - sb.csum = csum_set(&sb, BCH_CSUM_CRC64); - - printf("UUID: %s\n" - "Set UUID: %s\n" - "version: %u\n" - "block_size: %u\n" - "data_offset: %ju\n", - uuid_str, set_uuid_str, - (unsigned) sb.version, - sb.block_size, - data_offset); - - do_write_sb(fd, &sb); -} - -static int dev_open(const char *dev, bool wipe_bcache) -{ - struct cache_sb sb; - blkid_probe pr; - int fd; - - if ((fd = open(dev, O_RDWR|O_EXCL)) == -1) { - fprintf(stderr, "Can't open dev %s: %s\n", dev, strerror(errno)); - exit(EXIT_FAILURE); - } - - if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) - exit(EXIT_FAILURE); - - if (!memcmp(&sb.magic, &BCACHE_MAGIC, 16) && !wipe_bcache) { - fprintf(stderr, "Already a bcache device on %s, " - "overwrite with --wipe-bcache\n", dev); - exit(EXIT_FAILURE); - } - - if (!(pr = blkid_new_probe())) - exit(EXIT_FAILURE); - if (blkid_probe_set_device(pr, fd, 0, 0)) - exit(EXIT_FAILURE); - /* enable ptable probing; superblock probing is enabled by default */ - if (blkid_probe_enable_partitions(pr, true)) - exit(EXIT_FAILURE); - if (!blkid_do_probe(pr)) { - /* XXX wipefs doesn't know how to remove partition tables */ - fprintf(stderr, "Device %s already has a non-bcache superblock, " - "remove it using wipefs and wipefs -a\n", dev); - exit(EXIT_FAILURE); - } - - return fd; -} - -static void write_cache_sbs(int *fds, struct cache_sb *sb, - unsigned block_size, unsigned bucket_size) -{ - char uuid_str[40], set_uuid_str[40]; - size_t i; - - sb->offset = SB_SECTOR; - sb->version = BCACHE_SB_VERSION_CDEV_V3; - sb->magic = BCACHE_MAGIC; - sb->bucket_size = bucket_size; - sb->block_size = block_size; - sb->keys = bch_journal_buckets_offset(sb); - - /* - * don't have a userspace crc32c implementation handy, just always use - * crc64 - */ - SET_CACHE_SB_CSUM_TYPE(sb, BCH_CSUM_CRC64); - - for (i = 0; i < sb->nr_in_set; i++) { - struct cache_member *m = sb->members + i; - - sb->uuid = m->uuid; - - sb->nbuckets = getblocks(fds[i]) / sb->bucket_size; - sb->nr_this_dev = i; - sb->first_bucket = (23 / sb->bucket_size) + 1; - - if (sb->nbuckets < 1 << 7) { - fprintf(stderr, "Not enough buckets: %llu, need %u\n", - sb->nbuckets, 1 << 7); - exit(EXIT_FAILURE); - } - - sb->csum = csum_set(sb, CACHE_SB_CSUM_TYPE(sb)); - - 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(fds[i], sb); - } -} - -static void next_cache_device(struct cache_sb *sb, - unsigned replication_set, - unsigned tier, - unsigned replacement_policy, - bool discard) -{ - struct cache_member *m = sb->members + sb->nr_in_set; - - SET_CACHE_REPLICATION_SET(m, replication_set); - SET_CACHE_TIER(m, tier); - SET_CACHE_REPLACEMENT(m, replacement_policy); - SET_CACHE_DISCARD(m, discard); - uuid_generate(m->uuid.b); - - sb->nr_in_set++; -} - -static unsigned get_blocksize(const char *path) -{ - struct stat statbuf; - - if (stat(path, &statbuf)) { - fprintf(stderr, "Error statting %s: %s\n", - path, strerror(errno)); - exit(EXIT_FAILURE); - } - - if (S_ISBLK(statbuf.st_mode)) { - /* check IO limits: - * BLKALIGNOFF: alignment_offset - * BLKPBSZGET: physical_block_size - * BLKSSZGET: logical_block_size - * BLKIOMIN: minimum_io_size - * BLKIOOPT: optimal_io_size - * - * It may be tempting to use physical_block_size, - * or even minimum_io_size. - * But to be as transparent as possible, - * we want to use logical_block_size. - */ - unsigned int logical_block_size; - int fd = open(path, O_RDONLY); - - if (fd < 0) { - fprintf(stderr, "open(%s) failed: %m\n", path); - exit(EXIT_FAILURE); - } - if (ioctl(fd, BLKSSZGET, &logical_block_size)) { - fprintf(stderr, "ioctl(%s, BLKSSZGET) failed: %m\n", path); - exit(EXIT_FAILURE); - } - close(fd); - return logical_block_size / 512; - - } - /* else: not a block device. - * Why would we even want to write a bcache super block there? */ - - return statbuf.st_blksize / 512; -} - -static long strtoul_or_die(const char *p, size_t max, const char *msg) -{ - errno = 0; - long v = strtol(optarg, NULL, 10); - if (errno || v < 0 || v >= max) { - fprintf(stderr, "Invalid %s %zi\n", msg, v); - exit(EXIT_FAILURE); - } - - return v; -} - int main(int argc, char **argv) { int c, bdev = -1; From ee44c4f509667aa1bce20b44dcd459b1bc3eea99 Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Mon, 13 Oct 2014 15:21:09 -0700 Subject: [PATCH 02/21] set btree_node_size for the cache_sb based on bucket_size Change-Id: I98dab6e9a221cd8781095039d653ace84ffae806 Signed-off-by: Jacob Malevich --- bcache.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/bcache.c b/bcache.c index fbaaa0ef..7e061649 100644 --- a/bcache.c +++ b/bcache.c @@ -530,12 +530,34 @@ int dev_open(const char *dev, bool wipe_bcache) return fd; } +static unsigned min_bucket_size(int num_bucket_sizes, unsigned *bucket_sizes) +{ + int i; + unsigned min = bucket_sizes[0]; + + for (i = 0; i < num_bucket_sizes; i++) + min = bucket_sizes[i] < min ? bucket_sizes[i] : min; + + return min; +} + +static unsigned node_size(unsigned bucket_size) { + + if (bucket_size <= 256) + return bucket_size; + else if (bucket_size <= 512) + return bucket_size / 2; + else + return bucket_size / 4; +} + void write_cache_sbs(int *fds, struct cache_sb *sb, unsigned block_size, unsigned *bucket_sizes, int num_bucket_sizes) { char uuid_str[40], set_uuid_str[40]; size_t i; + unsigned min_size = min_bucket_size(num_bucket_sizes, bucket_sizes); sb->offset = SB_SECTOR; sb->version = BCACHE_SB_VERSION_CDEV_V3; @@ -552,11 +574,13 @@ void write_cache_sbs(int *fds, struct cache_sb *sb, for (i = 0; i < sb->nr_in_set; i++) { struct cache_member *m = sb->members + i; - sb->uuid = m->uuid; - if(num_bucket_sizes <= 1) + if (num_bucket_sizes <= 1) sb->bucket_size = bucket_sizes[0]; else sb->bucket_size = bucket_sizes[i]; + SET_CACHE_BTREE_NODE_SIZE(sb, node_size(min_size)); + + sb->uuid = m->uuid; sb->nbuckets = getblocks(fds[i]) / sb->bucket_size; sb->nr_this_dev = i; sb->first_bucket = (23 / sb->bucket_size) + 1; From 0fca0e5502bf31385adeaaa8c72d60e665ee0547 Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Mon, 22 Sep 2014 19:00:50 -0700 Subject: [PATCH 03/21] Add multiple bucket_sizes to make-bcache This is needed since libbcache expects an array of bucket sizes to be passed in. This is just so the tests can continue to use make-bcache until we can change them over to bcacheadm. Change-Id: I1002e3d8355d45ffa914e6577569a5adfd1d6ccf Signed-off-by: Jacob Malevich --- make-bcache.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/make-bcache.c b/make-bcache.c index b47cd9fb..35bfc8c6 100644 --- a/make-bcache.c +++ b/make-bcache.c @@ -59,7 +59,9 @@ int main(int argc, char **argv) int c, bdev = -1; size_t i, nr_backing_devices = 0; - unsigned block_size = 0, bucket_size = 1024; + unsigned block_size = 0; + unsigned bucket_sizes[argc]; + int num_bucket_sizes = 0; int writeback = 0, discard = 0, wipe_bcache = 0; unsigned replication_set = 0, tier = 0, replacement_policy = 0; uint64_t data_offset = BDEV_DATA_START_DEFAULT; @@ -112,6 +114,7 @@ int main(int argc, char **argv) SET_CACHE_PREFERRED_CSUM_TYPE(cache_set_sb, BCH_CSUM_CRC32C); SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb, 1); SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb, 1); + bucket_sizes[0] = 1024; while ((c = getopt_long(argc, argv, "-hCBU:w:b:l:", @@ -142,7 +145,8 @@ int main(int argc, char **argv) break; case 'b': - bucket_size = hatoi_validate(optarg, "bucket size"); + bucket_sizes[num_bucket_sizes] = hatoi_validate(optarg, "bucket size"); + num_bucket_sizes++; break; case 'w': block_size = hatoi_validate(optarg, "block size"); @@ -212,10 +216,14 @@ int main(int argc, char **argv) usage(); } - if (bucket_size < block_size) { - fprintf(stderr, "Bucket size cannot be smaller than block size\n"); - exit(EXIT_FAILURE); - } + i = 0; + do { + if (bucket_sizes[i] < block_size) { + fprintf(stderr, "Bucket size cannot be smaller than block size\n"); + exit(EXIT_FAILURE); + } + i++; + } while (i < num_bucket_sizes); if (!block_size) { for (i = 0; i < cache_set_sb->nr_in_set; i++) @@ -233,11 +241,12 @@ int main(int argc, char **argv) for (i = 0; i < nr_backing_devices; i++) backing_dev_fd[i] = dev_open(backing_devices[i], wipe_bcache); - write_cache_sbs(cache_dev_fd, cache_set_sb, block_size, bucket_size); + write_cache_sbs(cache_dev_fd, cache_set_sb, block_size, + bucket_sizes, num_bucket_sizes); for (i = 0; i < nr_backing_devices; i++) write_backingdev_sb(backing_dev_fd[i], - block_size, bucket_size, + block_size, bucket_sizes, writeback, data_offset, backing_dev_labels[i], cache_set_sb->set_uuid); From 82ac2a0338b17fc41d8c7673cfd79dbf9ad598ff Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Fri, 26 Sep 2014 16:10:20 -0700 Subject: [PATCH 04/21] bcacheadm tool bcacheadm is a combination of make-bcache, probe-bcache, bcache-super-show, and bcachectl(register). Change-Id: Ia4f4cdd5f882516358eb0e26a75296d2103af1d0 Signed-off-by: Jacob Malevich --- Makefile.am | 8 +- bcache-tools.spec | 2 +- bcacheadm.c | 403 ++++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 1 - 4 files changed, 411 insertions(+), 3 deletions(-) create mode 100644 bcacheadm.c diff --git a/Makefile.am b/Makefile.am index 06631cbf..1cc47d3a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,7 +9,8 @@ AM_LDFLAGS=`pkg-config --libs uuid blkid` -L$(top_builddir) bin_PROGRAMS=make-bcache \ probe-bcache \ bcache-super-show \ - bcachectl + bcachectl \ + bcacheadm noinst_PROGRAMS=bcache-test @@ -32,6 +33,11 @@ bcache_test_SOURCES=bcache-test.c bcache_test_LDFLAGS=-lm `pkg-config --libs openssl` bcache_test_CFLAGS=$(AM_CFLAGS) `pkg-config --cflags openssl` +bcacheadm_SOURCES=bcacheadm.c +bcacheadm_LDFLAGS=$(AM_LDFLAGS) -lnih +bcacheadm_LDADD=libbcache.a + + udevrule_DATA=69-bcache.rules udevruledir=$(prefix)/lib/udev/rules.d diff --git a/bcache-tools.spec b/bcache-tools.spec index 9b04d8b9..77815c2b 100644 --- a/bcache-tools.spec +++ b/bcache-tools.spec @@ -7,7 +7,7 @@ License: GPL Group: tools BuildRoot: %{_tmppath}/%{name}-root Requires: libblkid -BuildRequires: pkgconfig libblkid-devel linux-headers +BuildRequires: pkgconfig libblkid-devel linux-headers libnih-devel %package dev diff --git a/bcacheadm.c b/bcacheadm.c new file mode 100644 index 00000000..ecfc650c --- /dev/null +++ b/bcacheadm.c @@ -0,0 +1,403 @@ +/* + * Authors: Kent Overstreet + * Gabriel de Perthuis + * Jacob Malevich + * + * GPLv2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //libbcache +#define __KERNEL__ +#include +#undef __KERNEL__ + +#define PACKAGE_NAME "bcacheadm" +#define PACKAGE_VERSION "1.0" +#define PACKAGE_BUGREPORT "bugreport" + +//What is the actual max? +#define MAX_DEVS 64 + + + +/* bcacheadm globals */ +enum exit { + EXIT_OK = 0, /* Ok */ + EXIT_ERROR = 1, /* General/OS error */ + EXIT_SHELL = 2, /* Start maintenance shell */ + EXIT_SHELL_REBOOT = 3, /* Start maintenance shell, reboot when done */ + EXIT_REBOOT = 4, /* System must reboot */ +}; + + +/* make-bcache globals */ +int bdev = -1; +int devs = 0; +const char *cache_devices[MAX_DEVS]; +const char *backing_devices[MAX_DEVS]; +const char *backing_dev_labels[MAX_DEVS]; +size_t i, nr_backing_devices = 0; +unsigned block_size = 0; +unsigned bucket_sizes[MAX_DEVS]; +int num_bucket_sizes = 0; +int writeback = 0, discard = 0, wipe_bcache = 0; +unsigned replication_set = 0, tier = 0, replacement_policy = 0; +uint64_t data_offset = BDEV_DATA_START_DEFAULT; +char *label = NULL; +struct cache_sb *cache_set_sb; +enum long_opts { + CACHE_SET_UUID = 256, + CSUM_TYPE, + REPLICATION_SET, + META_REPLICAS, + DATA_REPLICAS, +}; + + +/* super-show globals */ +bool force_csum = false; +char *show_dev = NULL; + + +/* probe globals */ +bool udev = false; + +/* register globals */ +int bcachefd; + +/* make-bcache option setters */ +static int set_CACHE_SET_UUID(NihOption *option, const char *arg) +{ + if(uuid_parse(arg, cache_set_sb->set_uuid.b)){ + fprintf(stderr, "Bad uuid\n"); + return -1; + } + return 0; +} +static int set_CSUM_TYPE(NihOption *option, const char *arg) +{ + SET_CACHE_PREFERRED_CSUM_TYPE(cache_set_sb, + read_string_list_or_die(arg, csum_types, + "csum type")); + return 0; +} +static int set_REPLICATION_SET(NihOption *option, const char *arg) +{ + replication_set = strtoul_or_die(arg, + CACHE_REPLICATION_SET_MAX, + "replication set"); + return 0; +} +static int set_META_REPLICAS(NihOption *option, const char *arg) +{ + SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb, + strtoul_or_die(arg, + CACHE_SET_META_REPLICAS_WANT_MAX, + "meta replicas")); + return 0; +} +static int set_DATA_REPLICAS(NihOption *option, const char *arg) +{ + SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb, + strtoul_or_die(arg, + CACHE_SET_DATA_REPLICAS_WANT_MAX, + "data replicas")); + return 0; +} +static int set_cache(NihOption *option, const char *arg) +{ + bdev=0; + cache_devices[cache_set_sb->nr_in_set] = arg; + next_cache_device(cache_set_sb, + replication_set, + tier, + replacement_policy, + discard); + devs++; + return 0; +} +static int set_bdev(NihOption *option, const char *arg) +{ + bdev=1; + backing_dev_labels[nr_backing_devices]=label; + backing_devices[nr_backing_devices++]=arg; + devs++; + return 0; +} +static int set_bucket_sizes(NihOption *option, const char *arg) +{ + bucket_sizes[num_bucket_sizes]=hatoi_validate(arg, "bucket size"); + num_bucket_sizes++; + return 0; +} + + +/* probe setters */ +static int set_udev(NihOption *option, const char *arg) +{ + if (strcmp("udev", arg)) { + printf("Invalid output format %s\n", arg); + exit(EXIT_FAILURE); + } + udev = true; + return 0; +} + + +/* options */ +static NihOption make_bcache_options[] = { +// {int shortoption, char* longoption, char* help, NihOptionGroup, char* argname, void *value, NihOptionSetter} + {'C', "cache", N_("Format a cache device"), NULL, NULL, NULL, set_cache}, + {'B', "bdev", N_("Format a backing device"), NULL, NULL, NULL, set_bdev}, + {'l', "label", N_("label"), NULL, NULL, &label, NULL}, + //Only one bucket_size supported until a list of bucket sizes is parsed correctly + {'b', "bucket", N_("bucket size"), NULL, NULL, NULL, set_bucket_sizes}, + //Does the default setter automatically convert strings to an int? + {'w', "block", N_("block size (hard sector size of SSD, often 2k"), NULL,NULL, &block_size, NULL}, + {'t', "tier", N_("tier of subsequent devices"), NULL,NULL, &tier, NULL}, + {'p', "cache_replacement_policy", N_("one of (lru|fifo|random)"), NULL,NULL, &replacement_policy, NULL}, + {'o', "data_offset", N_("data offset in sectors"), NULL,NULL, &data_offset, NULL}, + {'h', "help", N_("display this help and exit"), NULL,NULL, NULL, NULL}, + + {0, "cset-uuid", N_("UUID for the cache set"), NULL, NULL, NULL, set_CACHE_SET_UUID }, + {0, "csum-type", N_("One of (none|crc32c|crc64)"), NULL, NULL, NULL, set_CSUM_TYPE }, + {0, "replication-set",N_("replication set of subsequent devices"), NULL, NULL, NULL, set_REPLICATION_SET }, + {0, "meta-replicas",N_("number of metadata replicas"), NULL, NULL, NULL, set_META_REPLICAS}, + {0, "data-replicas",N_("number of data replicas"), NULL, NULL, NULL, set_DATA_REPLICAS }, + + {0, "wipe-bcache", N_("destroy existing bcache data if present"), NULL, NULL, &wipe_bcache, NULL}, + {0, "discard", N_("enable discards"), NULL, NULL, &discard, NULL}, + {0, "writeback", N_("enable writeback"), NULL, NULL, &writeback, NULL}, + + NIH_OPTION_LAST +}; + +static NihOption super_show_options[] = { + {'f', "force_csum", N_("force_csum"), NULL, NULL, &force_csum, NULL}, + {0, "dev", N_("dev"), NULL, NULL, &show_dev, NULL}, + NIH_OPTION_LAST + +}; + +static NihOption probe_bcache_options[] = { + {'o', "udev", N_("udev"), NULL, NULL, NULL, set_udev}, + NIH_OPTION_LAST +}; + +static NihOption bcache_register_options[] = { + NIH_OPTION_LAST +}; + +static NihOption options[] = { + NIH_OPTION_LAST +}; + + +/* commands */ +int make_bcache (NihCommand *command, char *const *args) +{ + int cache_dev_fd[devs]; + + int backing_dev_fd[devs]; + + cache_set_sb = calloc(1, sizeof(*cache_set_sb) + + sizeof(struct cache_member) * devs); + + uuid_generate(cache_set_sb->set_uuid.b); + SET_CACHE_PREFERRED_CSUM_TYPE(cache_set_sb, BCH_CSUM_CRC32C); + SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb, 1); + SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb, 1); + + if(!bucket_sizes[0]) bucket_sizes[0] = 1024; + + if (bdev == -1) { + fprintf(stderr, "Please specify -C or -B\n"); + exit(EXIT_FAILURE); + } + + if (!cache_set_sb->nr_in_set && !nr_backing_devices) { + fprintf(stderr, "Please supply a device\n"); + exit(EXIT_FAILURE); + } + + i = 0; + do { + if (bucket_sizes[i] < block_size) { + fprintf(stderr, "Bucket size cannot be smaller than block size\n"); + exit(EXIT_FAILURE); + } + i++; + } while (i < num_bucket_sizes); + + if (!block_size) { + for (i = 0; i < cache_set_sb->nr_in_set; i++) + block_size = max(block_size, + get_blocksize(cache_devices[i])); + + for (i = 0; i < nr_backing_devices; i++) + block_size = max(block_size, + get_blocksize(backing_devices[i])); + } + + for (i = 0; i < cache_set_sb->nr_in_set; i++) + cache_dev_fd[i] = dev_open(cache_devices[i], wipe_bcache); + + for (i = 0; i < nr_backing_devices; i++) + backing_dev_fd[i] = dev_open(backing_devices[i], wipe_bcache); + + write_cache_sbs(cache_dev_fd, cache_set_sb, block_size, + bucket_sizes, num_bucket_sizes); + + for (i = 0; i < nr_backing_devices; i++) + write_backingdev_sb(backing_dev_fd[i], + block_size, bucket_sizes, + writeback, data_offset, + backing_dev_labels[i], + cache_set_sb->set_uuid); + + + return 0; +} + +int super_show (NihCommand *command, char *const *args) +{ + struct cache_sb sb_stack, *sb = &sb_stack; + size_t bytes = sizeof(*sb); + + int fd = open(show_dev, O_RDONLY); + if (fd < 0) { + printf("Can't open dev %s: %s\n", show_dev, strerror(errno)); + exit(2); + } + + if (pread(fd, sb, bytes, SB_START) != bytes) { + fprintf(stderr, "Couldn't read\n"); + exit(2); + } + + if (sb->keys) { + bytes = sizeof(*sb) + sb->keys * sizeof(uint64_t); + sb = malloc(bytes); + + if (pread(fd, sb, bytes, SB_START) != bytes) { + fprintf(stderr, "Couldn't read\n"); + exit(2); + } + } + + if (!SB_IS_BDEV(sb)) + show_super_cache(sb, force_csum); + else + show_super_backingdev(sb, force_csum); + + return 0; +} + +int probe_bcache (NihCommand *command, char *const *args) +{ + int i; + struct cache_sb sb; + char uuid[40]; + blkid_probe pr; + + for (i = 0; args[i]!=NULL; i++) { + int fd = open(args[i], O_RDONLY); + if (fd == -1) + continue; + + if (!(pr = blkid_new_probe())) + continue; + if (blkid_probe_set_device(pr, fd, 0, 0)) + continue; + /* probe partitions too */ + if (blkid_probe_enable_partitions(pr, true)) + continue; + /* bail if anything was found + * probe-bcache isn't needed once blkid recognizes bcache */ + if (!blkid_do_probe(pr)) { + continue; + } + + if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) + continue; + + if (memcmp(&sb.magic, &BCACHE_MAGIC, sizeof(sb.magic))) + continue; + + uuid_unparse(sb.uuid.b, uuid); + + if (udev) + printf("ID_FS_UUID=%s\n" + "ID_FS_UUID_ENC=%s\n" + "ID_FS_TYPE=bcache\n", + uuid, uuid); + else + printf("%s: UUID=\"\" TYPE=\"bcache\"\n", uuid); + } + + return 0; +} + +int bcache_register (NihCommand *command, char *const *args) +{ + int ret; + + bcachefd = open("/dev/bcache", O_RDWR); + if (bcachefd < 0) { + perror("Can't open bcache device"); + exit(EXIT_FAILURE); + } + + ret = ioctl(bcachefd, BCH_IOCTL_REGISTER, args); + if (ret < 0) { + fprintf(stderr, "ioctl error %d", ret); + exit(EXIT_FAILURE); + } + return 0; +} + +static NihCommand commands[] = { + {"format", N_("format "), "Format one or a list of devices with bcache datastructures. You need to do this before you create a volume", N_("format drive[s] with bcache"), NULL, make_bcache_options, make_bcache}, + {"show-sb", N_("show-sb "), "View a superblock on one or a list of bcache formated devices", N_("show superblock on each of the listed drive"), NULL, super_show_options, super_show}, + {"probe", N_("probe "), NULL, NULL, NULL, probe_bcache_options, probe_bcache}, + {"register", N_("register "), NULL, NULL, NULL, bcache_register_options, bcache_register}, + NIH_COMMAND_LAST +}; + + +int main(int argc, char *argv[]) +{ + int ret = 0; + nih_main_init (argv[0]); + + nih_option_set_synopsis (_("Manage bcache devices")); + nih_option_set_help ( + _("Helps you manage bcache devices")); + + ret = nih_command_parser (NULL, argc, argv, options, commands); + if (ret < 0) + exit (1); + + nih_signal_reset(); +} diff --git a/configure.ac b/configure.ac index a8039c00..f32ce3df 100644 --- a/configure.ac +++ b/configure.ac @@ -11,7 +11,6 @@ AC_CONFIG_MACRO_DIR([m4]) # Checks for programs. AC_PROG_CC - # Checks for libraries. # Checks for header files. From bc69c8fe047f02e3c93b1d99be149dcd17a73274 Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Wed, 15 Oct 2014 19:00:40 -0700 Subject: [PATCH 05/21] bcacheadm add list-cachesets and query-devs Change-Id: Ie2bc7ba8293d1d493c0a215119456e4bb9e659aa Signed-off-by: Jacob Malevich --- bcache.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++- bcache.h | 9 ++- bcacheadm.c | 133 ++++++++++++-------------------------------- 3 files changed, 198 insertions(+), 99 deletions(-) diff --git a/bcache.c b/bcache.c index 7e061649..bcc8f738 100644 --- a/bcache.c +++ b/bcache.c @@ -15,12 +15,17 @@ #include #include #include +#include #include #include #include #include "bcache.h" +#define __KERNEL__ +#include +#undef __KERNEL__ + const char * const cache_state[] = { "active", "ro", @@ -802,7 +807,7 @@ void show_super_backingdev(struct cache_sb *sb, bool force_csum) bdev_state[BDEV_STATE(sb)]); } -void show_cache_member(struct cache_sb *sb, unsigned i) +static void show_cache_member(struct cache_sb *sb, unsigned i) { struct cache_member *m = ((struct cache_member *) sb->d) + i; @@ -845,3 +850,151 @@ void show_super_cache(struct cache_sb *sb, bool force_csum) show_cache_member(sb, sb->nr_this_dev); } + +void query_dev(char *dev, bool force_csum) +{ + struct cache_sb sb_stack, *sb = &sb_stack; + size_t bytes = sizeof(*sb); + + int fd = open(dev, O_RDONLY); + if (fd < 0) { + printf("Can't open dev %s: %s\n", dev, strerror(errno)); + exit(2); + } + + if (pread(fd, sb, bytes, SB_START) != bytes) { + fprintf(stderr, "Couldn't read\n"); + exit(2); + } + + if (sb->keys) { + bytes = sizeof(*sb) + sb->keys * sizeof(uint64_t); + sb = malloc(bytes); + + if (pread(fd, sb, bytes, SB_START) != bytes) { + fprintf(stderr, "Couldn't read\n"); + exit(2); + } + } + + if (!SB_IS_BDEV(sb)) + show_super_cache(sb, force_csum); + else + show_super_backingdev(sb, force_csum); +} + +int list_cachesets(char *cset_dir) +{ + struct dirent *ent; + DIR *dir = opendir(cset_dir); + if (!dir) { + fprintf(stderr, "Failed to open dir %s\n", cset_dir); + return 1; + } + + while ((ent = readdir(dir)) != NULL) { + struct stat statbuf; + char entry[100]; + + if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) + continue; + + strcpy(entry, cset_dir); + strcat(entry, "/"); + strcat(entry, ent->d_name); + if(stat(entry, &statbuf) == -1) { + fprintf(stderr, "Failed to stat %s\n", entry); + return 1; + } + if (S_ISDIR(statbuf.st_mode)) { + printf("%s\n", ent->d_name); + } + } + + closedir(dir); + + return 0; +} + +char *parse_array_to_list(char *const *args) +{ + int i, len = 0; + char *space = " "; + for(i=0; args[i] != NULL; i++) { + len+=strlen(args[i]) + 1; + } + + char *arg_list = (char*)malloc(sizeof(char)*len); + strcpy(arg_list, args[0]); + strcat(arg_list, space); + + for(i=1; args[i] != NULL; i++) { + strcat(arg_list, args[i]); + strcat(arg_list, space); + } + + return arg_list; +} + +int register_bcache(char *devs) +{ + int ret, bcachefd; + + bcachefd = open("/dev/bcache", O_RDWR); + if (bcachefd < 0) { + perror("Can't open bcache device"); + exit(EXIT_FAILURE); + } + + ret = ioctl(bcachefd, BCH_IOCTL_REGISTER, devs); + if (ret < 0) { + fprintf(stderr, "ioctl error %d", ret); + exit(EXIT_FAILURE); + } + return 0; + +} + +int probe(char *dev, int udev) +{ + struct cache_sb sb; + char uuid[40]; + blkid_probe pr; + + int fd = open(dev, O_RDONLY); + if (fd == -1) + return -1; + + if (!(pr = blkid_new_probe())) + return -1; + if (blkid_probe_set_device(pr, fd, 0, 0)) + return -1; + /* probe partitions too */ + if (blkid_probe_enable_partitions(pr, true)) + return -1; + /* bail if anything was found + * probe-bcache isn't needed once blkid recognizes bcache */ + if (!blkid_do_probe(pr)) { + return -1; + } + + if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) + return -1; + + if (memcmp(&sb.magic, &BCACHE_MAGIC, sizeof(sb.magic))) + return -1; + + uuid_unparse(sb.uuid.b, uuid); + + if (udev) + printf("ID_FS_UUID=%s\n" + "ID_FS_UUID_ENC=%s\n" + "ID_FS_TYPE=bcache\n", + uuid, uuid); + else + printf("%s: UUID=\"\" TYPE=\"bcache\"\n", uuid); + + return 0; +} + + diff --git a/bcache.h b/bcache.h index 7f61a0e7..05c0989f 100644 --- a/bcache.h +++ b/bcache.h @@ -54,9 +54,16 @@ unsigned get_blocksize(const char *); long strtoul_or_die(const char *, size_t, const char *); void show_super_backingdev(struct cache_sb *, bool); -void show_cache_member(struct cache_sb *, unsigned); void show_super_cache(struct cache_sb *, bool); +void query_dev(char *dev, bool force_csum); +int list_cachesets(char *cset_dir); +char *parse_array_to_list(char *const *args); +int register_bcache(); +int probe(char *dev, int udev); + + + #define csum_set(i, type) \ ({ \ void *start = ((void *) (i)) + sizeof(uint64_t); \ diff --git a/bcacheadm.c b/bcacheadm.c index ecfc650c..ed65c6e7 100644 --- a/bcacheadm.c +++ b/bcacheadm.c @@ -28,9 +28,6 @@ #include #include #include //libbcache -#define __KERNEL__ -#include -#undef __KERNEL__ #define PACKAGE_NAME "bcacheadm" #define PACKAGE_VERSION "1.0" @@ -77,14 +74,12 @@ enum long_opts { /* super-show globals */ bool force_csum = false; -char *show_dev = NULL; - /* probe globals */ bool udev = false; -/* register globals */ -int bcachefd; +/* list globals */ +char *cset_dir = "/sys/fs/bcache"; /* make-bcache option setters */ static int set_CACHE_SET_UUID(NihOption *option, const char *arg) @@ -178,7 +173,6 @@ static NihOption make_bcache_options[] = { {'t', "tier", N_("tier of subsequent devices"), NULL,NULL, &tier, NULL}, {'p', "cache_replacement_policy", N_("one of (lru|fifo|random)"), NULL,NULL, &replacement_policy, NULL}, {'o', "data_offset", N_("data offset in sectors"), NULL,NULL, &data_offset, NULL}, - {'h', "help", N_("display this help and exit"), NULL,NULL, NULL, NULL}, {0, "cset-uuid", N_("UUID for the cache set"), NULL, NULL, NULL, set_CACHE_SET_UUID }, {0, "csum-type", N_("One of (none|crc32c|crc64)"), NULL, NULL, NULL, set_CSUM_TYPE }, @@ -193,13 +187,6 @@ static NihOption make_bcache_options[] = { NIH_OPTION_LAST }; -static NihOption super_show_options[] = { - {'f', "force_csum", N_("force_csum"), NULL, NULL, &force_csum, NULL}, - {0, "dev", N_("dev"), NULL, NULL, &show_dev, NULL}, - NIH_OPTION_LAST - -}; - static NihOption probe_bcache_options[] = { {'o', "udev", N_("udev"), NULL, NULL, NULL, set_udev}, NIH_OPTION_LAST @@ -209,6 +196,16 @@ static NihOption bcache_register_options[] = { NIH_OPTION_LAST }; +static NihOption query_devs_options[] = { + {'f', "force_csum", N_("force_csum"), NULL, NULL, &force_csum, NULL}, + NIH_OPTION_LAST +}; + +static NihOption list_cachesets_options[] = { + {'d', "dir", N_("directory"), NULL, NULL, &cset_dir, NULL}, + NIH_OPTION_LAST +}; + static NihOption options[] = { NIH_OPTION_LAST }; @@ -280,80 +277,12 @@ int make_bcache (NihCommand *command, char *const *args) return 0; } -int super_show (NihCommand *command, char *const *args) -{ - struct cache_sb sb_stack, *sb = &sb_stack; - size_t bytes = sizeof(*sb); - - int fd = open(show_dev, O_RDONLY); - if (fd < 0) { - printf("Can't open dev %s: %s\n", show_dev, strerror(errno)); - exit(2); - } - - if (pread(fd, sb, bytes, SB_START) != bytes) { - fprintf(stderr, "Couldn't read\n"); - exit(2); - } - - if (sb->keys) { - bytes = sizeof(*sb) + sb->keys * sizeof(uint64_t); - sb = malloc(bytes); - - if (pread(fd, sb, bytes, SB_START) != bytes) { - fprintf(stderr, "Couldn't read\n"); - exit(2); - } - } - - if (!SB_IS_BDEV(sb)) - show_super_cache(sb, force_csum); - else - show_super_backingdev(sb, force_csum); - - return 0; -} - int probe_bcache (NihCommand *command, char *const *args) { int i; - struct cache_sb sb; - char uuid[40]; - blkid_probe pr; - for (i = 0; args[i]!=NULL; i++) { - int fd = open(args[i], O_RDONLY); - if (fd == -1) - continue; - - if (!(pr = blkid_new_probe())) - continue; - if (blkid_probe_set_device(pr, fd, 0, 0)) - continue; - /* probe partitions too */ - if (blkid_probe_enable_partitions(pr, true)) - continue; - /* bail if anything was found - * probe-bcache isn't needed once blkid recognizes bcache */ - if (!blkid_do_probe(pr)) { - continue; - } - - if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) - continue; - - if (memcmp(&sb.magic, &BCACHE_MAGIC, sizeof(sb.magic))) - continue; - - uuid_unparse(sb.uuid.b, uuid); - - if (udev) - printf("ID_FS_UUID=%s\n" - "ID_FS_UUID_ENC=%s\n" - "ID_FS_TYPE=bcache\n", - uuid, uuid); - else - printf("%s: UUID=\"\" TYPE=\"bcache\"\n", uuid); + for (i = 0; args[i] != NULL; i++) { + probe(args[i], udev); } return 0; @@ -362,26 +291,36 @@ int probe_bcache (NihCommand *command, char *const *args) int bcache_register (NihCommand *command, char *const *args) { int ret; + char *arg_list = parse_array_to_list(args); - bcachefd = open("/dev/bcache", O_RDWR); - if (bcachefd < 0) { - perror("Can't open bcache device"); - exit(EXIT_FAILURE); + if(arg_list) { + ret = register_bcache(arg_list); + free(arg_list); } - ret = ioctl(bcachefd, BCH_IOCTL_REGISTER, args); - if (ret < 0) { - fprintf(stderr, "ioctl error %d", ret); - exit(EXIT_FAILURE); + return ret; +} + +int bcache_list_cachesets (NihCommand *command, char *const *args) +{ + return list_cachesets(cset_dir); +} + +int bcache_query_devs (NihCommand *command, char *const *args) +{ + int i; + + for (i = 0; args[i]!=NULL; i++) { + query_dev(args[i], false); } - return 0; } static NihCommand commands[] = { {"format", N_("format "), "Format one or a list of devices with bcache datastructures. You need to do this before you create a volume", N_("format drive[s] with bcache"), NULL, make_bcache_options, make_bcache}, - {"show-sb", N_("show-sb "), "View a superblock on one or a list of bcache formated devices", N_("show superblock on each of the listed drive"), NULL, super_show_options, super_show}, - {"probe", N_("probe "), NULL, NULL, NULL, probe_bcache_options, probe_bcache}, - {"register", N_("register "), NULL, NULL, NULL, bcache_register_options, bcache_register}, + {"probe", N_("probe "), "Does a blkid_probe on a device", N_("Does a blkid_probe on a device"), NULL, probe_bcache_options, probe_bcache}, + {"register", N_("register "), "Registers a list of devices", N_("Registers a list of devices"), NULL, bcache_register_options, bcache_register}, + {"list-cachesets", N_("list-cachesets"), "Lists cachesets in /sys/fs/bcache", N_("Lists cachesets in /sys/fs/bcache"), NULL, list_cachesets_options, bcache_list_cachesets}, + {"query-devs", N_("query "), "Gives info about the superblock of a list of devices", N_("show superblock on each of the listed drive"), NULL, query_devs_options, bcache_query_devs}, NIH_COMMAND_LAST }; From 637b614630affe6125efea65d7202aecd513fab9 Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Wed, 5 Nov 2014 17:45:57 -0800 Subject: [PATCH 06/21] bcacheadm status provides status for the newest sb version for each tier for all the devs passed in Change-Id: Ib6e5b08e65b5c36e7b1af0e9806efc39d069f94c Signed-off-by: Jacob Malevich --- bcache.c | 20 +++++++++++++-- bcache.h | 11 +++++---- bcacheadm.c | 70 +++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 84 insertions(+), 17 deletions(-) diff --git a/bcache.c b/bcache.c index bcc8f738..366962cd 100644 --- a/bcache.c +++ b/bcache.c @@ -851,7 +851,7 @@ void show_super_cache(struct cache_sb *sb, bool force_csum) show_cache_member(sb, sb->nr_this_dev); } -void query_dev(char *dev, bool force_csum) +struct cache_sb *query_dev(char *dev, bool force_csum) { struct cache_sb sb_stack, *sb = &sb_stack; size_t bytes = sizeof(*sb); @@ -877,6 +877,11 @@ void query_dev(char *dev, bool force_csum) } } + return sb; +} + +void print_dev_info(struct cache_sb *sb, bool force_csum) +{ if (!SB_IS_BDEV(sb)) show_super_cache(sb, force_csum); else @@ -891,6 +896,7 @@ int list_cachesets(char *cset_dir) fprintf(stderr, "Failed to open dir %s\n", cset_dir); return 1; } + printf("cachesets:\n"); while ((ent = readdir(dir)) != NULL) { struct stat statbuf; @@ -907,7 +913,7 @@ int list_cachesets(char *cset_dir) return 1; } if (S_ISDIR(statbuf.st_mode)) { - printf("%s\n", ent->d_name); + printf("\t%s\n", ent->d_name); } } @@ -997,4 +1003,14 @@ int probe(char *dev, int udev) return 0; } +void sb_state(struct cache_sb *sb, char *dev) +{ + struct cache_member *m = ((struct cache_member *) sb->d) + + sb->nr_this_dev; + printf("device %s\n", dev); + printf("\tcache state\t%s\n", cache_state[CACHE_STATE(m)]); + printf("\tcache_tier\t%llu\n", CACHE_TIER(m)); + printf("\tseq#: \t%llu\n", sb->seq); + +} diff --git a/bcache.h b/bcache.h index 05c0989f..c81d12fb 100644 --- a/bcache.h +++ b/bcache.h @@ -56,12 +56,13 @@ long strtoul_or_die(const char *, size_t, const char *); void show_super_backingdev(struct cache_sb *, bool); void show_super_cache(struct cache_sb *, bool); -void query_dev(char *dev, bool force_csum); -int list_cachesets(char *cset_dir); -char *parse_array_to_list(char *const *args); +struct cache_sb *query_dev(char *, bool); +int list_cachesets(char *); +char *parse_array_to_list(char *const *); int register_bcache(); -int probe(char *dev, int udev); - +int probe(char *, int); +void print_dev_info(struct cache_sb *, bool); +void sb_state(struct cache_sb *, char *); #define csum_set(i, type) \ diff --git a/bcacheadm.c b/bcacheadm.c index ed65c6e7..d9a9c462 100644 --- a/bcacheadm.c +++ b/bcacheadm.c @@ -33,9 +33,7 @@ #define PACKAGE_VERSION "1.0" #define PACKAGE_BUGREPORT "bugreport" -//What is the actual max? -#define MAX_DEVS 64 - +#define MAX_DEVS MAX_CACHES_PER_SET /* bcacheadm globals */ @@ -206,6 +204,10 @@ static NihOption list_cachesets_options[] = { NIH_OPTION_LAST }; +static NihOption status_options[] = { + NIH_OPTION_LAST +}; + static NihOption options[] = { NIH_OPTION_LAST }; @@ -310,17 +312,65 @@ int bcache_query_devs (NihCommand *command, char *const *args) { int i; - for (i = 0; args[i]!=NULL; i++) { - query_dev(args[i], false); + for (i = 0; args[i] != NULL; i++) { + struct cache_sb *sb = query_dev(args[i], false); + print_dev_info(sb, force_csum); } } +int bcache_status (NihCommand *command, char *const *args) +{ + int i; + struct cache_sb *sb_tier0 = NULL, *sb_tier1 = NULL; + char *dev0 = NULL, *dev1 = NULL; + + for (i = 0; args[i] != NULL; i++) { + struct cache_sb *sb = query_dev(args[i], false); + struct cache_member *m = ((struct cache_member *) sb->d) + + sb->nr_this_dev; + long long unsigned cache_tier = CACHE_TIER(m); + + if (!cache_tier) + if (!sb_tier0 || sb->seq > sb_tier0->seq) { + sb_tier0 = sb; + dev0 = args[i]; + } + else if (cache_tier == 1) + if (!sb_tier1 || sb->seq > sb_tier1->seq) { + sb_tier1 = sb; + dev1 = args[i]; + } + } + if (sb_tier0) sb_state(sb_tier0, dev0); + if (sb_tier1) sb_state(sb_tier1, dev1); +} + static NihCommand commands[] = { - {"format", N_("format "), "Format one or a list of devices with bcache datastructures. You need to do this before you create a volume", N_("format drive[s] with bcache"), NULL, make_bcache_options, make_bcache}, - {"probe", N_("probe "), "Does a blkid_probe on a device", N_("Does a blkid_probe on a device"), NULL, probe_bcache_options, probe_bcache}, - {"register", N_("register "), "Registers a list of devices", N_("Registers a list of devices"), NULL, bcache_register_options, bcache_register}, - {"list-cachesets", N_("list-cachesets"), "Lists cachesets in /sys/fs/bcache", N_("Lists cachesets in /sys/fs/bcache"), NULL, list_cachesets_options, bcache_list_cachesets}, - {"query-devs", N_("query "), "Gives info about the superblock of a list of devices", N_("show superblock on each of the listed drive"), NULL, query_devs_options, bcache_query_devs}, + {"format", N_("format "), + "Format one or a list of devices with bcache datastructures." + " You need to do this before you create a volume", + N_("format drive[s] with bcache"), + NULL, make_bcache_options, make_bcache}, + {"probe", N_("probe "), + "Does a blkid_probe on a device", + N_("Does a blkid_probe on a device"), + NULL, probe_bcache_options, probe_bcache}, + {"register", N_("register "), + "Registers a list of devices", + N_("Registers a list of devices"), + NULL, bcache_register_options, bcache_register}, + {"list-cachesets", N_("list-cachesets"), + "Lists cachesets in /sys/fs/bcache", + N_("Lists cachesets in /sys/fs/bcache"), + NULL, list_cachesets_options, bcache_list_cachesets}, + {"query-devs", N_("query "), + "Gives info about the superblock of a list of devices", + N_("show superblock on each of the listed drive"), + NULL, query_devs_options, bcache_query_devs}, + {"status", N_("status "), + "Finds the status of the most up to date superblock", + N_("Finds the status of the most up to date superblock"), + NULL, status_options, bcache_status}, NIH_COMMAND_LAST }; From 269761b11fb0a8b66291128b6cbbc533ebe98e11 Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Wed, 5 Nov 2014 19:38:27 -0800 Subject: [PATCH 07/21] bcacheadm status [FLAGS] FLAGS: --list -list all stats in the uuid directory --all -list all stats/values in the uuid directory --uuid -must pass in a uuid for the cacheset TODO: -subdirectory stats for individual caches -subdirectory stats for over time stats Change-Id: Ic7126a511fb17aa8c9ac7bf89e014ddbb719f46d Signed-off-by: Jacob Malevich --- bcache.c | 37 +++++++++++++++++++++++++++-- bcache.h | 2 ++ bcacheadm.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 102 insertions(+), 4 deletions(-) diff --git a/bcache.c b/bcache.c index 366962cd..d1ae1a6f 100644 --- a/bcache.c +++ b/bcache.c @@ -896,7 +896,6 @@ int list_cachesets(char *cset_dir) fprintf(stderr, "Failed to open dir %s\n", cset_dir); return 1; } - printf("cachesets:\n"); while ((ent = readdir(dir)) != NULL) { struct stat statbuf; @@ -913,7 +912,7 @@ int list_cachesets(char *cset_dir) return 1; } if (S_ISDIR(statbuf.st_mode)) { - printf("\t%s\n", ent->d_name); + printf("%s\n", ent->d_name); } } @@ -1014,3 +1013,37 @@ void sb_state(struct cache_sb *sb, char *dev) printf("\tseq#: \t%llu\n", sb->seq); } + +void read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, bool print_val) +{ + struct stat statbuf; + char entry[150]; + + strcpy(entry, stats_dir); + strcat(entry, "/"); + strcat(entry, stat_name); + if(stat(entry, &statbuf) == -1) { + fprintf(stderr, "Failed to stat %s\n", entry); + return; + } + + if (S_ISREG(statbuf.st_mode)) { + char buf[100]; + FILE *fp = NULL; + + fp = fopen(entry, "r"); + if(!fp) { + /* If we can't open the file, this is probably because + * of permissions, just move to the next file */ + return; + } + + while(fgets(buf, 100, fp)); + + if(print_val) + printf("%s\t%s", stat_name, buf); + else + printf("%s\n", stat_name); + fclose(fp); + } +} diff --git a/bcache.h b/bcache.h index c81d12fb..69b3345b 100644 --- a/bcache.h +++ b/bcache.h @@ -8,6 +8,7 @@ #define _BCACHE_H #include +#include typedef __u8 u8; typedef __u16 u16; @@ -63,6 +64,7 @@ int register_bcache(); int probe(char *, int); void print_dev_info(struct cache_sb *, bool); void sb_state(struct cache_sb *, char *); +void read_stat_dir(DIR *, char *, char *, bool); #define csum_set(i, type) \ diff --git a/bcacheadm.c b/bcacheadm.c index d9a9c462..29fe1249 100644 --- a/bcacheadm.c +++ b/bcacheadm.c @@ -27,6 +27,7 @@ #include #include #include +#include #include //libbcache #define PACKAGE_NAME "bcacheadm" @@ -60,7 +61,7 @@ int writeback = 0, discard = 0, wipe_bcache = 0; unsigned replication_set = 0, tier = 0, replacement_policy = 0; uint64_t data_offset = BDEV_DATA_START_DEFAULT; char *label = NULL; -struct cache_sb *cache_set_sb; +struct cache_sb *cache_set_sb = NULL; enum long_opts { CACHE_SET_UUID = 256, CSUM_TYPE, @@ -79,6 +80,14 @@ bool udev = false; /* list globals */ char *cset_dir = "/sys/fs/bcache"; +/* status globals */ +bool status_all = false; + +/* stats globals */ +bool stats_all = false; +bool stats_list = false; +static const char *stats_uuid = NULL; + /* make-bcache option setters */ static int set_CACHE_SET_UUID(NihOption *option, const char *arg) { @@ -145,7 +154,6 @@ static int set_bucket_sizes(NihOption *option, const char *arg) return 0; } - /* probe setters */ static int set_udev(NihOption *option, const char *arg) { @@ -205,6 +213,14 @@ static NihOption list_cachesets_options[] = { }; static NihOption status_options[] = { + {'a', "all", N_("all"), NULL, NULL, &status_all, NULL}, + NIH_OPTION_LAST +}; + +static NihOption stats_options[] = { + {'a', "all", N_("all"), NULL, NULL, &stats_all, NULL}, + {'l', "list", N_("list"), NULL, NULL, &stats_list, NULL}, + {'u', "uuid", N_("cache_set UUID"), NULL, "UUID", &stats_uuid, NULL}, NIH_OPTION_LAST }; @@ -345,6 +361,49 @@ int bcache_status (NihCommand *command, char *const *args) if (sb_tier1) sb_state(sb_tier1, dev1); } +int bcache_stats (NihCommand *command, char *const *args) +{ + /* all prints out a STAT:\tVALUE table + * list prints out a list of all STATS + * args contains a list of STAT, and prints their VALUE + */ + int i; + char *stats_dir = NULL; + DIR *dir = NULL; + struct dirent *ent = NULL; + + if (stats_uuid) { + /* + * dev or uuid must be passed in + * check that the given has an existing STAT directory + */ + stats_dir = (char*)malloc(sizeof(char)* + (strlen(cset_dir) + + strlen(stats_uuid) + 2)); + strcpy(stats_dir, cset_dir); + strcat(stats_dir, "/"); + strcat(stats_dir, stats_uuid); + + dir = opendir(stats_dir); + if (!dir) { + fprintf(stderr, "Failed to open dir %s\n", cset_dir); + return 1; + } + } else { + printf("Must provide a cacheset uuid\n"); + exit(EXIT_FAILURE); + } + + if(stats_list || stats_all) + while ((ent = readdir(dir)) != NULL) + read_stat_dir(dir, stats_dir, ent->d_name, stats_all); + + for (i = 0; args[i] != NULL; i++) + read_stat_dir(dir, stats_dir, args[i], true); + + closedir(dir); +} + static NihCommand commands[] = { {"format", N_("format "), "Format one or a list of devices with bcache datastructures." @@ -371,6 +430,10 @@ static NihCommand commands[] = { "Finds the status of the most up to date superblock", N_("Finds the status of the most up to date superblock"), NULL, status_options, bcache_status}, + {"stats", N_("stats "), + "List various bcache statistics", + N_("List various bcache statistics"), + NULL, stats_options, bcache_stats}, NIH_COMMAND_LAST }; From bae9ea7bbd80b94d99d835e295d7d25a97f8ee03 Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Thu, 6 Nov 2014 18:09:45 -0800 Subject: [PATCH 08/21] bcacheadm stats, add flags -c cache# displays stats for a specific cache in the cacheset --stats-five-min,hour,day,total specific stats for the cacheset Change-Id: I436d36d0853a250fe773573126c7a50a7251c72d Signed-off-by: Jacob Malevich --- bcacheadm.c | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/bcacheadm.c b/bcacheadm.c index 29fe1249..29a66572 100644 --- a/bcacheadm.c +++ b/bcacheadm.c @@ -87,6 +87,11 @@ bool status_all = false; bool stats_all = false; bool stats_list = false; static const char *stats_uuid = NULL; +static const char *stats_cache_num = NULL; +bool stats_five_min = false; +bool stats_hour = false; +bool stats_day = false; +bool stats_total = false; /* make-bcache option setters */ static int set_CACHE_SET_UUID(NihOption *option, const char *arg) @@ -221,6 +226,11 @@ static NihOption stats_options[] = { {'a', "all", N_("all"), NULL, NULL, &stats_all, NULL}, {'l', "list", N_("list"), NULL, NULL, &stats_list, NULL}, {'u', "uuid", N_("cache_set UUID"), NULL, "UUID", &stats_uuid, NULL}, + {'c', "cache", N_("cache number (starts from 0)"), NULL, "CACHE#", &stats_cache_num, NULL}, + {0, "five-min-stats", N_("stats accumulated in last 5 minutes"), NULL, NULL, &stats_five_min, NULL}, + {0, "hour-stats", N_("stats accumulated in last hour"), NULL, NULL, &stats_hour, NULL}, + {0, "day-stats", N_("stats accumulated in last day"), NULL, NULL, &stats_day, NULL}, + {0, "total-stats", N_("stats accumulated in total"), NULL, NULL, &stats_total, NULL}, NIH_OPTION_LAST }; @@ -361,29 +371,38 @@ int bcache_status (NihCommand *command, char *const *args) if (sb_tier1) sb_state(sb_tier1, dev1); } +static void stats_subdir(char* stats_dir) +{ + char tmp[50] = "/"; + if(stats_cache_num) { + strcat(tmp, "cache"); + strcat(tmp, stats_cache_num); + } else if (stats_five_min) + strcat(tmp, "stats_five_minute"); + else if (stats_hour) + strcat(tmp, "stats_hour"); + else if (stats_day) + strcat(tmp, "stats_day"); + else if (stats_total) + strcat(tmp, "stats_total"); + else + return; + + strcat(stats_dir, tmp); +} + int bcache_stats (NihCommand *command, char *const *args) { - /* all prints out a STAT:\tVALUE table - * list prints out a list of all STATS - * args contains a list of STAT, and prints their VALUE - */ int i; - char *stats_dir = NULL; + char stats_dir[200]; DIR *dir = NULL; struct dirent *ent = NULL; if (stats_uuid) { - /* - * dev or uuid must be passed in - * check that the given has an existing STAT directory - */ - stats_dir = (char*)malloc(sizeof(char)* - (strlen(cset_dir) + - strlen(stats_uuid) + 2)); strcpy(stats_dir, cset_dir); strcat(stats_dir, "/"); strcat(stats_dir, stats_uuid); - + stats_subdir(stats_dir); dir = opendir(stats_dir); if (!dir) { fprintf(stderr, "Failed to open dir %s\n", cset_dir); @@ -398,6 +417,7 @@ int bcache_stats (NihCommand *command, char *const *args) while ((ent = readdir(dir)) != NULL) read_stat_dir(dir, stats_dir, ent->d_name, stats_all); + for (i = 0; args[i] != NULL; i++) read_stat_dir(dir, stats_dir, args[i], true); From b602f0bf6a11952ec4700d55356b4cd1e5f2c84d Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Mon, 10 Nov 2014 15:37:58 -0800 Subject: [PATCH 09/21] Update some bcacheadm error messages Change-Id: Iddc638dacb7c68b621d686ba632da16fbe39bc15 Signed-off-by: Jacob Malevich --- bcache.c | 100 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 33 deletions(-) diff --git a/bcache.c b/bcache.c index d1ae1a6f..335668ea 100644 --- a/bcache.c +++ b/bcache.c @@ -374,13 +374,13 @@ uint64_t getblocks(int fd) uint64_t ret; struct stat statbuf; if (fstat(fd, &statbuf)) { - perror("stat error\n"); + perror("getblocks: stat error\n"); exit(EXIT_FAILURE); } ret = statbuf.st_size / 512; if (S_ISBLK(statbuf.st_mode)) if (ioctl(fd, BLKGETSIZE, &ret)) { - perror("ioctl error"); + perror("ioctl error getting blksize"); exit(EXIT_FAILURE); } return ret; @@ -438,12 +438,12 @@ static void do_write_sb(int fd, struct cache_sb *sb) /* Zero start of disk */ if (pwrite(fd, zeroes, SB_START, 0) != SB_START) { - perror("write error\n"); + 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\n"); + perror("write error trying to write superblock\n"); exit(EXIT_FAILURE); } @@ -503,36 +503,49 @@ int dev_open(const char *dev, bool wipe_bcache) struct cache_sb sb; blkid_probe pr; int fd; + char err[256]; if ((fd = open(dev, O_RDWR|O_EXCL)) == -1) { - fprintf(stderr, "Can't open dev %s: %s\n", dev, strerror(errno)); - exit(EXIT_FAILURE); + sprintf(err, "Can't open dev %s: %s\n", dev, strerror(errno)); + goto err; } - if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) - exit(EXIT_FAILURE); + if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) { + sprintf(err, "Failed to read superblock"); + goto err; + } if (!memcmp(&sb.magic, &BCACHE_MAGIC, 16) && !wipe_bcache) { - fprintf(stderr, "Already a bcache device on %s, " + sprintf(err, "Already a bcache device on %s, " "overwrite with --wipe-bcache\n", dev); - exit(EXIT_FAILURE); + goto err; } - if (!(pr = blkid_new_probe())) - exit(EXIT_FAILURE); - if (blkid_probe_set_device(pr, fd, 0, 0)) - exit(EXIT_FAILURE); + if (!(pr = blkid_new_probe())) { + sprintf(err, "Failed to create a new probe"); + goto err; + } + if (blkid_probe_set_device(pr, fd, 0, 0)) { + sprintf(err, "failed to set probe to device"); + goto err; + } /* enable ptable probing; superblock probing is enabled by default */ - if (blkid_probe_enable_partitions(pr, true)) - exit(EXIT_FAILURE); + if (blkid_probe_enable_partitions(pr, true)) { + sprintf(err, "Failed to enable partitions on probe"); + goto err; + } if (!blkid_do_probe(pr)) { /* XXX wipefs doesn't know how to remove partition tables */ - fprintf(stderr, "Device %s already has a non-bcache superblock, " - "remove it using wipefs and wipefs -a\n", dev); - exit(EXIT_FAILURE); + sprintf(err, "Device %s already has a non-bcache superblock, " + "remove it using wipefs and wipefs -a\n", dev); + goto err; } return fd; + + err: + fprintf(stderr, "dev_open failed with: %s", err); + exit(EXIT_FAILURE); } static unsigned min_bucket_size(int num_bucket_sizes, unsigned *bucket_sizes) @@ -953,7 +966,7 @@ int register_bcache(char *devs) ret = ioctl(bcachefd, BCH_IOCTL_REGISTER, devs); if (ret < 0) { - fprintf(stderr, "ioctl error %d", ret); + fprintf(stderr, "ioctl register error: %s", strerror(ret)); exit(EXIT_FAILURE); } return 0; @@ -965,29 +978,46 @@ int probe(char *dev, int udev) struct cache_sb sb; char uuid[40]; blkid_probe pr; + char *err = NULL; int fd = open(dev, O_RDONLY); - if (fd == -1) - return -1; + if (fd == -1) { + err = "Got file descriptor -1 trying to open dev"; + goto err; + } + + if (!(pr = blkid_new_probe())) { + err = "Failed trying to get a blkid for new probe"; + goto err; + } + + if (blkid_probe_set_device(pr, fd, 0, 0)) { + err = "Failed blkid probe set device"; + goto err; + } - if (!(pr = blkid_new_probe())) - return -1; - if (blkid_probe_set_device(pr, fd, 0, 0)) - return -1; /* probe partitions too */ - if (blkid_probe_enable_partitions(pr, true)) - return -1; + if (blkid_probe_enable_partitions(pr, true)) { + err = "Enable probe partitions"; + goto err; + } + /* bail if anything was found * probe-bcache isn't needed once blkid recognizes bcache */ if (!blkid_do_probe(pr)) { - return -1; + err = "blkid recognizes bcache"; + goto err; } - if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) - return -1; + if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) { + err = "Failed to read superblock"; + goto err; + } - if (memcmp(&sb.magic, &BCACHE_MAGIC, sizeof(sb.magic))) - return -1; + if (memcmp(&sb.magic, &BCACHE_MAGIC, sizeof(sb.magic))) { + err = "Bcache magic incorrect"; + goto err; + } uuid_unparse(sb.uuid.b, uuid); @@ -1000,6 +1030,10 @@ int probe(char *dev, int udev) printf("%s: UUID=\"\" TYPE=\"bcache\"\n", uuid); return 0; + + err: + fprintf(stderr, "Probe exit with error: %s", err); + return -1; } void sb_state(struct cache_sb *sb, char *dev) From 84eb67c6a647fb7277b30f940c3b219aaf457c6c Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Mon, 10 Nov 2014 18:42:36 -0800 Subject: [PATCH 10/21] Initial template for bcacheadm man page. TODO: Work with Kent to fill in descriptions for several items Change-Id: Iea4fe9e6a99842bf40b0213eecb61d48952aa1bb Signed-off-by: Jacob Malevich --- Makefile.am | 3 +- bcacheadm.8 | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 bcacheadm.8 diff --git a/Makefile.am b/Makefile.am index 1cc47d3a..67127a39 100644 --- a/Makefile.am +++ b/Makefile.am @@ -49,4 +49,5 @@ initramfsdir=$(prefix)/etc/initramfs-tools/hooks/ man8_MANS= bcache-super-show.8 \ make-bcache.8 \ - probe-bcache.8 + probe-bcache.8 \ + bcacheadm.8 diff --git a/bcacheadm.8 b/bcacheadm.8 new file mode 100644 index 00000000..84d919c1 --- /dev/null +++ b/bcacheadm.8 @@ -0,0 +1,153 @@ +.TH bcacheadm 8 +.SH NAME +bcacheadm \- manage bcache devices + +.SH SYNOPSIS +.B bcacheadm +[\fIoptions\fR] +.B COMMAND +[\fIoptions\fR] + +.SH COMMANDS +.TP +.BR format +.RS +Format one or a list of devices with bcache data structures. You need to do this before you create a volume. +.RE + +.BR register +.RS +Register a list of devices. +.RE + +.BR list-cachesets +.RS +List cachesets on this system. This just searches /sys/fs/bcache. +.RE + +.BR query-devs +.RS +Gives info about the superblock for a list of devices. +.RE + +.BR status +.RS +Finds the status of the most up to date superblock in each tier. Pass in a list of devices. +.RE + +.BR stats +.RS +List bcache specific statistics. Use --list to find out exactly what these are. To list stats for a cacheset, just give the cacheset uuid. To target a cache within the cacheset, use the -c option. To get time interval stats, use the hour, day, etc, options. +.RE + +.BR probe +.RS +Return UUID if device identified as bcache-formatted. +.PP +Only necessary until support for the bcache superblock is included +in blkid; in the meantime, provides just enough functionality for a udev script +to create the /dev/disk/by-uuid symlink. +.RE + +.BR help +.RS +List the bcacheadm commands +.RE + +.SH OPTIONS +.SH Options for bcacheadm +.TP +.BR \--help + + +.SH Options for format +.TP +.BR \-C +Create a cache +.TP +.BR \-B +Create a backing device +.TP +.BR \-b\ --bucket-size= +Specifies the bucket size. Allocation is done in terms of buckets, and cache +hits are counted per bucket; thus a smaller bucket size will give better cache +utilization, but poorer write performance. The bucket size is intended to be +equal to the size of your SSD's erase blocks, which seems to be 128k-512k for +most SSDs. Must be a power of two; accepts human readable units. Defaults to +128k. +.TP +.BR \-l\ --label= +label +.TP +.BR \-w,\ --block= +block size (hard sector size of SSD, often 2k +.TP +.BR \-t,\ --tier= +tier of subsequent devices +.TP +.BR \--cache-replacement-policy= +one of lru, fifo, or random +.TP +.BR \-o,\ --data_offset= +data offset in sectors +.TP +.BR \--cset-uuid= +Create a cache device with the specified UUID +.TP +.BR \--csum_type= +One of none, csc32c, or csc64 +.TP +.BR \--meta-replicas= +Number of metadata replicas +.TP +.BR \--data-replicas= +Number of data replicas +.TP +.BR \--wipe-bcache +Destroy existing bcache data if present +.TP +.BR \--discard +Enable discards +.TP +.BR \--writeback +Enable writeback + +.SH Options for register + +.SH Options for list-cachesets +.TP +.BR \-d,\ --dir= +Provide a directory other than /sys/fs/bcache + +.SH Options for query-devs +.TP +.BR \-f,\ --force-csum +Enables bcacheadm to going even if the superblock crc is invalid + +.SH Options for status + +.SH Options for stats +.TP +.BR \-a,\ --all +List all stats and their values for the given device. +.TP +.BR \-l,\ --list +List the names of the different stats for the given device. +.TP +.BR \-u,\ --uuid= +UUID for the cacheset +.TP +.BR \-c,\ --cache= +Cache number, starts from 0 +.TP +.BR \--five-min-stats +stats accumulated in the last 5 minutes +.TP +.BR \--hour-stats +stats accumulated in the last hour +.TP +.BR \--day-stats +stats accumulated in the last day +.TP +.BR \--total-stats +stats accumulated in total From 552dc9fa7d7e9fdac7cdddca793aaa5b2410196a Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Wed, 12 Nov 2014 15:22:38 -0800 Subject: [PATCH 11/21] bcacheadm: format bug fixes bcacheadm format is now working in replacement of make-bcache Change-Id: Ib152dde3b8dc1418d1508020529dd58e4cf5d222 Signed-off-by: Jacob Malevich --- Makefile.am | 1 + bcache.c | 2 +- bcacheadm.c | 166 ++++++++++++++++++++++++++++++---------------------- 3 files changed, 98 insertions(+), 71 deletions(-) diff --git a/Makefile.am b/Makefile.am index 67127a39..98ff957e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,6 +34,7 @@ bcache_test_LDFLAGS=-lm `pkg-config --libs openssl` bcache_test_CFLAGS=$(AM_CFLAGS) `pkg-config --cflags openssl` bcacheadm_SOURCES=bcacheadm.c +bcacheadm_CFLAGS=$(AM_CFLAGS) -g bcacheadm_LDFLAGS=$(AM_LDFLAGS) -lnih bcacheadm_LDADD=libbcache.a diff --git a/bcache.c b/bcache.c index 335668ea..375da69e 100644 --- a/bcache.c +++ b/bcache.c @@ -699,7 +699,7 @@ unsigned get_blocksize(const char *path) long strtoul_or_die(const char *p, size_t max, const char *msg) { errno = 0; - long v = strtol(optarg, NULL, 10); + long v = strtol(p, NULL, 10); if (errno || v < 0 || v >= max) { fprintf(stderr, "Invalid %s %zi\n", msg, v); exit(EXIT_FAILURE); diff --git a/bcacheadm.c b/bcacheadm.c index 29a66572..c7ae720c 100644 --- a/bcacheadm.c +++ b/bcacheadm.c @@ -50,15 +50,16 @@ enum exit { /* make-bcache globals */ int bdev = -1; int devs = 0; -const char *cache_devices[MAX_DEVS]; -const char *backing_devices[MAX_DEVS]; -const char *backing_dev_labels[MAX_DEVS]; -size_t i, nr_backing_devices = 0; +char *cache_devices[MAX_DEVS]; +unsigned tier_mapping[MAX_DEVS]; +char *backing_devices[MAX_DEVS]; +char *backing_dev_labels[MAX_DEVS]; +size_t i, nr_backing_devices = 0, nr_cache_devices = 0; unsigned block_size = 0; unsigned bucket_sizes[MAX_DEVS]; int num_bucket_sizes = 0; int writeback = 0, discard = 0, wipe_bcache = 0; -unsigned replication_set = 0, tier = 0, replacement_policy = 0; +unsigned replication_set = 0, replacement_policy = 0; uint64_t data_offset = BDEV_DATA_START_DEFAULT; char *label = NULL; struct cache_sb *cache_set_sb = NULL; @@ -69,6 +70,11 @@ enum long_opts { META_REPLICAS, DATA_REPLICAS, }; +const char *cache_set_uuid = 0; +const char *csum_type = 0; +char *metadata_replicas = 0; +char *data_replicas = 0; +unsigned tier = 0; /* super-show globals */ @@ -94,64 +100,42 @@ bool stats_day = false; bool stats_total = false; /* make-bcache option setters */ -static int set_CACHE_SET_UUID(NihOption *option, const char *arg) +static int set_block_size(NihOption *option, const char *arg) { - if(uuid_parse(arg, cache_set_sb->set_uuid.b)){ - fprintf(stderr, "Bad uuid\n"); - return -1; - } - return 0; -} -static int set_CSUM_TYPE(NihOption *option, const char *arg) -{ - SET_CACHE_PREFERRED_CSUM_TYPE(cache_set_sb, - read_string_list_or_die(arg, csum_types, - "csum type")); - return 0; -} -static int set_REPLICATION_SET(NihOption *option, const char *arg) -{ - replication_set = strtoul_or_die(arg, - CACHE_REPLICATION_SET_MAX, - "replication set"); - return 0; -} -static int set_META_REPLICAS(NihOption *option, const char *arg) -{ - SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb, - strtoul_or_die(arg, - CACHE_SET_META_REPLICAS_WANT_MAX, - "meta replicas")); - return 0; -} -static int set_DATA_REPLICAS(NihOption *option, const char *arg) -{ - SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb, - strtoul_or_die(arg, - CACHE_SET_DATA_REPLICAS_WANT_MAX, - "data replicas")); + block_size = hatoi_validate(arg, "block size"); return 0; } + static int set_cache(NihOption *option, const char *arg) { - bdev=0; - cache_devices[cache_set_sb->nr_in_set] = arg; - next_cache_device(cache_set_sb, - replication_set, - tier, - replacement_policy, - discard); + bdev = 0; + cache_devices[nr_cache_devices] = (char *)malloc(sizeof(char *) * + strlen(arg) + 1); + strcpy(cache_devices[nr_cache_devices], arg); + tier_mapping[nr_cache_devices] = tier; + devs++; - return 0; + nr_cache_devices++; } + static int set_bdev(NihOption *option, const char *arg) { - bdev=1; - backing_dev_labels[nr_backing_devices]=label; - backing_devices[nr_backing_devices++]=arg; + bdev = 1; + + backing_dev_labels[nr_backing_devices] = (char *)malloc(sizeof(char *) * + strlen(label) + 1); + strcpy(backing_dev_labels[nr_backing_devices], label); + + backing_devices[nr_backing_devices] = (char *)malloc(sizeof(char *) * + strlen(arg) + 1); + strcpy(backing_devices[nr_backing_devices], arg); + + nr_backing_devices++; devs++; + return 0; } + static int set_bucket_sizes(NihOption *option, const char *arg) { bucket_sizes[num_bucket_sizes]=hatoi_validate(arg, "bucket size"); @@ -174,22 +158,22 @@ static int set_udev(NihOption *option, const char *arg) /* options */ static NihOption make_bcache_options[] = { // {int shortoption, char* longoption, char* help, NihOptionGroup, char* argname, void *value, NihOptionSetter} - {'C', "cache", N_("Format a cache device"), NULL, NULL, NULL, set_cache}, - {'B', "bdev", N_("Format a backing device"), NULL, NULL, NULL, set_bdev}, - {'l', "label", N_("label"), NULL, NULL, &label, NULL}, + {'C', "cache", N_("Format a cache device"), NULL, "dev", NULL, set_cache}, + {'B', "bdev", N_("Format a backing device"), NULL, "dev", NULL, set_bdev}, + {'l', "label", N_("label"), NULL, "label", &label, NULL}, //Only one bucket_size supported until a list of bucket sizes is parsed correctly - {'b', "bucket", N_("bucket size"), NULL, NULL, NULL, set_bucket_sizes}, + {'b', "bucket", N_("bucket size"), NULL, "size", NULL, set_bucket_sizes}, //Does the default setter automatically convert strings to an int? - {'w', "block", N_("block size (hard sector size of SSD, often 2k"), NULL,NULL, &block_size, NULL}, - {'t', "tier", N_("tier of subsequent devices"), NULL,NULL, &tier, NULL}, - {'p', "cache_replacement_policy", N_("one of (lru|fifo|random)"), NULL,NULL, &replacement_policy, NULL}, - {'o', "data_offset", N_("data offset in sectors"), NULL,NULL, &data_offset, NULL}, + {'w', "block", N_("block size (hard sector size of SSD, often 2k"), NULL,"size", NULL, set_block_size}, + {'t', "tier", N_("tier of subsequent devices"), NULL,"#", &tier, NULL}, + {'p', "cache_replacement_policy", N_("one of (lru|fifo|random)"), NULL,"policy", &replacement_policy, NULL}, + {'o', "data_offset", N_("data offset in sectors"), NULL,"offset", &data_offset, NULL}, - {0, "cset-uuid", N_("UUID for the cache set"), NULL, NULL, NULL, set_CACHE_SET_UUID }, - {0, "csum-type", N_("One of (none|crc32c|crc64)"), NULL, NULL, NULL, set_CSUM_TYPE }, - {0, "replication-set",N_("replication set of subsequent devices"), NULL, NULL, NULL, set_REPLICATION_SET }, - {0, "meta-replicas",N_("number of metadata replicas"), NULL, NULL, NULL, set_META_REPLICAS}, - {0, "data-replicas",N_("number of data replicas"), NULL, NULL, NULL, set_DATA_REPLICAS }, + {0, "cset-uuid", N_("UUID for the cache set"), NULL, "uuid", &cache_set_uuid, NULL}, + {0, "csum-type", N_("One of (none|crc32c|crc64)"), NULL, "type", &csum_type, NULL }, + {0, "replication-set",N_("replication set of subsequent devices"), NULL, NULL, &replication_set, NULL }, + {0, "meta-replicas",N_("number of metadata replicas"), NULL, "#", &metadata_replicas, NULL}, + {0, "data-replicas",N_("number of data replicas"), NULL, "#", &data_replicas, NULL }, {0, "wipe-bcache", N_("destroy existing bcache data if present"), NULL, NULL, &wipe_bcache, NULL}, {0, "discard", N_("enable discards"), NULL, NULL, &discard, NULL}, @@ -245,22 +229,61 @@ int make_bcache (NihCommand *command, char *const *args) int cache_dev_fd[devs]; int backing_dev_fd[devs]; + printf("meta: %s, data: %s", metadata_replicas, data_replicas); cache_set_sb = calloc(1, sizeof(*cache_set_sb) + sizeof(struct cache_member) * devs); - uuid_generate(cache_set_sb->set_uuid.b); - SET_CACHE_PREFERRED_CSUM_TYPE(cache_set_sb, BCH_CSUM_CRC32C); - SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb, 1); - SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb, 1); + if (cache_set_uuid) { + if(uuid_parse(cache_set_uuid, cache_set_sb->set_uuid.b)) { + fprintf(stderr, "Bad uuid\n"); + return -1; + } + } else { + uuid_generate(cache_set_sb->set_uuid.b); + } - if(!bucket_sizes[0]) bucket_sizes[0] = 1024; + if (csum_type) { + SET_CACHE_PREFERRED_CSUM_TYPE(cache_set_sb, + read_string_list_or_die(csum_type, csum_types, + "csum type")); + } else { + SET_CACHE_PREFERRED_CSUM_TYPE(cache_set_sb, BCH_CSUM_CRC32C); + } + + if (metadata_replicas) { + SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb, + strtoul_or_die(metadata_replicas, + CACHE_SET_META_REPLICAS_WANT_MAX, + "meta replicas")); + } else { + SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb, 1); + } + + if (data_replicas) { + SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb, + strtoul_or_die(data_replicas, + CACHE_SET_DATA_REPLICAS_WANT_MAX, + "data replicas")); + } else { + SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb, 1); + } if (bdev == -1) { fprintf(stderr, "Please specify -C or -B\n"); exit(EXIT_FAILURE); } + if(!bucket_sizes[0]) bucket_sizes[0] = 1024; + + + for(i = 0; i < nr_cache_devices; i++) + next_cache_device(cache_set_sb, + replication_set, + tier_mapping[i], + replacement_policy, + discard); + if (!cache_set_sb->nr_in_set && !nr_backing_devices) { fprintf(stderr, "Please supply a device\n"); exit(EXIT_FAILURE); @@ -269,7 +292,8 @@ int make_bcache (NihCommand *command, char *const *args) i = 0; do { if (bucket_sizes[i] < block_size) { - fprintf(stderr, "Bucket size cannot be smaller than block size\n"); + fprintf(stderr, + "Bucket size cannot be smaller than block size\n"); exit(EXIT_FAILURE); } i++; @@ -338,7 +362,9 @@ int bcache_query_devs (NihCommand *command, char *const *args) { int i; + for (i = 0; args[i] != NULL; i++) { + printf("query-devs on :%s\n", args[i]); struct cache_sb *sb = query_dev(args[i], false); print_dev_info(sb, force_csum); } From 34f54790d5e6dce2ec9557f5c1a5e440502a9874 Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Wed, 12 Nov 2014 17:51:42 -0800 Subject: [PATCH 12/21] bcacheadm: fix tiering and backing device bugs TODO: Support multiple devices for a single -C or -B flag Change-Id: I73b18a39a0e0ff564600c2fc7386a785d3a10870 Signed-off-by: Jacob Malevich --- bcache.c | 2 +- bcache.h | 2 +- bcacheadm.c | 19 +++++++++++-------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/bcache.c b/bcache.c index 375da69e..444643dc 100644 --- a/bcache.c +++ b/bcache.c @@ -637,7 +637,7 @@ void write_cache_sbs(int *fds, struct cache_sb *sb, void next_cache_device(struct cache_sb *sb, unsigned replication_set, - unsigned tier, + int tier, unsigned replacement_policy, bool discard) { diff --git a/bcache.h b/bcache.h index 69b3345b..873fdb74 100644 --- a/bcache.h +++ b/bcache.h @@ -50,7 +50,7 @@ void write_backingdev_sb(int, unsigned, unsigned *, bool, uint64_t, const char *, uuid_le); int dev_open(const char *, bool); void write_cache_sbs(int *, struct cache_sb *, unsigned, unsigned *, int); -void next_cache_device(struct cache_sb *, unsigned, unsigned, unsigned, bool); +void next_cache_device(struct cache_sb *, unsigned, int, unsigned, bool); unsigned get_blocksize(const char *); long strtoul_or_die(const char *, size_t, const char *); diff --git a/bcacheadm.c b/bcacheadm.c index c7ae720c..e0cccb89 100644 --- a/bcacheadm.c +++ b/bcacheadm.c @@ -51,7 +51,7 @@ enum exit { int bdev = -1; int devs = 0; char *cache_devices[MAX_DEVS]; -unsigned tier_mapping[MAX_DEVS]; +int tier_mapping[MAX_DEVS]; char *backing_devices[MAX_DEVS]; char *backing_dev_labels[MAX_DEVS]; size_t i, nr_backing_devices = 0, nr_cache_devices = 0; @@ -74,7 +74,7 @@ const char *cache_set_uuid = 0; const char *csum_type = 0; char *metadata_replicas = 0; char *data_replicas = 0; -unsigned tier = 0; +char *tier = 0; /* super-show globals */ @@ -112,7 +112,10 @@ static int set_cache(NihOption *option, const char *arg) cache_devices[nr_cache_devices] = (char *)malloc(sizeof(char *) * strlen(arg) + 1); strcpy(cache_devices[nr_cache_devices], arg); - tier_mapping[nr_cache_devices] = tier; + if(!tier) + tier_mapping[nr_cache_devices] = 0; + else + tier_mapping[nr_cache_devices] = atoi(tier); devs++; nr_cache_devices++; @@ -122,9 +125,11 @@ static int set_bdev(NihOption *option, const char *arg) { bdev = 1; - backing_dev_labels[nr_backing_devices] = (char *)malloc(sizeof(char *) * - strlen(label) + 1); - strcpy(backing_dev_labels[nr_backing_devices], label); + if(label) { + backing_dev_labels[nr_backing_devices] = + (char *)malloc(sizeof(char *) * strlen(label) + 1); + strcpy(backing_dev_labels[nr_backing_devices], label); + } backing_devices[nr_backing_devices] = (char *)malloc(sizeof(char *) * strlen(arg) + 1); @@ -229,7 +234,6 @@ int make_bcache (NihCommand *command, char *const *args) int cache_dev_fd[devs]; int backing_dev_fd[devs]; - printf("meta: %s, data: %s", metadata_replicas, data_replicas); cache_set_sb = calloc(1, sizeof(*cache_set_sb) + sizeof(struct cache_member) * devs); @@ -276,7 +280,6 @@ int make_bcache (NihCommand *command, char *const *args) if(!bucket_sizes[0]) bucket_sizes[0] = 1024; - for(i = 0; i < nr_cache_devices; i++) next_cache_device(cache_set_sb, replication_set, From 7d34cf342e5d11c068f51162bfe50dcdaa0aac59 Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Thu, 13 Nov 2014 12:30:26 -0800 Subject: [PATCH 13/21] bcacheadm: register bcache ioctl already takes an argv, no need to parse it Change-Id: I0295ebde998c038feb40332ea303935035b8e2bd Signed-off-by: Jacob Malevich --- bcache.c | 24 ++---------------------- bcacheadm.c | 8 +------- 2 files changed, 3 insertions(+), 29 deletions(-) diff --git a/bcache.c b/bcache.c index 444643dc..5d1162f1 100644 --- a/bcache.c +++ b/bcache.c @@ -934,39 +934,19 @@ int list_cachesets(char *cset_dir) return 0; } -char *parse_array_to_list(char *const *args) -{ - int i, len = 0; - char *space = " "; - for(i=0; args[i] != NULL; i++) { - len+=strlen(args[i]) + 1; - } - - char *arg_list = (char*)malloc(sizeof(char)*len); - strcpy(arg_list, args[0]); - strcat(arg_list, space); - - for(i=1; args[i] != NULL; i++) { - strcat(arg_list, args[i]); - strcat(arg_list, space); - } - - return arg_list; -} - int register_bcache(char *devs) { int ret, bcachefd; bcachefd = open("/dev/bcache", O_RDWR); if (bcachefd < 0) { - perror("Can't open bcache device"); + perror("Can't open bcache device\n"); exit(EXIT_FAILURE); } ret = ioctl(bcachefd, BCH_IOCTL_REGISTER, devs); if (ret < 0) { - fprintf(stderr, "ioctl register error: %s", strerror(ret)); + fprintf(stderr, "ioctl register error: %s\n", strerror(ret)); exit(EXIT_FAILURE); } return 0; diff --git a/bcacheadm.c b/bcacheadm.c index e0cccb89..64ebb6b2 100644 --- a/bcacheadm.c +++ b/bcacheadm.c @@ -345,13 +345,7 @@ int probe_bcache (NihCommand *command, char *const *args) int bcache_register (NihCommand *command, char *const *args) { - int ret; - char *arg_list = parse_array_to_list(args); - - if(arg_list) { - ret = register_bcache(arg_list); - free(arg_list); - } + int ret = register_bcache(args); return ret; } From 3fda6adc197fd35abf9e762112d451076355d217 Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Thu, 13 Nov 2014 17:08:20 -0800 Subject: [PATCH 14/21] bcacheadm: list-cachesets --list-devs option lists the devices in each cacheset Change-Id: Ie3beb38203eefc3ab64b2a3d37652964f7021e54 Signed-off-by: Jacob Malevich --- bcache.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- bcache.h | 2 +- bcacheadm.c | 6 ++++-- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/bcache.c b/bcache.c index 5d1162f1..fc20e640 100644 --- a/bcache.c +++ b/bcache.c @@ -901,7 +901,43 @@ void print_dev_info(struct cache_sb *sb, bool force_csum) show_super_backingdev(sb, force_csum); } -int list_cachesets(char *cset_dir) +static void list_cacheset_devs(char *cset_dir, char *cset_name) { + int i = 0; + DIR *cachedir; + struct stat cache_stat; + char intbuf[4]; + char entry[256]; + + strcpy(entry, cset_dir); + strcat(entry, "/"); + strcat(entry, cset_name); + strcat(entry, "/cache0"); + snprintf(intbuf, 4, "%d", i); + + while(true) { + char buf[256]; + int len; + + if((cachedir = opendir(entry)) == NULL) + break; + + if(stat(entry, &cache_stat)) + break; + + if((len = readlink(entry, buf, sizeof(buf) - 1)) != -1) { + buf[len] = '\0'; + printf("\t%s\n", buf); + } + + /* remove i from end and append i++ */ + entry[strlen(entry)-strlen(intbuf)] = 0; + i++; + snprintf(intbuf, 4, "%d", i); + strcat(entry, intbuf); + } +} + +int list_cachesets(char *cset_dir, bool list_devs) { struct dirent *ent; DIR *dir = opendir(cset_dir); @@ -912,7 +948,8 @@ int list_cachesets(char *cset_dir) while ((ent = readdir(dir)) != NULL) { struct stat statbuf; - char entry[100]; + char entry[256]; + struct dirent *cache_ent; if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue; @@ -920,12 +957,18 @@ int list_cachesets(char *cset_dir) strcpy(entry, cset_dir); strcat(entry, "/"); strcat(entry, ent->d_name); + if(stat(entry, &statbuf) == -1) { fprintf(stderr, "Failed to stat %s\n", entry); return 1; } + if (S_ISDIR(statbuf.st_mode)) { printf("%s\n", ent->d_name); + + if(list_devs) { + list_cacheset_devs(cset_dir, ent->d_name); + } } } diff --git a/bcache.h b/bcache.h index 873fdb74..0dff6139 100644 --- a/bcache.h +++ b/bcache.h @@ -58,7 +58,7 @@ void show_super_backingdev(struct cache_sb *, bool); void show_super_cache(struct cache_sb *, bool); struct cache_sb *query_dev(char *, bool); -int list_cachesets(char *); +int list_cachesets(char *, bool); char *parse_array_to_list(char *const *); int register_bcache(); int probe(char *, int); diff --git a/bcacheadm.c b/bcacheadm.c index 64ebb6b2..57264307 100644 --- a/bcacheadm.c +++ b/bcacheadm.c @@ -85,6 +85,7 @@ bool udev = false; /* list globals */ char *cset_dir = "/sys/fs/bcache"; +bool list_devs = false; /* status globals */ bool status_all = false; @@ -203,6 +204,7 @@ static NihOption query_devs_options[] = { static NihOption list_cachesets_options[] = { {'d', "dir", N_("directory"), NULL, NULL, &cset_dir, NULL}, + {0, "list-devs", N_("list all devices in the cache sets as well"), NULL, NULL, &list_devs, NULL}, NIH_OPTION_LAST }; @@ -352,7 +354,7 @@ int bcache_register (NihCommand *command, char *const *args) int bcache_list_cachesets (NihCommand *command, char *const *args) { - return list_cachesets(cset_dir); + return list_cachesets(cset_dir, list_devs); } int bcache_query_devs (NihCommand *command, char *const *args) @@ -361,7 +363,7 @@ int bcache_query_devs (NihCommand *command, char *const *args) for (i = 0; args[i] != NULL; i++) { - printf("query-devs on :%s\n", args[i]); + printf("query-devs on: %s\n", args[i]); struct cache_sb *sb = query_dev(args[i], false); print_dev_info(sb, force_csum); } From 28271115d7ce70933e3366e9c2b050c975660bcf Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Thu, 13 Nov 2014 17:31:39 -0800 Subject: [PATCH 15/21] bcache query-dev fixes, and don't print the sb out for status Change-Id: I909ac15ca32a9cdecd6c7455e884d14f30ab0188 Signed-off-by: Jacob Malevich --- bcache.c | 17 ++++++++--------- bcache.h | 3 +-- bcacheadm.c | 9 +++------ 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/bcache.c b/bcache.c index fc20e640..6ba5fad7 100644 --- a/bcache.c +++ b/bcache.c @@ -864,7 +864,7 @@ void show_super_cache(struct cache_sb *sb, bool force_csum) show_cache_member(sb, sb->nr_this_dev); } -struct cache_sb *query_dev(char *dev, bool force_csum) +struct cache_sb *query_dev(char *dev, bool force_csum, bool print_sb) { struct cache_sb sb_stack, *sb = &sb_stack; size_t bytes = sizeof(*sb); @@ -890,15 +890,14 @@ struct cache_sb *query_dev(char *dev, bool force_csum) } } - return sb; -} + if(print_sb) { + if (!SB_IS_BDEV(sb)) + show_super_cache(sb, force_csum); + else + show_super_backingdev(sb, force_csum); + } -void print_dev_info(struct cache_sb *sb, bool force_csum) -{ - if (!SB_IS_BDEV(sb)) - show_super_cache(sb, force_csum); - else - show_super_backingdev(sb, force_csum); + return sb; } static void list_cacheset_devs(char *cset_dir, char *cset_name) { diff --git a/bcache.h b/bcache.h index 0dff6139..3a551d1e 100644 --- a/bcache.h +++ b/bcache.h @@ -57,12 +57,11 @@ long strtoul_or_die(const char *, size_t, const char *); void show_super_backingdev(struct cache_sb *, bool); void show_super_cache(struct cache_sb *, bool); -struct cache_sb *query_dev(char *, bool); +struct cache_sb *query_dev(char *, bool, bool); int list_cachesets(char *, bool); char *parse_array_to_list(char *const *); int register_bcache(); int probe(char *, int); -void print_dev_info(struct cache_sb *, bool); void sb_state(struct cache_sb *, char *); void read_stat_dir(DIR *, char *, char *, bool); diff --git a/bcacheadm.c b/bcacheadm.c index 57264307..76e53941 100644 --- a/bcacheadm.c +++ b/bcacheadm.c @@ -362,11 +362,8 @@ int bcache_query_devs (NihCommand *command, char *const *args) int i; - for (i = 0; args[i] != NULL; i++) { - printf("query-devs on: %s\n", args[i]); - struct cache_sb *sb = query_dev(args[i], false); - print_dev_info(sb, force_csum); - } + for (i = 0; args[i] != NULL; i++) + query_dev(args[i], force_csum, true); } int bcache_status (NihCommand *command, char *const *args) @@ -376,7 +373,7 @@ int bcache_status (NihCommand *command, char *const *args) char *dev0 = NULL, *dev1 = NULL; for (i = 0; args[i] != NULL; i++) { - struct cache_sb *sb = query_dev(args[i], false); + struct cache_sb *sb = query_dev(args[i], false, false); struct cache_member *m = ((struct cache_member *) sb->d) + sb->nr_this_dev; long long unsigned cache_tier = CACHE_TIER(m); From 4603dcf36b07230277474c6db76d76a128edaa5a Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Fri, 14 Nov 2014 11:24:02 -0800 Subject: [PATCH 16/21] Option for returning only the uuid of the dev when doing a query-dev Change-Id: Ia055da0516bc7baac836642fa1405b77adfc5139 Signed-off-by: Jacob Malevich --- bcache.c | 14 +++++++++++++- bcache.h | 2 +- bcacheadm.c | 8 +++++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/bcache.c b/bcache.c index 6ba5fad7..4b9c66c4 100644 --- a/bcache.c +++ b/bcache.c @@ -718,6 +718,12 @@ static void print_encode(char *in) printf("%%%x", *pos); } +static void show_uuid_only(struct cache_sb *sb) { + char uuid[40]; + uuid_unparse(sb->uuid.b, uuid); + printf("%s\n", uuid); +} + static void show_super_common(struct cache_sb *sb, bool force_csum) { char uuid[40]; @@ -864,7 +870,8 @@ void show_super_cache(struct cache_sb *sb, bool force_csum) show_cache_member(sb, sb->nr_this_dev); } -struct cache_sb *query_dev(char *dev, bool force_csum, bool print_sb) +struct cache_sb *query_dev(char *dev, bool force_csum, + bool print_sb, bool uuid_only) { struct cache_sb sb_stack, *sb = &sb_stack; size_t bytes = sizeof(*sb); @@ -890,6 +897,11 @@ struct cache_sb *query_dev(char *dev, bool force_csum, bool print_sb) } } + if(uuid_only) { + show_uuid_only(sb); + return sb; + } + if(print_sb) { if (!SB_IS_BDEV(sb)) show_super_cache(sb, force_csum); diff --git a/bcache.h b/bcache.h index 3a551d1e..e10c73c7 100644 --- a/bcache.h +++ b/bcache.h @@ -57,7 +57,7 @@ long strtoul_or_die(const char *, size_t, const char *); void show_super_backingdev(struct cache_sb *, bool); void show_super_cache(struct cache_sb *, bool); -struct cache_sb *query_dev(char *, bool, bool); +struct cache_sb *query_dev(char *, bool, bool, bool); int list_cachesets(char *, bool); char *parse_array_to_list(char *const *); int register_bcache(); diff --git a/bcacheadm.c b/bcacheadm.c index 76e53941..76ad0c6b 100644 --- a/bcacheadm.c +++ b/bcacheadm.c @@ -77,8 +77,9 @@ char *data_replicas = 0; char *tier = 0; -/* super-show globals */ +/* query-dev globals */ bool force_csum = false; +bool uuid_only = false; /* probe globals */ bool udev = false; @@ -199,6 +200,7 @@ static NihOption bcache_register_options[] = { static NihOption query_devs_options[] = { {'f', "force_csum", N_("force_csum"), NULL, NULL, &force_csum, NULL}, + {'u', "uuid-only", N_("only print out the uuid for the devices, not the whole superblock"), NULL, NULL, &uuid_only, NULL}, NIH_OPTION_LAST }; @@ -363,7 +365,7 @@ int bcache_query_devs (NihCommand *command, char *const *args) for (i = 0; args[i] != NULL; i++) - query_dev(args[i], force_csum, true); + query_dev(args[i], force_csum, true, uuid_only); } int bcache_status (NihCommand *command, char *const *args) @@ -373,7 +375,7 @@ int bcache_status (NihCommand *command, char *const *args) char *dev0 = NULL, *dev1 = NULL; for (i = 0; args[i] != NULL; i++) { - struct cache_sb *sb = query_dev(args[i], false, false); + struct cache_sb *sb = query_dev(args[i], false, false, false); struct cache_member *m = ((struct cache_member *) sb->d) + sb->nr_this_dev; long long unsigned cache_tier = CACHE_TIER(m); From 34980cc0df9892909f893f029cefee4c7df55ffd Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Fri, 14 Nov 2014 14:29:05 -0800 Subject: [PATCH 17/21] bcacheadm: dev path parsing Parse out the dev name for list-cachesets --list-devs This gives the dev path that will be needed for query-dev to get the superblock Change-Id: I333cd8a0e593e02d7635111309b8aff14050cc41 Signed-off-by: Jacob Malevich --- bcache.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/bcache.c b/bcache.c index 4b9c66c4..72adccad 100644 --- a/bcache.c +++ b/bcache.c @@ -912,7 +912,24 @@ struct cache_sb *query_dev(char *dev, bool force_csum, return sb; } -static void list_cacheset_devs(char *cset_dir, char *cset_name) { +static void dev_name(char *ugly_path) { + char buf[32]; + int i, end = strlen(ugly_path); + + //Chop off "/bcache", then look for the next '/' from the end + for (i = end - 8; ; i--) + if(ugly_path[i] == '/') + break; + + strcpy(buf, ugly_path + i); + buf[end - i - 7] = 0; + + // Is the dev guaranteed to be in /dev? + // This is needed for finding the superblock with a query-dev + printf("/dev%s\n", buf); +} + +static void list_cacheset_devs(char *cset_dir, char *cset_name, bool parse_dev_name) { int i = 0; DIR *cachedir; struct stat cache_stat; @@ -937,7 +954,10 @@ static void list_cacheset_devs(char *cset_dir, char *cset_name) { if((len = readlink(entry, buf, sizeof(buf) - 1)) != -1) { buf[len] = '\0'; - printf("\t%s\n", buf); + if(parse_dev_name) + dev_name(buf); + else + printf("\t%s\n", buf); } /* remove i from end and append i++ */ @@ -978,7 +998,7 @@ int list_cachesets(char *cset_dir, bool list_devs) printf("%s\n", ent->d_name); if(list_devs) { - list_cacheset_devs(cset_dir, ent->d_name); + list_cacheset_devs(cset_dir, ent->d_name, true); } } } From 6ad19a812b1f1daefed42c8cbfb606afe18b38e5 Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Tue, 18 Nov 2014 14:14:13 -0800 Subject: [PATCH 18/21] bcacheadm: add ability to find a dev uuid within a cacheset simplifies input for finding stats for a single dev Change-Id: I5d879aaa8cb68aaaedabd2bc780fbea4994e2541 Signed-off-by: Jacob Malevich --- bcache.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++----- bcache.h | 4 +-- bcacheadm.8 | 5 +++- bcacheadm.c | 20 +++++++++----- 4 files changed, 89 insertions(+), 16 deletions(-) diff --git a/bcache.c b/bcache.c index 72adccad..1e3668a1 100644 --- a/bcache.c +++ b/bcache.c @@ -718,10 +718,8 @@ static void print_encode(char *in) printf("%%%x", *pos); } -static void show_uuid_only(struct cache_sb *sb) { - char uuid[40]; - uuid_unparse(sb->uuid.b, uuid); - printf("%s\n", uuid); +static void show_uuid_only(struct cache_sb *sb, char *dev_uuid) { + uuid_unparse(sb->uuid.b, dev_uuid); } static void show_super_common(struct cache_sb *sb, bool force_csum) @@ -871,7 +869,7 @@ void show_super_cache(struct cache_sb *sb, bool force_csum) } struct cache_sb *query_dev(char *dev, bool force_csum, - bool print_sb, bool uuid_only) + bool print_sb, bool uuid_only, char *dev_uuid) { struct cache_sb sb_stack, *sb = &sb_stack; size_t bytes = sizeof(*sb); @@ -898,7 +896,7 @@ struct cache_sb *query_dev(char *dev, bool force_csum, } if(uuid_only) { - show_uuid_only(sb); + show_uuid_only(sb, dev_uuid); return sb; } @@ -968,6 +966,70 @@ static void list_cacheset_devs(char *cset_dir, char *cset_name, bool parse_dev_n } } +void find_matching_uuid(char *stats_dir, char *subdir, const char *stats_dev_uuid) { + /* Do a query-dev --uuid only to get the uuid + * repeat on each dev until we find a matching one + * append that cache# to subdir and return + */ + + int i = 0; + DIR *cachedir; + struct stat cache_stat; + char intbuf[4]; + char entry[256]; + + strcpy(entry, stats_dir); + strcat(entry, subdir); + snprintf(intbuf, 4, "%d", i); + strcat(entry, intbuf); + + while(true) { + char buf[256]; + int len; + + if((cachedir = opendir(entry)) == NULL) + break; + + if(stat(entry, &cache_stat)) + break; + + if((len = readlink(entry, buf, sizeof(buf) - 1)) != -1) { + char dev_uuid[40]; + buf[len] = '\0'; + int i, end = strlen(buf); + char tmp[32], devname[32]; + + /* Chop off "/bcache", then look for the + * next '/' from the end + */ + for (i = end - 8; ; i--) + if(buf[i] == '/') + break; + + strcpy(tmp, buf + i); + tmp[end - i - 7] = 0; + strcpy(devname, "/dev"); + strcat(devname, tmp); + + query_dev(devname, false, false, true, dev_uuid); + if(!strcmp(stats_dev_uuid, dev_uuid)) { + strcat(subdir, intbuf); + return; + } + } + + /* remove i from end and append i++ */ + entry[strlen(entry)-strlen(intbuf)] = 0; + i++; + snprintf(intbuf, 4, "%d", i); + strcat(entry, intbuf); + } + + + printf("dev uuid doesn't exist in cache_set\n"); + exit(1); +} + int list_cachesets(char *cset_dir, bool list_devs) { struct dirent *ent; @@ -1129,7 +1191,7 @@ void read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, bool print_val) while(fgets(buf, 100, fp)); if(print_val) - printf("%s\t%s", stat_name, buf); + printf("%s\n", buf); else printf("%s\n", stat_name); fclose(fp); diff --git a/bcache.h b/bcache.h index e10c73c7..efd7525e 100644 --- a/bcache.h +++ b/bcache.h @@ -57,14 +57,14 @@ long strtoul_or_die(const char *, size_t, const char *); void show_super_backingdev(struct cache_sb *, bool); void show_super_cache(struct cache_sb *, bool); -struct cache_sb *query_dev(char *, bool, bool, bool); +struct cache_sb *query_dev(char *, bool, bool, bool, char *dev_uuid); int list_cachesets(char *, bool); char *parse_array_to_list(char *const *); int register_bcache(); int probe(char *, int); void sb_state(struct cache_sb *, char *); void read_stat_dir(DIR *, char *, char *, bool); - +void find_matching_uuid(char *, char *, const char*); #define csum_set(i, type) \ ({ \ diff --git a/bcacheadm.8 b/bcacheadm.8 index 84d919c1..0ff96697 100644 --- a/bcacheadm.8 +++ b/bcacheadm.8 @@ -134,9 +134,12 @@ List all stats and their values for the given device. .BR \-l,\ --list List the names of the different stats for the given device. .TP -.BR \-u,\ --uuid= +.BR \-u,\ --set= UUID for the cacheset .TP +.BR \-d,\ --dev= +UUID for a device within the cacheset. Must pass in the cacheset UUID in order to search for a dev. +.TP .BR \-c,\ --cache= Cache number, starts from 0 .TP diff --git a/bcacheadm.c b/bcacheadm.c index 76ad0c6b..e1d92509 100644 --- a/bcacheadm.c +++ b/bcacheadm.c @@ -95,6 +95,7 @@ bool status_all = false; bool stats_all = false; bool stats_list = false; static const char *stats_uuid = NULL; +static const char *stats_dev_uuid = NULL; static const char *stats_cache_num = NULL; bool stats_five_min = false; bool stats_hour = false; @@ -218,7 +219,8 @@ static NihOption status_options[] = { static NihOption stats_options[] = { {'a', "all", N_("all"), NULL, NULL, &stats_all, NULL}, {'l', "list", N_("list"), NULL, NULL, &stats_list, NULL}, - {'u', "uuid", N_("cache_set UUID"), NULL, "UUID", &stats_uuid, NULL}, + {'u', "set", N_("cache_set UUID"), NULL, "UUID", &stats_uuid, NULL}, + {'d', "dev", N_("dev UUID"), NULL, "UUID", &stats_dev_uuid, NULL}, {'c', "cache", N_("cache number (starts from 0)"), NULL, "CACHE#", &stats_cache_num, NULL}, {0, "five-min-stats", N_("stats accumulated in last 5 minutes"), NULL, NULL, &stats_five_min, NULL}, {0, "hour-stats", N_("stats accumulated in last hour"), NULL, NULL, &stats_hour, NULL}, @@ -363,9 +365,12 @@ int bcache_query_devs (NihCommand *command, char *const *args) { int i; - - for (i = 0; args[i] != NULL; i++) - query_dev(args[i], force_csum, true, uuid_only); + for (i = 0; args[i] != NULL; i++){ + char dev_uuid[40]; + query_dev(args[i], force_csum, true, uuid_only, dev_uuid); + if(uuid_only) + printf("%s\n", dev_uuid); + } } int bcache_status (NihCommand *command, char *const *args) @@ -375,7 +380,7 @@ int bcache_status (NihCommand *command, char *const *args) char *dev0 = NULL, *dev1 = NULL; for (i = 0; args[i] != NULL; i++) { - struct cache_sb *sb = query_dev(args[i], false, false, false); + struct cache_sb *sb = query_dev(args[i], false, false, false, NULL); struct cache_member *m = ((struct cache_member *) sb->d) + sb->nr_this_dev; long long unsigned cache_tier = CACHE_TIER(m); @@ -398,7 +403,10 @@ int bcache_status (NihCommand *command, char *const *args) static void stats_subdir(char* stats_dir) { char tmp[50] = "/"; - if(stats_cache_num) { + if(stats_dev_uuid) { + strcat(tmp, "cache"); + find_matching_uuid(stats_dir, tmp, stats_dev_uuid); + } else if(stats_cache_num) { strcat(tmp, "cache"); strcat(tmp, stats_cache_num); } else if (stats_five_min) From 7a80b660c2dbf8f0c3e5cd347f970d4a24a00326 Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Fri, 21 Nov 2014 14:42:07 -0800 Subject: [PATCH 19/21] bcacheadm unregister devices uses unregister ioctl to unregister a cacheset that the device belongs to Change-Id: I01772de3471888c4951f050b3e92f41b58c5d103 Signed-off-by: Jacob Malevich --- bcache.c | 27 +++++++++++++++++++++++---- bcache.h | 5 ++++- bcacheadm.c | 15 +++++++++++++++ 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/bcache.c b/bcache.c index 1e3668a1..82232c80 100644 --- a/bcache.c +++ b/bcache.c @@ -1070,15 +1070,21 @@ int list_cachesets(char *cset_dir, bool list_devs) return 0; } -int register_bcache(char *devs) +static int get_bcache_fd() { - int ret, bcachefd; - - bcachefd = open("/dev/bcache", O_RDWR); + int bcachefd = open("/dev/bcache", O_RDWR); if (bcachefd < 0) { perror("Can't open bcache device\n"); exit(EXIT_FAILURE); } + return bcachefd; +} + +int register_bcache(char *const *devs) +{ + int ret, bcachefd; + + bcachefd = get_bcache_fd(); ret = ioctl(bcachefd, BCH_IOCTL_REGISTER, devs); if (ret < 0) { @@ -1086,7 +1092,20 @@ int register_bcache(char *devs) exit(EXIT_FAILURE); } return 0; +} +int unregister_bcache(char *const *devs) +{ + int ret, bcachefd; + + bcachefd = get_bcache_fd(); + + ret = ioctl(bcachefd, BCH_IOCTL_UNREGISTER, devs); + if (ret < 0) { + fprintf(stderr, "ioctl unregister error: %s\n", strerror(ret)); + exit(EXIT_FAILURE); + } + return 0; } int probe(char *dev, int udev) diff --git a/bcache.h b/bcache.h index efd7525e..41bf13dd 100644 --- a/bcache.h +++ b/bcache.h @@ -60,11 +60,14 @@ void show_super_cache(struct cache_sb *, bool); struct cache_sb *query_dev(char *, bool, bool, bool, char *dev_uuid); int list_cachesets(char *, bool); char *parse_array_to_list(char *const *); -int register_bcache(); +int register_bcache(char *const *); +int unregister_bcache(char *const *); int probe(char *, int); void sb_state(struct cache_sb *, char *); void read_stat_dir(DIR *, char *, char *, bool); void find_matching_uuid(char *, char *, const char*); +//int add_device(char *); +//int remove_device(char *); #define csum_set(i, type) \ ({ \ diff --git a/bcacheadm.c b/bcacheadm.c index e1d92509..913e4ca0 100644 --- a/bcacheadm.c +++ b/bcacheadm.c @@ -199,6 +199,10 @@ static NihOption bcache_register_options[] = { NIH_OPTION_LAST }; +static NihOption bcache_unregister_options[] = { + NIH_OPTION_LAST +}; + static NihOption query_devs_options[] = { {'f', "force_csum", N_("force_csum"), NULL, NULL, &force_csum, NULL}, {'u', "uuid-only", N_("only print out the uuid for the devices, not the whole superblock"), NULL, NULL, &uuid_only, NULL}, @@ -356,6 +360,13 @@ int bcache_register (NihCommand *command, char *const *args) return ret; } +int bcache_unregister (NihCommand *command, char *const *args) +{ + int ret = unregister_bcache(args); + + return ret; +} + int bcache_list_cachesets (NihCommand *command, char *const *args) { return list_cachesets(cset_dir, list_devs); @@ -470,6 +481,10 @@ static NihCommand commands[] = { "Registers a list of devices", N_("Registers a list of devices"), NULL, bcache_register_options, bcache_register}, + {"unregister", N_("unregister "), + "Unregisters a list of devices", + N_("Unregisters a list of devices"), + NULL, bcache_unregister_options, bcache_unregister}, {"list-cachesets", N_("list-cachesets"), "Lists cachesets in /sys/fs/bcache", N_("Lists cachesets in /sys/fs/bcache"), From 0098187201458056948a618d9136cd9322070dd9 Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Mon, 24 Nov 2014 15:53:35 -0800 Subject: [PATCH 20/21] Fix string parsing Change-Id: I0edd8f1e247ae802cdccf871a40b50d8a8714433 Signed-off-by: Jacob Malevich --- bcache.c | 44 ++++++++++++++++++++------------------------ bcache.h | 1 + bcacheadm.8 | 7 +------ bcacheadm.c | 37 ++++++++++++++++++++----------------- 4 files changed, 42 insertions(+), 47 deletions(-) diff --git a/bcache.c b/bcache.c index 82232c80..06b06cf1 100644 --- a/bcache.c +++ b/bcache.c @@ -503,7 +503,7 @@ int dev_open(const char *dev, bool wipe_bcache) struct cache_sb sb; blkid_probe pr; int fd; - char err[256]; + char err[MAX_PATH]; if ((fd = open(dev, O_RDWR|O_EXCL)) == -1) { sprintf(err, "Can't open dev %s: %s\n", dev, strerror(errno)); @@ -910,7 +910,7 @@ struct cache_sb *query_dev(char *dev, bool force_csum, return sb; } -static void dev_name(char *ugly_path) { +static void dev_name(const char *ugly_path) { char buf[32]; int i, end = strlen(ugly_path); @@ -932,16 +932,13 @@ static void list_cacheset_devs(char *cset_dir, char *cset_name, bool parse_dev_n DIR *cachedir; struct stat cache_stat; char intbuf[4]; - char entry[256]; + char entry[MAX_PATH]; - strcpy(entry, cset_dir); - strcat(entry, "/"); - strcat(entry, cset_name); - strcat(entry, "/cache0"); + snprintf(entry, MAX_PATH, "%s/%s/cache0", cset_dir, cset_name); snprintf(intbuf, 4, "%d", i); while(true) { - char buf[256]; + char buf[MAX_PATH]; int len; if((cachedir = opendir(entry)) == NULL) @@ -976,15 +973,14 @@ void find_matching_uuid(char *stats_dir, char *subdir, const char *stats_dev_uui DIR *cachedir; struct stat cache_stat; char intbuf[4]; - char entry[256]; + char entry[MAX_PATH]; - strcpy(entry, stats_dir); - strcat(entry, subdir); + snprintf(entry, MAX_PATH, "%s%s", stats_dir, subdir); snprintf(intbuf, 4, "%d", i); strcat(entry, intbuf); while(true) { - char buf[256]; + char buf[MAX_PATH]; int len; if((cachedir = opendir(entry)) == NULL) @@ -1041,16 +1037,13 @@ int list_cachesets(char *cset_dir, bool list_devs) while ((ent = readdir(dir)) != NULL) { struct stat statbuf; - char entry[256]; + char entry[MAX_PATH]; struct dirent *cache_ent; if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue; - strcpy(entry, cset_dir); - strcat(entry, "/"); - strcat(entry, ent->d_name); - + snprintf(entry, MAX_PATH, "%s/%s", cset_dir, ent->d_name); if(stat(entry, &statbuf) == -1) { fprintf(stderr, "Failed to stat %s\n", entry); return 1; @@ -1070,9 +1063,10 @@ int list_cachesets(char *cset_dir, bool list_devs) return 0; } -static int get_bcache_fd() +static int get_bcache_fd(void) { int bcachefd = open("/dev/bcache", O_RDWR); + if (bcachefd < 0) { perror("Can't open bcache device\n"); exit(EXIT_FAILURE); @@ -1091,6 +1085,8 @@ int register_bcache(char *const *devs) fprintf(stderr, "ioctl register error: %s\n", strerror(ret)); exit(EXIT_FAILURE); } + + close(bcachefd); return 0; } @@ -1105,6 +1101,8 @@ int unregister_bcache(char *const *devs) fprintf(stderr, "ioctl unregister error: %s\n", strerror(ret)); exit(EXIT_FAILURE); } + + close(bcachefd); return 0; } @@ -1186,18 +1184,16 @@ void sb_state(struct cache_sb *sb, char *dev) void read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, bool print_val) { struct stat statbuf; - char entry[150]; + char entry[MAX_PATH]; - strcpy(entry, stats_dir); - strcat(entry, "/"); - strcat(entry, stat_name); + snprintf(entry, MAX_PATH, "%s/%s", stats_dir, stat_name); if(stat(entry, &statbuf) == -1) { fprintf(stderr, "Failed to stat %s\n", entry); return; } if (S_ISREG(statbuf.st_mode)) { - char buf[100]; + char buf[MAX_PATH]; FILE *fp = NULL; fp = fopen(entry, "r"); @@ -1207,7 +1203,7 @@ void read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, bool print_val) return; } - while(fgets(buf, 100, fp)); + while(fgets(buf, MAX_PATH, fp)); if(print_val) printf("%s\n", buf); diff --git a/bcache.h b/bcache.h index 41bf13dd..3737facc 100644 --- a/bcache.h +++ b/bcache.h @@ -21,6 +21,7 @@ typedef __s32 s32; typedef __s64 s64; #define SB_START (SB_SECTOR * 512) +#define MAX_PATH 256 #define max(x, y) ({ \ diff --git a/bcacheadm.8 b/bcacheadm.8 index 0ff96697..52c5fe74 100644 --- a/bcacheadm.8 +++ b/bcacheadm.8 @@ -69,12 +69,7 @@ Create a cache Create a backing device .TP .BR \-b\ --bucket-size= -Specifies the bucket size. Allocation is done in terms of buckets, and cache -hits are counted per bucket; thus a smaller bucket size will give better cache -utilization, but poorer write performance. The bucket size is intended to be -equal to the size of your SSD's erase blocks, which seems to be 128k-512k for -most SSDs. Must be a power of two; accepts human readable units. Defaults to -128k. +Specifies the bucket size. .TP .BR \-l\ --label= label diff --git a/bcacheadm.c b/bcacheadm.c index 913e4ca0..15260b0e 100644 --- a/bcacheadm.c +++ b/bcacheadm.c @@ -114,11 +114,16 @@ static int set_cache(NihOption *option, const char *arg) bdev = 0; cache_devices[nr_cache_devices] = (char *)malloc(sizeof(char *) * strlen(arg) + 1); - strcpy(cache_devices[nr_cache_devices], arg); + cache_devices[nr_cache_devices] = strdup(arg); if(!tier) tier_mapping[nr_cache_devices] = 0; - else - tier_mapping[nr_cache_devices] = atoi(tier); + else { + int ntier = atoi(tier); + if(tier == 0 || tier == 1) + tier_mapping[nr_cache_devices] = ntier; + else + printf("Invalid tier\n"); + } devs++; nr_cache_devices++; @@ -131,12 +136,12 @@ static int set_bdev(NihOption *option, const char *arg) if(label) { backing_dev_labels[nr_backing_devices] = (char *)malloc(sizeof(char *) * strlen(label) + 1); - strcpy(backing_dev_labels[nr_backing_devices], label); + backing_dev_labels[nr_backing_devices] = strdup(label); } backing_devices[nr_backing_devices] = (char *)malloc(sizeof(char *) * strlen(arg) + 1); - strcpy(backing_devices[nr_backing_devices], arg); + backing_devices[nr_backing_devices] = strdup(arg); nr_backing_devices++; devs++; @@ -239,7 +244,7 @@ static NihOption options[] = { /* commands */ -int make_bcache (NihCommand *command, char *const *args) +int make_bcache(NihCommand *command, char *const *args) { int cache_dev_fd[devs]; @@ -342,7 +347,7 @@ int make_bcache (NihCommand *command, char *const *args) return 0; } -int probe_bcache (NihCommand *command, char *const *args) +int probe_bcache(NihCommand *command, char *const *args) { int i; @@ -353,26 +358,26 @@ int probe_bcache (NihCommand *command, char *const *args) return 0; } -int bcache_register (NihCommand *command, char *const *args) +int bcache_register(NihCommand *command, char *const *args) { int ret = register_bcache(args); return ret; } -int bcache_unregister (NihCommand *command, char *const *args) +int bcache_unregister(NihCommand *command, char *const *args) { int ret = unregister_bcache(args); return ret; } -int bcache_list_cachesets (NihCommand *command, char *const *args) +int bcache_list_cachesets(NihCommand *command, char *const *args) { return list_cachesets(cset_dir, list_devs); } -int bcache_query_devs (NihCommand *command, char *const *args) +int bcache_query_devs(NihCommand *command, char *const *args) { int i; @@ -384,7 +389,7 @@ int bcache_query_devs (NihCommand *command, char *const *args) } } -int bcache_status (NihCommand *command, char *const *args) +int bcache_status(NihCommand *command, char *const *args) { int i; struct cache_sb *sb_tier0 = NULL, *sb_tier1 = NULL; @@ -434,17 +439,15 @@ static void stats_subdir(char* stats_dir) strcat(stats_dir, tmp); } -int bcache_stats (NihCommand *command, char *const *args) +int bcache_stats(NihCommand *command, char *const *args) { int i; - char stats_dir[200]; + char stats_dir[MAX_PATH]; DIR *dir = NULL; struct dirent *ent = NULL; if (stats_uuid) { - strcpy(stats_dir, cset_dir); - strcat(stats_dir, "/"); - strcat(stats_dir, stats_uuid); + snprintf(stats_dir, MAX_PATH, "%s/%s", cset_dir, stats_uuid); stats_subdir(stats_dir); dir = opendir(stats_dir); if (!dir) { From 7763a86ca89450628a3d6985ebd3db85c6091963 Mon Sep 17 00:00:00 2001 From: Jacob Malevich Date: Mon, 24 Nov 2014 17:16:55 -0800 Subject: [PATCH 21/21] Remove exit points from libbache and return error messages instead. Change-Id: Ibd238bb63354dae841c2a70e5ded550b3c603d4b Signed-off-by: Jacob Malevich --- bcache.c | 100 ++++++++++++++++++++++++++++++---------------------- bcache.h | 12 +++---- bcacheadm.c | 96 ++++++++++++++++++++++++++++++++++--------------- 3 files changed, 132 insertions(+), 76 deletions(-) diff --git a/bcache.c b/bcache.c index 06b06cf1..2c1f2322 100644 --- a/bcache.c +++ b/bcache.c @@ -963,7 +963,7 @@ static void list_cacheset_devs(char *cset_dir, char *cset_name, bool parse_dev_n } } -void find_matching_uuid(char *stats_dir, char *subdir, const char *stats_dev_uuid) { +char *find_matching_uuid(char *stats_dir, char *subdir, const char *stats_dev_uuid) { /* Do a query-dev --uuid only to get the uuid * repeat on each dev until we find a matching one * append that cache# to subdir and return @@ -974,6 +974,7 @@ void find_matching_uuid(char *stats_dir, char *subdir, const char *stats_dev_uui struct stat cache_stat; char intbuf[4]; char entry[MAX_PATH]; + char *err = NULL; snprintf(entry, MAX_PATH, "%s%s", stats_dir, subdir); snprintf(intbuf, 4, "%d", i); @@ -1010,7 +1011,7 @@ void find_matching_uuid(char *stats_dir, char *subdir, const char *stats_dev_uui query_dev(devname, false, false, true, dev_uuid); if(!strcmp(stats_dev_uuid, dev_uuid)) { strcat(subdir, intbuf); - return; + return err; } } @@ -1022,17 +1023,20 @@ void find_matching_uuid(char *stats_dir, char *subdir, const char *stats_dev_uui } - printf("dev uuid doesn't exist in cache_set\n"); - exit(1); + err = "dev uuid doesn't exist in cache_set"; + return err; } -int list_cachesets(char *cset_dir, bool list_devs) +char *list_cachesets(char *cset_dir, bool list_devs) { struct dirent *ent; - DIR *dir = opendir(cset_dir); + DIR *dir; + char *err = NULL; + + dir = opendir(cset_dir); if (!dir) { - fprintf(stderr, "Failed to open dir %s\n", cset_dir); - return 1; + err = "Failed to open cacheset dir"; + goto err; } while ((ent = readdir(dir)) != NULL) { @@ -1045,8 +1049,8 @@ int list_cachesets(char *cset_dir, bool list_devs) snprintf(entry, MAX_PATH, "%s/%s", cset_dir, ent->d_name); if(stat(entry, &statbuf) == -1) { - fprintf(stderr, "Failed to stat %s\n", entry); - return 1; + err = "Failed to stat cacheset subdir"; + goto err; } if (S_ISDIR(statbuf.st_mode)) { @@ -1058,55 +1062,63 @@ int list_cachesets(char *cset_dir, bool list_devs) } } +err: closedir(dir); - - return 0; + return err; } -static int get_bcache_fd(void) -{ - int bcachefd = open("/dev/bcache", O_RDWR); - - if (bcachefd < 0) { - perror("Can't open bcache device\n"); - exit(EXIT_FAILURE); - } - return bcachefd; -} - -int register_bcache(char *const *devs) +char *register_bcache(char *const *devs) { int ret, bcachefd; + char *err = NULL; - bcachefd = get_bcache_fd(); + bcachefd = open("/dev/bcache", O_RDWR); + if (bcachefd < 0) { + err = "Can't open bcache device"; + goto err; + } ret = ioctl(bcachefd, BCH_IOCTL_REGISTER, devs); if (ret < 0) { - fprintf(stderr, "ioctl register error: %s\n", strerror(ret)); - exit(EXIT_FAILURE); + char tmp[64]; + snprintf(tmp, 64, "ioctl register error: %s\n", + strerror(ret)); + err = strdup(tmp); + goto err; } - close(bcachefd); - return 0; +err: + if (bcachefd) + close(bcachefd); + return err; } -int unregister_bcache(char *const *devs) +char *unregister_bcache(char *const *devs) { int ret, bcachefd; + char *err = NULL; - bcachefd = get_bcache_fd(); + bcachefd = open("/dev/bcache", O_RDWR); + if (bcachefd < 0) { + err = "Can't open bcache device"; + goto err; + } ret = ioctl(bcachefd, BCH_IOCTL_UNREGISTER, devs); if (ret < 0) { - fprintf(stderr, "ioctl unregister error: %s\n", strerror(ret)); - exit(EXIT_FAILURE); + char tmp[64]; + snprintf(tmp, 64, "ioctl unregister error: %s\n", + strerror(ret)); + err = strdup(tmp); + goto err; } +err: close(bcachefd); - return 0; + return err; } -int probe(char *dev, int udev) +char *probe(char *dev, int udev) { struct cache_sb sb; char uuid[40]; @@ -1164,9 +1176,8 @@ int probe(char *dev, int udev) return 0; - err: - fprintf(stderr, "Probe exit with error: %s", err); - return -1; +err: + return err; } void sb_state(struct cache_sb *sb, char *dev) @@ -1181,15 +1192,18 @@ void sb_state(struct cache_sb *sb, char *dev) } -void read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, bool print_val) +char *read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, bool print_val) { struct stat statbuf; char entry[MAX_PATH]; + char *err = NULL; snprintf(entry, MAX_PATH, "%s/%s", stats_dir, stat_name); if(stat(entry, &statbuf) == -1) { - fprintf(stderr, "Failed to stat %s\n", entry); - return; + char tmp[MAX_PATH]; + snprintf(tmp, MAX_PATH, "Failed to stat %s\n", entry); + err = strdup(tmp); + goto err; } if (S_ISREG(statbuf.st_mode)) { @@ -1200,7 +1214,7 @@ void read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, bool print_val) if(!fp) { /* If we can't open the file, this is probably because * of permissions, just move to the next file */ - return; + return NULL; } while(fgets(buf, MAX_PATH, fp)); @@ -1211,4 +1225,6 @@ void read_stat_dir(DIR *dir, char *stats_dir, char *stat_name, bool print_val) printf("%s\n", stat_name); fclose(fp); } +err: + return err; } diff --git a/bcache.h b/bcache.h index 3737facc..99307e64 100644 --- a/bcache.h +++ b/bcache.h @@ -59,14 +59,14 @@ void show_super_backingdev(struct cache_sb *, bool); void show_super_cache(struct cache_sb *, bool); struct cache_sb *query_dev(char *, bool, bool, bool, char *dev_uuid); -int list_cachesets(char *, bool); +char *list_cachesets(char *, bool); char *parse_array_to_list(char *const *); -int register_bcache(char *const *); -int unregister_bcache(char *const *); -int probe(char *, int); +char *register_bcache(char *const *); +char *unregister_bcache(char *const *); +char *probe(char *, int); void sb_state(struct cache_sb *, char *); -void read_stat_dir(DIR *, char *, char *, bool); -void find_matching_uuid(char *, char *, const char*); +char *read_stat_dir(DIR *, char *, char *, bool); +char *find_matching_uuid(char *, char *, const char*); //int add_device(char *); //int remove_device(char *); diff --git a/bcacheadm.c b/bcacheadm.c index 15260b0e..913fcefd 100644 --- a/bcacheadm.c +++ b/bcacheadm.c @@ -112,14 +112,12 @@ static int set_block_size(NihOption *option, const char *arg) static int set_cache(NihOption *option, const char *arg) { bdev = 0; - cache_devices[nr_cache_devices] = (char *)malloc(sizeof(char *) * - strlen(arg) + 1); cache_devices[nr_cache_devices] = strdup(arg); if(!tier) tier_mapping[nr_cache_devices] = 0; else { int ntier = atoi(tier); - if(tier == 0 || tier == 1) + if(ntier == 0 || ntier == 1) tier_mapping[nr_cache_devices] = ntier; else printf("Invalid tier\n"); @@ -133,14 +131,9 @@ static int set_bdev(NihOption *option, const char *arg) { bdev = 1; - if(label) { - backing_dev_labels[nr_backing_devices] = - (char *)malloc(sizeof(char *) * strlen(label) + 1); + if(label) backing_dev_labels[nr_backing_devices] = strdup(label); - } - backing_devices[nr_backing_devices] = (char *)malloc(sizeof(char *) * - strlen(arg) + 1); backing_devices[nr_backing_devices] = strdup(arg); nr_backing_devices++; @@ -350,9 +343,14 @@ int make_bcache(NihCommand *command, char *const *args) int probe_bcache(NihCommand *command, char *const *args) { int i; + char *err = NULL; for (i = 0; args[i] != NULL; i++) { - probe(args[i], udev); + err = probe(args[i], udev); + if(err) { + printf("probe_bcache error: %s\n", err); + return -1; + } } return 0; @@ -360,21 +358,40 @@ int probe_bcache(NihCommand *command, char *const *args) int bcache_register(NihCommand *command, char *const *args) { - int ret = register_bcache(args); + char *err = NULL; - return ret; + err = register_bcache(args); + if (err) { + printf("bcache_register error: %s\n", err); + return -1; + } + + return 0; } int bcache_unregister(NihCommand *command, char *const *args) { - int ret = unregister_bcache(args); + char *err = NULL; - return ret; + err = unregister_bcache(args); + if (err) { + printf("bcache_unregister error: %s\n", err); + return -1; + } + + return 0; } int bcache_list_cachesets(NihCommand *command, char *const *args) { - return list_cachesets(cset_dir, list_devs); + char *err = NULL; + err = list_cachesets(cset_dir, list_devs); + if (err) { + printf("bcache_list_cachesets error :%s\n", err); + return -1; + } + + return 0; } int bcache_query_devs(NihCommand *command, char *const *args) @@ -416,12 +433,15 @@ int bcache_status(NihCommand *command, char *const *args) if (sb_tier1) sb_state(sb_tier1, dev1); } -static void stats_subdir(char* stats_dir) +static char *stats_subdir(char* stats_dir) { char tmp[50] = "/"; + char *err = NULL; if(stats_dev_uuid) { strcat(tmp, "cache"); - find_matching_uuid(stats_dir, tmp, stats_dev_uuid); + err = find_matching_uuid(stats_dir, tmp, stats_dev_uuid); + if(err) + goto err; } else if(stats_cache_num) { strcat(tmp, "cache"); strcat(tmp, stats_cache_num); @@ -434,9 +454,12 @@ static void stats_subdir(char* stats_dir) else if (stats_total) strcat(tmp, "stats_total"); else - return; + return err; strcat(stats_dir, tmp); + +err: + return err; } int bcache_stats(NihCommand *command, char *const *args) @@ -445,29 +468,46 @@ int bcache_stats(NihCommand *command, char *const *args) char stats_dir[MAX_PATH]; DIR *dir = NULL; struct dirent *ent = NULL; + char *err = NULL; if (stats_uuid) { snprintf(stats_dir, MAX_PATH, "%s/%s", cset_dir, stats_uuid); - stats_subdir(stats_dir); + err = stats_subdir(stats_dir); + if(err) + goto err; + dir = opendir(stats_dir); if (!dir) { - fprintf(stderr, "Failed to open dir %s\n", cset_dir); - return 1; + err = "Failed to open dir"; + goto err; } } else { - printf("Must provide a cacheset uuid\n"); - exit(EXIT_FAILURE); + err = "Must provide a cacheset uuid"; + goto err; } - if(stats_list || stats_all) - while ((ent = readdir(dir)) != NULL) - read_stat_dir(dir, stats_dir, ent->d_name, stats_all); + if(stats_list || stats_all) { + while ((ent = readdir(dir)) != NULL) { + err = read_stat_dir(dir, stats_dir, ent->d_name, stats_all); + if (err) + goto err; + } + } - for (i = 0; args[i] != NULL; i++) - read_stat_dir(dir, stats_dir, args[i], true); + for (i = 0; args[i] != NULL; i++) { + err = read_stat_dir(dir, stats_dir, args[i], true); + if (err) + goto err; + } closedir(dir); + return 0; + +err: + closedir(dir); + printf("bcache_stats error: %s\n", err); + return -1; } static NihCommand commands[] = {