]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - make-bcache.c
bcache-tools are GPL
[bcachefs-tools-debian] / make-bcache.c
index 5f4ebccadc3fef0b79f0a9a92eb239e6fb8451d2..6ffe89e1965ef5fbd2dd11b0f9430502a0d51545 100644 (file)
@@ -1,3 +1,9 @@
+/*
+ * Author: Kent Overstreet <kmo@daterainc.com>
+ *
+ * GPLv2
+ */
+
 #define _FILE_OFFSET_BITS      64
 #define __USE_FILE_OFFSET64
 #define _XOPEN_SOURCE 600
 
 #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;
@@ -136,7 +148,9 @@ void usage()
               "        -B, --bdev              Format a backing device\n"
               "        -b, --bucket            bucket size\n"
               "        -w, --block             block size (hard sector size of SSD, often 2k)\n"
-              "        -U                      UUID\n"
+              "        -o, --data-offset       data offset in sectors\n"
+              "            --cset-uuid         UUID for the cache set\n"
+//            "        -U                      UUID\n"
               "            --writeback         enable writeback\n"
               "            --discard           enable discards\n"
               "            --cache_replacement_policy=(lru|fifo)\n"
@@ -151,145 +165,181 @@ const char * const cache_replacement_policies[] = {
        NULL
 };
 
-int writeback;
-int discard;
-unsigned cache_replacement_policy;
-uint64_t data_offset = BDEV_DATA_START;
-
-struct option opts[] = {
-       { "cache",              0, NULL,        'C' },
-       { "bdev",               0, NULL,        'B' },
-       { "bucket",             1, NULL,        'b' },
-       { "block",              1, NULL,        'w' },
-       { "writeback",          0, &writeback,  1 },
-       { "discard",            0, &discard,    1 },
-       { "cache_replacement_policy", 1, NULL, 'p' },
-//     { "data_offset",        1, NULL,        'o' },
-       { "help",               0, NULL,        'h' },
-       { NULL,                 0, NULL,        0 },
-};
-
-void write_sb(char *dev, struct cache_sb *sb)
+static void write_sb(char *dev, unsigned block_size, unsigned bucket_size,
+                    bool writeback, bool discard,
+                    unsigned cache_replacement_policy,
+                    uint64_t data_offset,
+                    uuid_t set_uuid, bool bdev)
 {
        int fd;
-       char uuid[40], set_uuid[40];
-
-       if (sb->version > BCACHE_SB_MAX_VERSION) {
-               printf("Must specify one of -C or -B\n");
-               usage();
-       }
-
-       if (sb->bucket_size < sb->block_size) {
-               printf("Bucket size cannot be smaller than block size\n");
-               exit(EXIT_FAILURE);
-       }
+       char uuid_str[40], set_uuid_str[40];
+       struct cache_sb sb;
 
        if ((fd = open(dev, O_RDWR|O_EXCL)) == -1) {
                printf("Can't open dev %s: %s\n", dev, strerror(errno));
                exit(EXIT_FAILURE);
        }
 
-       sb->flags = 0;
+       memset(&sb, 0, sizeof(struct cache_sb));
 
-       if (SB_BDEV(sb)) {
-               SET_BDEV_WRITEBACK(sb, writeback);
+       sb.offset       = SB_SECTOR;
+       sb.version      = bdev
+               ? BCACHE_SB_VERSION_BDEV
+               : BCACHE_SB_VERSION_CDEV;
 
-               if (data_offset != BDEV_DATA_START) {
-                       sb->version = BCACHE_SB_BDEV_VERSION;
-                       sb->keys = 1;
-                       sb->d[0] = data_offset;
+       memcpy(sb.magic, bcache_magic, 16);
+       uuid_generate(sb.uuid);
+       memcpy(sb.set_uuid, set_uuid, sizeof(sb.set_uuid));
+
+       sb.bucket_size  = bucket_size;
+       sb.block_size   = block_size;
+
+       uuid_unparse(sb.uuid, uuid_str);
+       uuid_unparse(sb.set_uuid, set_uuid_str);
+
+       if (SB_IS_BDEV(&sb)) {
+               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;
                }
+
+               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);
        } else {
-               SET_CACHE_DISCARD(sb, discard);
-               SET_CACHE_REPLACEMENT(sb, cache_replacement_policy);
-       }
+               sb.nbuckets             = getblocks(fd) / sb.bucket_size;
+               sb.nr_in_set            = 1;
+               sb.first_bucket         = (23 / sb.bucket_size) + 1;
 
-       sb->offset              = SB_SECTOR;
-       memcpy(sb->magic, bcache_magic, 16);
-       sb->nbuckets            = getblocks(fd) / sb->bucket_size;
-       sb->nr_in_set           = 1;
-       sb->first_bucket        = (23 / sb->bucket_size) + 1;
-       uuid_unparse(sb->uuid, uuid);
-       uuid_unparse(sb->set_uuid, set_uuid);
-       sb->csum = csum_set(sb);
-
-       if (sb->nbuckets < 1 << 7) {
-               printf("Not enough buckets: %ju, need %u\n",
-                      sb->nbuckets, 1 << 7);
-               exit(EXIT_FAILURE);
+               if (sb.nbuckets < 1 << 7) {
+                       printf("Not enough buckets: %ju, need %u\n",
+                              sb.nbuckets, 1 << 7);
+                       exit(EXIT_FAILURE);
+               }
+
+               SET_CACHE_DISCARD(&sb, discard);
+               SET_CACHE_REPLACEMENT(&sb, cache_replacement_policy);
+
+               printf("UUID:                   %s\n"
+                      "Set UUID:               %s\n"
+                      "version:                %u\n"
+                      "nbuckets:               %ju\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);
        }
 
-       printf("UUID:                   %s\n"
-              "Set UUID:               %s\n"
-              "nbuckets:               %ju\n"
-              "block_size:             %u\n"
-              "bucket_size:            %u\n"
-              "nr_in_set:              %u\n"
-              "nr_this_dev:            %u\n"
-              "first_bucket:           %u\n",
-              uuid, set_uuid,
-              sb->nbuckets,
-              sb->block_size,
-              sb->bucket_size,
-              sb->nr_in_set,
-              sb->nr_this_dev,
-              sb->first_bucket);
-
-       if (pwrite(fd, sb, sizeof(*sb), SB_SECTOR << 9) != sizeof(*sb)) {
+       sb.csum = csum_set(&sb);
+
+       if (pwrite(fd, &sb, sizeof(sb), SB_SECTOR << 9) != sizeof(sb)) {
                perror("write error\n");
                exit(EXIT_FAILURE);
        }
 
        fsync(fd);
        close(fd);
-
-       uuid_generate(sb->uuid);
 }
 
-int main(int argc, char **argv)
+static unsigned get_blocksize(const char *path)
 {
-       bool written = false;
-       int c;
-       struct cache_sb sb;
+       struct stat statbuf;
 
-       memset(&sb, 0, sizeof(struct cache_sb));
-       sb.version = -1;
-       sb.block_size = 1;
-       sb.bucket_size = 1024;
+       if (stat(path, &statbuf)) {
+               fprintf(stderr, "Error statting %s: %s\n",
+                       path, strerror(errno));
+               exit(EXIT_FAILURE);
+       }
 
-       uuid_generate(sb.uuid);
-       uuid_generate(sb.set_uuid);
+       return statbuf.st_blksize / 512;
+}
+
+int main(int argc, char **argv)
+{
+       int c, bdev = -1;
+       unsigned i, ncache_devices = 0, nbacking_devices = 0;
+       char *cache_devices[argc];
+       char *backing_devices[argc];
+
+       unsigned block_size = 0, bucket_size = 1024;
+       int writeback = 0, discard = 0;
+       unsigned cache_replacement_policy = 0;
+       uint64_t data_offset = BDEV_DATA_START_DEFAULT;
+       uuid_t set_uuid;
+
+       uuid_generate(set_uuid);
+
+       struct option opts[] = {
+               { "cache",              0, NULL,        'C' },
+               { "bdev",               0, NULL,        'B' },
+               { "bucket",             1, NULL,        'b' },
+               { "block",              1, NULL,        'w' },
+               { "writeback",          0, &writeback,  1 },
+               { "discard",            0, &discard,    1 },
+               { "cache_replacement_policy", 1, NULL, 'p' },
+               { "data_offset",        1, NULL,        'o' },
+               { "cset-uuid",          1, NULL,        'u' },
+               { "help",               0, NULL,        'h' },
+               { NULL,                 0, NULL,        0 },
+       };
 
        while ((c = getopt_long(argc, argv,
                                "-hCBU:w:b:",
                                opts, NULL)) != -1)
                switch (c) {
                case 'C':
-                       sb.version = 0;
+                       bdev = 0;
                        break;
                case 'B':
-                       sb.version = CACHE_BACKING_DEV;
+                       bdev = 1;
                        break;
                case 'b':
-                       sb.bucket_size = hatoi_validate(optarg, "bucket size");
+                       bucket_size = hatoi_validate(optarg, "bucket size");
                        break;
                case 'w':
-                       sb.block_size = hatoi_validate(optarg, "block size");
+                       block_size = hatoi_validate(optarg, "block size");
                        break;
+#if 0
                case 'U':
                        if (uuid_parse(optarg, sb.uuid)) {
                                printf("Bad uuid\n");
                                exit(EXIT_FAILURE);
                        }
                        break;
+#endif
                case 'p':
                        cache_replacement_policy = read_string_list(optarg,
                                                    cache_replacement_policies);
                        break;
                case 'o':
                        data_offset = atoll(optarg);
-                       if (sb.d[0] < BDEV_DATA_START) {
-                               printf("Bad data offset; minimum %d sectors\n", BDEV_DATA_START);
+                       if (data_offset < BDEV_DATA_START_DEFAULT) {
+                               printf("Bad data offset; minimum %d sectors\n",
+                                      BDEV_DATA_START_DEFAULT);
+                               exit(EXIT_FAILURE);
+                       }
+                       break;
+               case 'u':
+                       if (uuid_parse(optarg, set_uuid)) {
+                               printf("Bad uuid\n");
                                exit(EXIT_FAILURE);
                        }
                        break;
@@ -297,15 +347,47 @@ int main(int argc, char **argv)
                        usage();
                        break;
                case 1:
-                       write_sb(optarg, &sb);
-                       written = true;
+                       if (bdev == -1) {
+                               printf("Please specify -C or -B\n");
+                               exit(EXIT_FAILURE);
+                       }
+
+                       if (bdev)
+                               backing_devices[nbacking_devices++] = optarg;
+                       else
+                               cache_devices[ncache_devices++] = optarg;
                        break;
                }
 
-       if (!written) {
+       if (!ncache_devices && !nbacking_devices) {
                printf("Please supply a device\n");
                usage();
        }
 
+       if (bucket_size < block_size) {
+               printf("Bucket size cannot be smaller than block size\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (!block_size) {
+               for (i = 0; i < ncache_devices; i++)
+                       block_size = max(block_size,
+                                        get_blocksize(cache_devices[i]));
+
+               for (i = 0; i < nbacking_devices; i++)
+                       block_size = max(block_size,
+                                        get_blocksize(backing_devices[i]));
+       }
+
+       for (i = 0; i < ncache_devices; i++)
+               write_sb(cache_devices[i], block_size, bucket_size,
+                        writeback, discard, cache_replacement_policy,
+                        data_offset, set_uuid, false);
+
+       for (i = 0; i < nbacking_devices; i++)
+               write_sb(backing_devices[i], block_size, bucket_size,
+                        writeback, discard, cache_replacement_policy,
+                        data_offset, set_uuid, true);
+
        return 0;
 }