]> git.sesse.net Git - bcachefs-tools-debian/blob - make-bcache.c
04861f91ae785cfe1bdbcb64fe6b96a2e078ec05
[bcachefs-tools-debian] / make-bcache.c
1 #define _FILE_OFFSET_BITS       64
2 #define __USE_FILE_OFFSET64
3 #define _XOPEN_SOURCE 500
4
5 #include <fcntl.h>
6 #include <linux/fs.h>
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/ioctl.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <unistd.h>
15
16 static const char bcache_magic[] = {
17         0xc6, 0x85, 0x73, 0xf6, 0x4e, 0x1a, 0x45, 0xca,
18         0x82, 0x65, 0xf5, 0x7f, 0x48, 0xba, 0x6d, 0x81 };
19
20 struct cache_sb {
21         uint8_t  magic[16];
22         uint32_t version;
23         uint16_t block_size;            /* sectors */
24         uint16_t bucket_size;           /* sectors */
25         uint32_t journal_start;         /* buckets */
26         uint32_t first_bucket;          /* start of data */
27         uint64_t nbuckets;              /* device size */
28         uint64_t btree_root;
29         uint16_t btree_level;
30 };
31
32 struct bucket_disk {
33         uint16_t        priority;
34         uint8_t         generation;
35 } __attribute((packed));
36
37 char zero[4096];
38
39 long getblocks(int fd)
40 {
41         long ret;
42         struct stat statbuf;
43         if (fstat(fd, &statbuf)) {
44                 perror("stat error\n");
45                 exit(EXIT_FAILURE);
46         }
47         ret = statbuf.st_size / 512;
48         if (S_ISBLK(statbuf.st_mode))
49                 if (ioctl(fd, BLKGETSIZE, &ret)) {
50                         perror("ioctl error");
51                         exit(EXIT_FAILURE);
52                 }
53         return ret;
54 }
55
56 long hatoi(const char *s)
57 {
58         char *e;
59         long long i = strtol(s, &e, 10);
60         switch (*e) {
61                 case 't':
62                 case 'T':
63                         i *= 1024;
64                 case 'g':
65                 case 'G':
66                         i *= 1024;
67                 case 'm':
68                 case 'M':
69                         i *= 1024;
70                 case 'k':
71                 case 'K':
72                         i *= 1024;
73         }
74         return i;
75 }
76
77 void usage()
78 {
79         printf("");
80         exit(EXIT_FAILURE);
81 }
82
83 int main(int argc, char **argv)
84 {
85         int64_t nblocks, bucketsize = 32, blocksize = 8;
86         int fd, i, c;
87         struct cache_sb sb;
88
89         while ((c = getopt(argc, argv, "b:")) != -1)
90                 switch (c) {
91                 case 'b':
92                         bucketsize = hatoi(optarg) / 512;
93                         break;
94                 }
95
96         if (argc <= optind) {
97                 printf("Please supply a device\n");
98                 exit(EXIT_FAILURE);
99         }
100
101         fd = open(argv[optind], O_RDWR);
102         if (fd == -1) {
103                 perror("Can't open dev\n");
104                 exit(EXIT_FAILURE);
105         }
106         nblocks = getblocks(fd);
107         printf("device is %li sectors\n", nblocks);
108
109         if (bucketsize < blocksize ||
110             bucketsize > nblocks / 8) {
111                 printf("Bad bucket size %li\n", bucketsize);
112                 exit(EXIT_FAILURE);
113         }
114
115         memcpy(sb.magic, bcache_magic, 16);
116         sb.version = 0;
117         sb.block_size = blocksize;
118         sb.bucket_size = bucketsize;
119         sb.nbuckets = nblocks / sb.bucket_size;
120
121         do
122                 sb.first_bucket = ((--sb.nbuckets * sizeof(struct bucket_disk)) + (24 << 9)) / (sb.bucket_size << 9) + 1;
123         while ((sb.nbuckets + sb.first_bucket) * sb.bucket_size > nblocks);
124
125         sb.journal_start = sb.first_bucket;
126
127         sb.btree_root = sb.first_bucket * sb.bucket_size;
128         sb.btree_level = 0;
129
130         printf("block_size:             %u\n"
131                "bucket_size:            %u\n"
132                "journal_start:          %u\n"
133                "first_bucket:           %u\n"
134                "nbuckets:               %ju\n",
135                sb.block_size,
136                sb.bucket_size,
137                sb.journal_start,
138                sb.first_bucket,
139                sb.nbuckets);
140
141         /* Zero out priorities */
142         lseek(fd, 4096, SEEK_SET);
143         for (i = 8; i < sb.first_bucket * sb.bucket_size; i++)
144                 if (write(fd, zero, 512) != 512)
145                         goto err;
146
147         if (pwrite(fd, &sb, sizeof(sb), 4096) != sizeof(sb))
148                 goto err;
149
150         fsync(fd);
151         exit(EXIT_SUCCESS);
152 err:
153         perror("write error\n");
154         return 1;
155 }