1 #define _FILE_OFFSET_BITS 64
2 #define __USE_FILE_OFFSET64
3 #define _XOPEN_SOURCE 600
16 #include <sys/ioctl.h>
17 #include <sys/types.h>
20 #include <uuid/uuid.h>
24 #define max(x, y) ({ \
25 typeof(x) _max1 = (x); \
26 typeof(y) _max2 = (y); \
27 (void) (&_max1 == &_max2); \
28 _max1 > _max2 ? _max1 : _max2; })
30 uint64_t getblocks(int fd)
34 if (fstat(fd, &statbuf)) {
35 perror("stat error\n");
38 ret = statbuf.st_size / 512;
39 if (S_ISBLK(statbuf.st_mode))
40 if (ioctl(fd, BLKGETSIZE, &ret)) {
41 perror("ioctl error");
47 uint64_t hatoi(const char *s)
50 long long i = strtoll(s, &e, 10);
68 unsigned hatoi_validate(const char *s, const char *msg)
70 uint64_t v = hatoi(s);
73 printf("%s must be a power of two\n", msg);
80 printf("%s too large\n", msg);
85 printf("%s too small\n", msg);
92 char *skip_spaces(const char *str)
110 while (end >= s && isspace(*end))
117 ssize_t read_string_list(const char *buf, const char * const list[])
120 char *s, *d = strdup(buf);
126 for (i = 0; list[i]; i++)
127 if (!strcmp(list[i], s))
140 printf("Usage: make-bcache [options] device\n"
141 " -C, --cache Format a cache device\n"
142 " -B, --bdev Format a backing device\n"
143 " -b, --bucket bucket size\n"
144 " -w, --block block size (hard sector size of SSD, often 2k)\n"
145 " -o, --data-offset data offset in sectors\n"
146 " --cset-uuid UUID for the cache set\n"
148 " --writeback enable writeback\n"
149 " --discard enable discards\n"
150 " --cache_replacement_policy=(lru|fifo)\n"
151 " -h, --help display this help and exit\n");
155 const char * const cache_replacement_policies[] = {
162 static void write_sb(char *dev, unsigned block_size, unsigned bucket_size,
163 bool writeback, bool discard,
164 unsigned cache_replacement_policy,
165 uint64_t data_offset,
166 uuid_t set_uuid, bool bdev)
169 char uuid_str[40], set_uuid_str[40];
172 if ((fd = open(dev, O_RDWR|O_EXCL)) == -1) {
173 printf("Can't open dev %s: %s\n", dev, strerror(errno));
177 memset(&sb, 0, sizeof(struct cache_sb));
179 sb.offset = SB_SECTOR;
181 ? BCACHE_SB_VERSION_BDEV
182 : BCACHE_SB_VERSION_CDEV;
184 memcpy(sb.magic, bcache_magic, 16);
185 uuid_generate(sb.uuid);
186 memcpy(sb.set_uuid, set_uuid, sizeof(sb.set_uuid));
188 sb.bucket_size = bucket_size;
189 sb.block_size = block_size;
191 uuid_unparse(sb.uuid, uuid_str);
192 uuid_unparse(sb.set_uuid, set_uuid_str);
194 if (SB_IS_BDEV(&sb)) {
196 &sb, writeback ? CACHE_MODE_WRITEBACK : CACHE_MODE_WRITETHROUGH);
198 if (data_offset != BDEV_DATA_START_DEFAULT) {
199 sb.version = BCACHE_SB_VERSION_BDEV_WITH_OFFSET;
200 sb.data_offset = data_offset;
207 "data_offset: %ju\n",
208 uuid_str, set_uuid_str,
209 (unsigned) sb.version,
213 sb.nbuckets = getblocks(fd) / sb.bucket_size;
215 sb.first_bucket = (23 / sb.bucket_size) + 1;
217 if (sb.nbuckets < 1 << 7) {
218 printf("Not enough buckets: %ju, need %u\n",
219 sb.nbuckets, 1 << 7);
223 SET_CACHE_DISCARD(&sb, discard);
224 SET_CACHE_REPLACEMENT(&sb, cache_replacement_policy);
234 "first_bucket: %u\n",
235 uuid_str, set_uuid_str,
236 (unsigned) sb.version,
245 sb.csum = csum_set(&sb);
247 if (pwrite(fd, &sb, sizeof(sb), SB_SECTOR << 9) != sizeof(sb)) {
248 perror("write error\n");
256 static unsigned get_blocksize(const char *path)
260 if (stat(path, &statbuf)) {
261 fprintf(stderr, "Error statting %s: %s\n",
262 path, strerror(errno));
266 return statbuf.st_blksize / 512;
269 int main(int argc, char **argv)
272 unsigned i, ncache_devices = 0, nbacking_devices = 0;
273 char *cache_devices[argc];
274 char *backing_devices[argc];
276 unsigned block_size = 0, bucket_size = 1024;
277 int writeback = 0, discard = 0;
278 unsigned cache_replacement_policy = 0;
279 uint64_t data_offset = BDEV_DATA_START_DEFAULT;
282 uuid_generate(set_uuid);
284 struct option opts[] = {
285 { "cache", 0, NULL, 'C' },
286 { "bdev", 0, NULL, 'B' },
287 { "bucket", 1, NULL, 'b' },
288 { "block", 1, NULL, 'w' },
289 { "writeback", 0, &writeback, 1 },
290 { "discard", 0, &discard, 1 },
291 { "cache_replacement_policy", 1, NULL, 'p' },
292 { "data_offset", 1, NULL, 'o' },
293 { "cset-uuid", 1, NULL, 'u' },
294 { "help", 0, NULL, 'h' },
295 { NULL, 0, NULL, 0 },
298 while ((c = getopt_long(argc, argv,
309 bucket_size = hatoi_validate(optarg, "bucket size");
312 block_size = hatoi_validate(optarg, "block size");
316 if (uuid_parse(optarg, sb.uuid)) {
317 printf("Bad uuid\n");
323 cache_replacement_policy = read_string_list(optarg,
324 cache_replacement_policies);
327 data_offset = atoll(optarg);
328 if (data_offset < BDEV_DATA_START_DEFAULT) {
329 printf("Bad data offset; minimum %d sectors\n",
330 BDEV_DATA_START_DEFAULT);
335 if (uuid_parse(optarg, set_uuid)) {
336 printf("Bad uuid\n");
345 printf("Please specify -C or -B\n");
350 backing_devices[nbacking_devices++] = optarg;
352 cache_devices[ncache_devices++] = optarg;
356 if (!ncache_devices && !nbacking_devices) {
357 printf("Please supply a device\n");
361 if (bucket_size < block_size) {
362 printf("Bucket size cannot be smaller than block size\n");
367 for (i = 0; i < ncache_devices; i++)
368 block_size = max(block_size,
369 get_blocksize(cache_devices[i]));
371 for (i = 0; i < nbacking_devices; i++)
372 block_size = max(block_size,
373 get_blocksize(backing_devices[i]));
376 for (i = 0; i < ncache_devices; i++)
377 write_sb(cache_devices[i], block_size, bucket_size,
378 writeback, discard, cache_replacement_policy,
379 data_offset, set_uuid, false);
381 for (i = 0; i < nbacking_devices; i++)
382 write_sb(backing_devices[i], block_size, bucket_size,
383 writeback, discard, cache_replacement_policy,
384 data_offset, set_uuid, true);