]> git.sesse.net Git - bcachefs-tools-debian/blob - make-bcache.c
Merge branch 'master' of ssh://gits.daterainc.com:2984/project/2013.MAIN/bcache-tools
[bcachefs-tools-debian] / make-bcache.c
1 /*
2  * Author: Kent Overstreet <kmo@daterainc.com>
3  *
4  * GPLv2
5  */
6
7 #define _FILE_OFFSET_BITS       64
8 #define __USE_FILE_OFFSET 64
9 #define _XOPEN_SOURCE 600
10
11 #include <ctype.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <getopt.h>
15 #include <limits.h>
16 #include <linux/fs.h>
17 #include <stdbool.h>
18 #include <stdint.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/ioctl.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <uuid/uuid.h>
27
28 #include "bcache.h"
29
30 void usage()
31 {
32         fprintf(stderr,
33                    "Usage: make-bcache [options] device\n"
34                "        -C, --cache                     Format a cache device\n"
35                "        -B, --bdev                      Format a backing device\n"
36                "            --wipe-bcache               destroy existing bcache data if present\n"
37                "        -l, --label                     label\n"
38                "            --cset-uuid                 UUID for the cache set\n"
39                "            --csum-type                 One of (none|crc32c|crc64)\n"
40
41                "        -b, --bucket                    bucket size\n"
42                "        -w, --block                     block size (hard sector size of SSD, often 2k)\n"
43
44                "            --replication-set           replication set of subsequent devices\n"
45                "            --meta-replicas             number of metadata replicas\n"
46                "            --data-replicas             number of data replicas\n"
47                "            --tier                      tier of subsequent devices\n"
48                "            --cache_replacement_policy  one of (lru|fifo|random)\n"
49                "            --discard                   enable discards\n"
50
51                "            --writeback                 enable writeback\n"
52                "        -o, --data-offset               data offset in sectors\n"
53                "        -h, --help                      display this help and exit\n");
54         exit(EXIT_FAILURE);
55 }
56
57 int main(int argc, char **argv)
58 {
59         int c, bdev = -1;
60         size_t i, nr_backing_devices = 0;
61
62         unsigned block_size = 0;
63         unsigned bucket_sizes[argc];
64         int num_bucket_sizes = 0;
65         int writeback = 0, discard = 0, wipe_bcache = 0;
66         unsigned replication_set = 0, tier = 0, replacement_policy = 0;
67         uint64_t data_offset = BDEV_DATA_START_DEFAULT;
68         char *label = NULL;
69
70         const char *cache_devices[argc];
71         int cache_dev_fd[argc];
72
73         const char *backing_devices[argc];
74         int backing_dev_fd[argc];
75         const char *backing_dev_labels[argc];
76
77         enum long_opts {
78                 CACHE_SET_UUID = 256,
79                 CSUM_TYPE,
80                 REPLICATION_SET,
81                 META_REPLICAS,
82                 DATA_REPLICAS,
83         };
84
85         const struct option opts[] = {
86                 { "cache",                      0, NULL,        'C' },
87                 { "bdev",                       0, NULL,        'B' },
88                 { "wipe-bcache",                0, &wipe_bcache, 1  },
89                 { "label",                      1, NULL,        'l' },
90                 { "cset-uuid",                  1, NULL,        CACHE_SET_UUID },
91                 { "csum-type",                  1, NULL,        CSUM_TYPE },
92
93                 { "bucket",                     1, NULL,        'b' },
94                 { "block",                      1, NULL,        'w' },
95
96                 { "replication-set",            1, NULL,        REPLICATION_SET },
97                 { "meta-replicas",              1, NULL,        META_REPLICAS},
98                 { "data-replicas",              1, NULL,        DATA_REPLICAS },
99                 { "tier",                       1, NULL,        't' },
100                 { "cache_replacement_policy",   1, NULL,        'p' },
101                 { "discard",                    0, &discard,    1   },
102
103                 { "writeback",                  0, &writeback,  1   },
104                 { "data_offset",                1, NULL,        'o' },
105
106                 { "help",                       0, NULL,        'h' },
107                 { NULL,                         0, NULL,        0 },
108         };
109
110         struct cache_sb *cache_set_sb = calloc(1, sizeof(*cache_set_sb) +
111                                      sizeof(struct cache_member) * argc);
112
113         uuid_generate(cache_set_sb->set_uuid.b);
114         SET_CACHE_PREFERRED_CSUM_TYPE(cache_set_sb, BCH_CSUM_CRC32C);
115         SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb, 1);
116         SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb, 1);
117         bucket_sizes[0] = 1024;
118
119         while ((c = getopt_long(argc, argv,
120                                 "-hCBU:w:b:l:",
121                                 opts, NULL)) != -1) {
122
123                 switch (c) {
124                 case 'C':
125                         bdev = 0;
126                         break;
127                 case 'B':
128                         bdev = 1;
129                         break;
130                 case 'l':
131                         label = optarg;
132                         memcpy(cache_set_sb->label, label,
133                                sizeof(cache_set_sb->label));
134                         break;
135                 case CACHE_SET_UUID:
136                         if (uuid_parse(optarg, cache_set_sb->set_uuid.b)) {
137                                 fprintf(stderr, "Bad uuid\n");
138                                 exit(EXIT_FAILURE);
139                         }
140                         break;
141                 case CSUM_TYPE:
142                         SET_CACHE_PREFERRED_CSUM_TYPE(cache_set_sb,
143                                 read_string_list_or_die(optarg, csum_types,
144                                                         "csum type"));
145                         break;
146
147                 case 'b':
148                         bucket_sizes[num_bucket_sizes] = hatoi_validate(optarg, "bucket size");
149                         num_bucket_sizes++;
150                         break;
151                 case 'w':
152                         block_size = hatoi_validate(optarg, "block size");
153                         break;
154
155                 case REPLICATION_SET:
156                         replication_set = strtoul_or_die(optarg,
157                                                          CACHE_REPLICATION_SET_MAX,
158                                                          "replication set");
159                         break;
160                 case META_REPLICAS:
161                         SET_CACHE_SET_META_REPLICAS_WANT(cache_set_sb,
162                                         strtoul_or_die(optarg, 
163                                                        CACHE_SET_META_REPLICAS_WANT_MAX,
164                                                        "meta replicas"));
165                         break;
166                 case DATA_REPLICAS:
167                         SET_CACHE_SET_DATA_REPLICAS_WANT(cache_set_sb,
168                                         strtoul_or_die(optarg, 
169                                                        CACHE_SET_DATA_REPLICAS_WANT_MAX,
170                                                        "data replicas"));
171                         break;
172                 case 't':
173                         tier = strtoul_or_die(optarg, CACHE_TIERS, "tier");
174                         break;
175                 case 'p':
176                         replacement_policy = read_string_list_or_die(optarg,
177                                                         replacement_policies,
178                                                         "cache replacement policy");
179                         break;
180
181                 case 'o':
182                         data_offset = atoll(optarg);
183                         if (data_offset < BDEV_DATA_START_DEFAULT) {
184                                 fprintf(stderr, "Bad data offset; minimum %d sectors\n",
185                                        BDEV_DATA_START_DEFAULT);
186                                 exit(EXIT_FAILURE);
187                         }
188                         break;
189                 case 'h':
190                         usage();
191                         break;
192                 case 1:
193                         if (bdev == -1) {
194                                 fprintf(stderr, "Please specify -C or -B\n");
195                                 exit(EXIT_FAILURE);
196                         }
197
198                         if (bdev) {
199                                 backing_dev_labels[nr_backing_devices] = label;
200                                 backing_devices[nr_backing_devices++] = optarg;
201                         } else {
202                                 cache_devices[cache_set_sb->nr_in_set] = optarg;
203                                 next_cache_device(cache_set_sb,
204                                                   replication_set,
205                                                   tier,
206                                                   replacement_policy,
207                                                   discard);
208                         }
209
210                         break;
211                 }
212         }
213
214         if (!cache_set_sb->nr_in_set && !nr_backing_devices) {
215                 fprintf(stderr, "Please supply a device\n");
216                 usage();
217         }
218
219         i = 0;
220         do {
221                 if (bucket_sizes[i] < block_size) {
222                         fprintf(stderr, "Bucket size cannot be smaller than block size\n");
223                         exit(EXIT_FAILURE);
224                 }
225                 i++;
226         } while (i < num_bucket_sizes);
227
228         if (!block_size) {
229                 for (i = 0; i < cache_set_sb->nr_in_set; i++)
230                         block_size = max(block_size,
231                                          get_blocksize(cache_devices[i]));
232
233                 for (i = 0; i < nr_backing_devices; i++)
234                         block_size = max(block_size,
235                                          get_blocksize(backing_devices[i]));
236         }
237
238         for (i = 0; i < cache_set_sb->nr_in_set; i++)
239                 cache_dev_fd[i] = dev_open(cache_devices[i], wipe_bcache);
240
241         for (i = 0; i < nr_backing_devices; i++)
242                 backing_dev_fd[i] = dev_open(backing_devices[i], wipe_bcache);
243
244         write_cache_sbs(cache_dev_fd, cache_set_sb, block_size,
245                                         bucket_sizes, num_bucket_sizes);
246
247         for (i = 0; i < nr_backing_devices; i++)
248                 write_backingdev_sb(backing_dev_fd[i],
249                                     block_size, bucket_sizes,
250                                     writeback, data_offset,
251                                     backing_dev_labels[i],
252                                     cache_set_sb->set_uuid);
253
254         return 0;
255 }