]> git.sesse.net Git - bcachefs-tools-debian/blob - make-bcache.c
Updates for backing devices
[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                "        -U UUID\n");
67         exit(EXIT_FAILURE);
68 }
69
70 int main(int argc, char **argv)
71 {
72         bool cache = false, backingdev = false;
73         int64_t nblocks, journal = 0;
74         int fd, i, c;
75         char uuid[40], set_uuid[40];
76         struct cache_sb sb;
77
78         memset(&sb, 0, sizeof(struct cache_sb));
79
80         uuid_generate(sb.uuid);
81         uuid_generate(sb.set_uuid);
82
83         while ((c = getopt(argc, argv, "CBU:w:b:j:")) != -1)
84                 switch (c) {
85                 case 'C':
86                         cache = true;
87                         break;
88                 case 'B':
89                         backingdev = true;
90                         break;
91                 case 'b':
92                         sb.bucket_size = hatoi(optarg) / 512;
93                         break;
94                 case 'w':
95                         sb.block_size = hatoi(optarg) / 512;
96                         break;
97                 case 'j':
98                         journal = atoi(optarg);
99                         break;
100                 case 'U':
101                         if (uuid_parse(optarg, sb.uuid)) {
102                                 printf("Bad uuid\n");
103                                 exit(EXIT_FAILURE);
104                         }
105                         break;
106                 }
107
108         if (!sb.block_size)
109                 sb.block_size = 4;
110
111         if (!sb.bucket_size)
112                 sb.bucket_size = cache ? 256 : 8192;
113
114         if (cache == backingdev) {
115                 printf("Must specify one of -C or -B\n");
116                 exit(EXIT_FAILURE);
117         }
118
119         if (argc <= optind) {
120                 printf("Please supply a device\n");
121                 exit(EXIT_FAILURE);
122         }
123
124         fd = open(argv[optind], O_RDWR);
125         if (fd == -1) {
126                 perror("Can't open dev\n");
127                 exit(EXIT_FAILURE);
128         }
129         nblocks = getblocks(fd);
130         printf("device is %ju sectors\n", nblocks);
131
132         if (sb.bucket_size < sb.block_size ||
133             sb.bucket_size > nblocks / 8) {
134                 printf("Bad bucket size %i\n", sb.bucket_size);
135                 exit(EXIT_FAILURE);
136         }
137
138         memcpy(sb.magic, bcache_magic, 16);
139         sb.version = backingdev ? CACHE_BACKING_DEV : 0;
140         sb.nbuckets = nblocks / sb.bucket_size;
141         sb.nr_in_set = 1;
142         uuid_unparse(sb.uuid, uuid);
143         uuid_unparse(sb.set_uuid, set_uuid);
144
145         sb.journal_start = ((sb.nbuckets * sizeof(struct bucket_disk)) + (24 << 9)) / (sb.bucket_size << 9) + 1;
146         sb.first_bucket = sb.journal_start + journal;
147
148         printf("block_size:             %u\n"
149                "bucket_size:            %u\n"
150                "journal_start:          %u\n"
151                "first_bucket:           %u\n"
152                "nbuckets:               %ju\n"
153                "UUID:                   %s\n"
154                "Set UUID:               %s\n",
155                sb.block_size,
156                sb.bucket_size,
157                sb.journal_start,
158                sb.first_bucket,
159                sb.nbuckets,
160                uuid, set_uuid);
161
162         /* Zero out priorities */
163         lseek(fd, 4096, SEEK_SET);
164         for (i = 8; i < sb.first_bucket * sb.bucket_size; i++)
165                 if (write(fd, zero, 512) != 512)
166                         goto err;
167
168         if (pwrite(fd, &sb, sizeof(sb), 4096) != sizeof(sb))
169                 goto err;
170
171         fsync(fd);
172         exit(EXIT_SUCCESS);
173 err:
174         perror("write error\n");
175         return 1;
176 }