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