diff --git a/bcache.h b/bcache.h index e667cc01..8087092f 100644 --- a/bcache.h +++ b/bcache.h @@ -15,6 +15,14 @@ static const char bcache_magic[] = { 0xc6, 0x85, 0x73, 0xf6, 0x4e, 0x1a, 0x45, 0xca, 0x82, 0x65, 0xf5, 0x7f, 0x48, 0xba, 0x6d, 0x81 }; +/* Version 1: Backing dev + * Version 2: Seed pointer into btree node checksum + * Version 3: Backing dev superblock has offset of start of data + */ + +#define BCACHE_SB_BDEV_VERSION 3 +#define BCACHE_SB_MAX_VERSION 3 + #define SB_SECTOR 8 #define SB_LABEL_SIZE 32 @@ -51,8 +59,13 @@ struct cache_sb { uint64_t d[]; /* journal buckets */ }; +BITMASK(SB_BDEV, struct cache_sb, version, 0, 1); + BITMASK(BDEV_WRITEBACK, struct cache_sb, flags, 0, 1); +BITMASK(CACHE_DISCARD, struct cache_sb, flags, 1, 1); +BITMASK(CACHE_REPLACEMENT, struct cache_sb, flags, 2, 3); + inline uint64_t crc64(const void *_data, size_t len); #define node(i, j) ((void *) ((i)->d + (j))) diff --git a/make-bcache.c b/make-bcache.c index 2c311476..70174ed7 100644 --- a/make-bcache.c +++ b/make-bcache.c @@ -58,6 +58,52 @@ uint64_t hatoi(const char *s) return i; } +char *skip_spaces(const char *str) +{ + while (isspace(*str)) + ++str; + return (char *)str; +} + +char *strim(char *s) +{ + size_t size; + char *end; + + s = skip_spaces(s); + size = strlen(s); + if (!size) + return s; + + end = s + size - 1; + while (end >= s && isspace(*end)) + end--; + *(end + 1) = '\0'; + + return s; +} + +ssize_t read_string_list(const char *buf, const char * const list[]) +{ + size_t i; + char *s, *d = strdup(buf); + if (!d) + return -ENOMEM; + + s = strim(d); + + for (i = 0; list[i]; i++) + if (!strcmp(list[i], s)) + break; + + free(d); + + if (!list[i]) + return -EINVAL; + + return i; +} + void usage() { printf("Usage: make-bcache [options] device\n" @@ -67,20 +113,35 @@ void usage() " -w, --block block size (hard sector size of SSD, often 2k)\n" " -U UUID\n" " --writeback enable writeback\n" + " --discard enable discards\n" + " --cache_replacement_policy=(lru|fifo)\n" " -h, --help display this help and exit\n"); exit(EXIT_FAILURE); } +const char * const cache_replacement_policies[] = { + "lru", + "fifo", + "random", + NULL +}; + int writeback; +int discard; +unsigned cache_replacement_policy; +uint64_t data_offset = 16; struct option opts[] = { - { "cache", 0, NULL, 'C' }, - { "bdev", 0, NULL, 'B' }, - { "bucket", 1, NULL, 'b' }, - { "block", 1, NULL, 'w' }, - { "writeback", 0, &writeback, 1 }, - { "help", 0, NULL, 'h' }, - { NULL, 0, NULL, 0 }, + { "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) @@ -88,7 +149,7 @@ void write_sb(char *dev, struct cache_sb *sb) int fd; char uuid[40], set_uuid[40]; - if (sb->version > 1) { + if (sb->version > BCACHE_SB_MAX_VERSION) { printf("Must specify one of -C or -B\n"); usage(); } @@ -109,11 +170,20 @@ void write_sb(char *dev, struct cache_sb *sb) exit(EXIT_FAILURE); } - if (sb->version == CACHE_BACKING_DEV && - writeback) - SET_BDEV_WRITEBACK(sb, 1); - else - SET_BDEV_WRITEBACK(sb, 0); + sb->flags = 0; + + if (SB_BDEV(sb)) { + SET_BDEV_WRITEBACK(sb, writeback); + + if (data_offset != 16) { + sb->version = BCACHE_SB_BDEV_VERSION; + sb->keys = 1; + sb->d[0] = data_offset; + } + } else { + SET_CACHE_DISCARD(sb, discard); + SET_CACHE_REPLACEMENT(sb, cache_replacement_policy); + } sb->offset = SB_SECTOR; memcpy(sb->magic, bcache_magic, 16); @@ -164,7 +234,7 @@ int main(int argc, char **argv) struct cache_sb sb; memset(&sb, 0, sizeof(struct cache_sb)); - sb.version = 2; + sb.version = -1; sb.block_size = 8; sb.bucket_size = 1024; @@ -193,6 +263,17 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } break; + case 'p': + cache_replacement_policy = read_string_list(optarg, + cache_replacement_policies); + break; + case 'o': + data_offset = atoll(optarg); + if (sb.d[0] < 16) { + printf("Bad data offset; minimum 16 sectors\n"); + exit(EXIT_FAILURE); + } + break; case 'h': usage(); break;