]> git.sesse.net Git - bcachefs-tools-debian/blob - make-bcache.c
Add an option for setting the set uuid
[bcachefs-tools-debian] / make-bcache.c
1 #define _FILE_OFFSET_BITS       64
2 #define __USE_FILE_OFFSET64
3 #define _XOPEN_SOURCE 600
4
5 #include <fcntl.h>
6 #include <linux/fs.h>
7 #include <stdbool.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/ioctl.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16 #include <uuid/uuid.h>
17
18 #include "bcache.h"
19
20 char zero[4096];
21
22 uint64_t getblocks(int fd)
23 {
24         uint64_t ret;
25         struct stat statbuf;
26         if (fstat(fd, &statbuf)) {
27                 perror("stat error\n");
28                 exit(EXIT_FAILURE);
29         }
30         ret = statbuf.st_size / 512;
31         if (S_ISBLK(statbuf.st_mode))
32                 if (ioctl(fd, BLKGETSIZE, &ret)) {
33                         perror("ioctl error");
34                         exit(EXIT_FAILURE);
35                 }
36         return ret;
37 }
38
39 uint64_t hatoi(const char *s)
40 {
41         char *e;
42         long long i = strtoll(s, &e, 10);
43         switch (*e) {
44                 case 't':
45                 case 'T':
46                         i *= 1024;
47                 case 'g':
48                 case 'G':
49                         i *= 1024;
50                 case 'm':
51                 case 'M':
52                         i *= 1024;
53                 case 'k':
54                 case 'K':
55                         i *= 1024;
56         }
57         return i;
58 }
59
60 void usage()
61 {
62         printf("Usage: make-bcache [options] device\n"
63                "        -C Format a cache device\n"
64                "        -B Format a backing device\n"
65                "        -b bucket size\n"
66                "        -w block size (hard sector size of SSD, often 2k)\n"
67                "        -j journal size, in buckets\n"
68                "        -U UUID\n"
69                "        -S Set UUID\n");
70         exit(EXIT_FAILURE);
71 }
72
73 int main(int argc, char **argv)
74 {
75         bool cache = false, backingdev = false;
76         int64_t nblocks, journal = 0;
77         int fd, i, c;
78         char uuid[40], set_uuid[40];
79         struct cache_sb sb;
80
81         memset(&sb, 0, sizeof(struct cache_sb));
82
83         uuid_generate(sb.uuid);
84         uuid_generate(sb.set_uuid);
85
86         while ((c = getopt(argc, argv, "CBU:w:b:j:")) != -1)
87                 switch (c) {
88                 case 'C':
89                         cache = true;
90                         break;
91                 case 'B':
92                         backingdev = true;
93                         break;
94                 case 'b':
95                         sb.bucket_size = hatoi(optarg) / 512;
96                         break;
97                 case 'w':
98                         sb.block_size = hatoi(optarg) / 512;
99                         break;
100                 case 'j':
101                         journal = atoi(optarg);
102                         break;
103                 case 'U':
104                         if (uuid_parse(optarg, sb.uuid)) {
105                                 printf("Bad uuid\n");
106                                 exit(EXIT_FAILURE);
107                         }
108                         break;
109                 case 'S':
110                         if (uuid_parse(optarg, sb.set_uuid)) {
111                                 printf("Bad uuid\n");
112                                 exit(EXIT_FAILURE);
113                         }
114                         break;
115                 }
116
117         if (!sb.block_size)
118                 sb.block_size = 4;
119
120         if (!sb.bucket_size)
121                 sb.bucket_size = cache ? 256 : 8192;
122
123         if (cache == backingdev) {
124                 printf("Must specify one of -C or -B\n");
125                 usage();
126         }
127
128         if (argc <= optind) {
129                 printf("Please supply a device\n");
130                 exit(EXIT_FAILURE);
131         }
132
133         fd = open(argv[optind], O_RDWR);
134         if (fd == -1) {
135                 perror("Can't open dev\n");
136                 exit(EXIT_FAILURE);
137         }
138         nblocks = getblocks(fd);
139         printf("device is %ju sectors\n", nblocks);
140
141         if (sb.bucket_size < sb.block_size ||
142             sb.bucket_size > nblocks / 8) {
143                 printf("Bad bucket size %i\n", sb.bucket_size);
144                 exit(EXIT_FAILURE);
145         }
146
147         memcpy(sb.magic, bcache_magic, 16);
148         sb.version = backingdev ? CACHE_BACKING_DEV : 0;
149         sb.nbuckets = nblocks / sb.bucket_size;
150         sb.nr_in_set = 1;
151         uuid_unparse(sb.uuid, uuid);
152         uuid_unparse(sb.set_uuid, set_uuid);
153
154         sb.journal_start = ((sb.nbuckets * sizeof(struct bucket_disk)) + (24 << 9)) / (sb.bucket_size << 9) + 1;
155         sb.first_bucket = sb.journal_start + journal;
156
157         printf("block_size:             %u\n"
158                "bucket_size:            %u\n"
159                "journal_start:          %u\n"
160                "first_bucket:           %u\n"
161                "nbuckets:               %ju\n"
162                "UUID:                   %s\n"
163                "Set UUID:               %s\n",
164                sb.block_size,
165                sb.bucket_size,
166                sb.journal_start,
167                sb.first_bucket,
168                sb.nbuckets,
169                uuid, set_uuid);
170
171         if (!backingdev) {
172                 /* Zero out priorities */
173                 lseek(fd, 4096, SEEK_SET);
174                 for (i = 8; i < sb.first_bucket * sb.bucket_size; i++)
175                         if (write(fd, zero, 512) != 512)
176                                 goto err;
177         }
178
179         if (pwrite(fd, &sb, sizeof(sb), 4096) != sizeof(sb))
180                 goto err;
181
182         fsync(fd);
183         exit(EXIT_SUCCESS);
184 err:
185         perror("write error\n");
186         return 1;
187 }