Commit | Line | Data |
---|---|---|
06ed4b31 | 1 | #define _XOPEN_SOURCE 500 |
1261ec42 CM |
2 | #ifndef __CHECKER__ |
3 | #include <sys/ioctl.h> | |
4 | #include <sys/mount.h> | |
5 | #endif | |
06ed4b31 CM |
6 | #include <stdio.h> |
7 | #include <stdlib.h> | |
8 | #include <sys/types.h> | |
9 | #include <sys/stat.h> | |
10 | #include <fcntl.h> | |
11 | #include <unistd.h> | |
12 | #include "kerncompat.h" | |
13 | #include "radix-tree.h" | |
14 | #include "ctree.h" | |
15 | #include "disk-io.h" | |
16 | ||
1261ec42 CM |
17 | #ifdef __CHECKER__ |
18 | #define BLKGETSIZE64 0 | |
19 | static inline int ioctl(int fd, int define, u64 *size) { return 0; } | |
20 | #endif | |
21 | ||
22 | #if 0 | |
23 | #if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64) | |
24 | # define BLKGETSIZE64 _IOR(0x12, 114, __u64) | |
25 | #endif | |
26 | #endif | |
27 | ||
123abc88 | 28 | int mkfs(int fd, u64 num_blocks, u32 blocksize) |
3768f368 CM |
29 | { |
30 | struct btrfs_super_block super; | |
123abc88 | 31 | struct btrfs_leaf *empty_leaf; |
3768f368 CM |
32 | struct btrfs_root_item root_item; |
33 | struct btrfs_item item; | |
34 | struct btrfs_extent_item extent_item; | |
35 | char *block; | |
36 | int ret; | |
123abc88 CM |
37 | u32 itemoff; |
38 | u32 start_block = BTRFS_SUPER_INFO_OFFSET / blocksize; | |
3768f368 | 39 | |
123abc88 CM |
40 | btrfs_set_super_blocknr(&super, start_block); |
41 | btrfs_set_super_root(&super, start_block + 1); | |
3768f368 CM |
42 | strcpy((char *)(&super.magic), BTRFS_MAGIC); |
43 | btrfs_set_super_blocksize(&super, blocksize); | |
44 | btrfs_set_super_total_blocks(&super, num_blocks); | |
1261ec42 | 45 | btrfs_set_super_blocks_used(&super, start_block + 5); |
3768f368 CM |
46 | |
47 | block = malloc(blocksize); | |
48 | memset(block, 0, blocksize); | |
49 | BUG_ON(sizeof(super) > blocksize); | |
50 | memcpy(block, &super, sizeof(super)); | |
123abc88 | 51 | ret = pwrite(fd, block, blocksize, BTRFS_SUPER_INFO_OFFSET); |
3768f368 CM |
52 | BUG_ON(ret != blocksize); |
53 | ||
54 | /* create the tree of root objects */ | |
123abc88 CM |
55 | empty_leaf = malloc(blocksize); |
56 | memset(empty_leaf, 0, blocksize); | |
57 | btrfs_set_header_parentid(&empty_leaf->header, | |
58 | BTRFS_ROOT_TREE_OBJECTID); | |
59 | btrfs_set_header_blocknr(&empty_leaf->header, start_block + 1); | |
9f5fae2f | 60 | btrfs_set_header_nritems(&empty_leaf->header, 3); |
3768f368 CM |
61 | |
62 | /* create the items for the root tree */ | |
123abc88 | 63 | btrfs_set_root_blocknr(&root_item, start_block + 2); |
3768f368 | 64 | btrfs_set_root_refs(&root_item, 1); |
123abc88 | 65 | itemoff = __BTRFS_LEAF_DATA_SIZE(blocksize) - sizeof(root_item); |
3768f368 CM |
66 | btrfs_set_item_offset(&item, itemoff); |
67 | btrfs_set_item_size(&item, sizeof(root_item)); | |
62e2749e CM |
68 | btrfs_set_disk_key_objectid(&item.key, BTRFS_EXTENT_TREE_OBJECTID); |
69 | btrfs_set_disk_key_offset(&item.key, 0); | |
70 | btrfs_set_disk_key_flags(&item.key, 0); | |
71 | btrfs_set_disk_key_type(&item.key, BTRFS_ROOT_ITEM_KEY); | |
123abc88 CM |
72 | memcpy(empty_leaf->items, &item, sizeof(item)); |
73 | memcpy(btrfs_leaf_data(empty_leaf) + itemoff, | |
74 | &root_item, sizeof(root_item)); | |
3768f368 | 75 | |
123abc88 | 76 | btrfs_set_root_blocknr(&root_item, start_block + 3); |
3768f368 CM |
77 | itemoff = itemoff - sizeof(root_item); |
78 | btrfs_set_item_offset(&item, itemoff); | |
9f5fae2f | 79 | btrfs_set_disk_key_objectid(&item.key, BTRFS_INODE_MAP_OBJECTID); |
123abc88 | 80 | memcpy(empty_leaf->items + 1, &item, sizeof(item)); |
9f5fae2f CM |
81 | memcpy(btrfs_leaf_data(empty_leaf) + itemoff, |
82 | &root_item, sizeof(root_item)); | |
83 | ||
84 | btrfs_set_root_blocknr(&root_item, start_block + 4); | |
85 | itemoff = itemoff - sizeof(root_item); | |
86 | btrfs_set_item_offset(&item, itemoff); | |
87 | btrfs_set_disk_key_objectid(&item.key, BTRFS_FS_TREE_OBJECTID); | |
88 | memcpy(empty_leaf->items + 2, &item, sizeof(item)); | |
123abc88 CM |
89 | memcpy(btrfs_leaf_data(empty_leaf) + itemoff, |
90 | &root_item, sizeof(root_item)); | |
91 | ret = pwrite(fd, empty_leaf, blocksize, (start_block + 1) * blocksize); | |
3768f368 CM |
92 | |
93 | /* create the items for the extent tree */ | |
123abc88 | 94 | btrfs_set_header_parentid(&empty_leaf->header, |
3768f368 | 95 | BTRFS_EXTENT_TREE_OBJECTID); |
123abc88 | 96 | btrfs_set_header_blocknr(&empty_leaf->header, start_block + 2); |
9f5fae2f | 97 | btrfs_set_header_nritems(&empty_leaf->header, 5); |
3768f368 CM |
98 | |
99 | /* item1, reserve blocks 0-16 */ | |
62e2749e CM |
100 | btrfs_set_disk_key_objectid(&item.key, 0); |
101 | btrfs_set_disk_key_offset(&item.key, start_block + 1); | |
102 | btrfs_set_disk_key_flags(&item.key, 0); | |
103 | btrfs_set_disk_key_type(&item.key, BTRFS_EXTENT_ITEM_KEY); | |
123abc88 CM |
104 | itemoff = __BTRFS_LEAF_DATA_SIZE(blocksize) - |
105 | sizeof(struct btrfs_extent_item); | |
3768f368 CM |
106 | btrfs_set_item_offset(&item, itemoff); |
107 | btrfs_set_item_size(&item, sizeof(struct btrfs_extent_item)); | |
108 | btrfs_set_extent_refs(&extent_item, 1); | |
109 | btrfs_set_extent_owner(&extent_item, 0); | |
123abc88 CM |
110 | memcpy(empty_leaf->items, &item, sizeof(item)); |
111 | memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item), | |
112 | &extent_item, btrfs_item_size(&item)); | |
3768f368 CM |
113 | |
114 | /* item2, give block 17 to the root */ | |
62e2749e CM |
115 | btrfs_set_disk_key_objectid(&item.key, start_block + 1); |
116 | btrfs_set_disk_key_offset(&item.key, 1); | |
3768f368 CM |
117 | itemoff = itemoff - sizeof(struct btrfs_extent_item); |
118 | btrfs_set_item_offset(&item, itemoff); | |
119 | btrfs_set_extent_owner(&extent_item, BTRFS_ROOT_TREE_OBJECTID); | |
123abc88 CM |
120 | memcpy(empty_leaf->items + 1, &item, sizeof(item)); |
121 | memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item), | |
122 | &extent_item, btrfs_item_size(&item)); | |
3768f368 CM |
123 | |
124 | /* item3, give block 18 to the extent root */ | |
62e2749e CM |
125 | btrfs_set_disk_key_objectid(&item.key, start_block + 2); |
126 | btrfs_set_disk_key_offset(&item.key, 1); | |
3768f368 CM |
127 | itemoff = itemoff - sizeof(struct btrfs_extent_item); |
128 | btrfs_set_item_offset(&item, itemoff); | |
129 | btrfs_set_extent_owner(&extent_item, BTRFS_EXTENT_TREE_OBJECTID); | |
123abc88 CM |
130 | memcpy(empty_leaf->items + 2, &item, sizeof(item)); |
131 | memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item), | |
132 | &extent_item, btrfs_item_size(&item)); | |
3768f368 | 133 | |
9f5fae2f | 134 | /* item4, give block 19 to the inode map */ |
62e2749e CM |
135 | btrfs_set_disk_key_objectid(&item.key, start_block + 3); |
136 | btrfs_set_disk_key_offset(&item.key, 1); | |
3768f368 CM |
137 | itemoff = itemoff - sizeof(struct btrfs_extent_item); |
138 | btrfs_set_item_offset(&item, itemoff); | |
9f5fae2f | 139 | btrfs_set_extent_owner(&extent_item, BTRFS_INODE_MAP_OBJECTID); |
123abc88 CM |
140 | memcpy(empty_leaf->items + 3, &item, sizeof(item)); |
141 | memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item), | |
142 | &extent_item, btrfs_item_size(&item)); | |
143 | ret = pwrite(fd, empty_leaf, blocksize, (start_block + 2) * blocksize); | |
144 | if (ret != blocksize) | |
3768f368 CM |
145 | return -1; |
146 | ||
9f5fae2f CM |
147 | /* item5, give block 20 to the FS root */ |
148 | btrfs_set_disk_key_objectid(&item.key, start_block + 4); | |
149 | btrfs_set_disk_key_offset(&item.key, 1); | |
150 | itemoff = itemoff - sizeof(struct btrfs_extent_item); | |
151 | btrfs_set_item_offset(&item, itemoff); | |
152 | btrfs_set_extent_owner(&extent_item, BTRFS_FS_TREE_OBJECTID); | |
153 | memcpy(empty_leaf->items + 4, &item, sizeof(item)); | |
154 | memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item), | |
155 | &extent_item, btrfs_item_size(&item)); | |
156 | ret = pwrite(fd, empty_leaf, blocksize, (start_block + 2) * blocksize); | |
157 | if (ret != blocksize) | |
158 | return -1; | |
159 | ||
160 | /* create the inode map */ | |
161 | btrfs_set_header_parentid(&empty_leaf->header, | |
162 | BTRFS_INODE_MAP_OBJECTID); | |
123abc88 CM |
163 | btrfs_set_header_blocknr(&empty_leaf->header, start_block + 3); |
164 | btrfs_set_header_nritems(&empty_leaf->header, 0); | |
165 | ret = pwrite(fd, empty_leaf, blocksize, (start_block + 3) * blocksize); | |
9f5fae2f CM |
166 | if (ret != blocksize) |
167 | return -1; | |
168 | ||
169 | /* finally create the FS root */ | |
170 | btrfs_set_header_parentid(&empty_leaf->header, BTRFS_FS_TREE_OBJECTID); | |
171 | btrfs_set_header_blocknr(&empty_leaf->header, start_block + 4); | |
172 | btrfs_set_header_nritems(&empty_leaf->header, 0); | |
173 | ret = pwrite(fd, empty_leaf, blocksize, (start_block + 4) * blocksize); | |
123abc88 | 174 | if (ret != blocksize) |
3768f368 CM |
175 | return -1; |
176 | return 0; | |
177 | } | |
1261ec42 CM |
178 | |
179 | u64 device_size(int fd, struct stat *st) | |
180 | { | |
181 | u64 size; | |
182 | if (S_ISREG(st->st_mode)) { | |
183 | return st->st_size; | |
184 | } | |
185 | if (!S_ISBLK(st->st_mode)) { | |
186 | return 0; | |
187 | } | |
188 | if (ioctl(fd, BLKGETSIZE64, &size) >= 0) { | |
189 | return size; | |
190 | } | |
191 | return 0; | |
192 | } | |
193 | ||
194 | int main(int ac, char **av) | |
195 | { | |
196 | char *file; | |
197 | u64 block_count = 0; | |
198 | int fd; | |
199 | struct stat st; | |
200 | int ret; | |
201 | int i; | |
202 | char *buf = malloc(4096); | |
203 | if (ac >= 2) { | |
204 | file = av[1]; | |
205 | if (ac == 3) { | |
206 | block_count = atoi(av[2]); | |
207 | if (!block_count) { | |
208 | fprintf(stderr, "error finding block count\n"); | |
209 | exit(1); | |
210 | } | |
211 | } | |
212 | } else { | |
213 | fprintf(stderr, "usage: mkfs.btrfs file [block count]\n"); | |
214 | exit(1); | |
215 | } | |
216 | fd = open(file, O_RDWR); | |
217 | if (fd < 0) { | |
218 | fprintf(stderr, "unable to open %s\n", file); | |
219 | exit(1); | |
220 | } | |
221 | ret = fstat(fd, &st); | |
222 | if (ret < 0) { | |
223 | fprintf(stderr, "unable to stat %s\n", file); | |
224 | exit(1); | |
225 | } | |
226 | if (block_count == 0) { | |
227 | block_count = device_size(fd, &st); | |
228 | if (block_count == 0) { | |
229 | fprintf(stderr, "unable to find %s size\n", file); | |
230 | exit(1); | |
231 | } | |
232 | } | |
233 | block_count /= 4096; | |
234 | if (block_count < 256) { | |
235 | fprintf(stderr, "device %s is too small\n", file); | |
236 | exit(1); | |
237 | } | |
238 | memset(buf, 0, 4096); | |
239 | for(i = 0; i < 6; i++) { | |
240 | ret = write(fd, buf, 4096); | |
241 | if (ret != 4096) { | |
242 | fprintf(stderr, "unable to zero fill device\n"); | |
243 | exit(1); | |
244 | } | |
245 | } | |
246 | ret = mkfs(fd, block_count, 4096); | |
247 | if (ret) { | |
248 | fprintf(stderr, "error during mkfs %d\n", ret); | |
249 | exit(1); | |
250 | } | |
251 | printf("fs created on %s blocksize %d blocks %Lu\n", | |
252 | file, 4096, block_count); | |
253 | return 0; | |
254 | } | |
255 |