Switch to byte granular allocations
[platform/upstream/btrfs-progs.git] / mkfs.c
1 /*
2  * Copyright (C) 2007 Oracle.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public
6  * License v2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public
14  * License along with this program; if not, write to the
15  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16  * Boston, MA 021110-1307, USA.
17  */
18
19 #define _XOPEN_SOURCE 500
20 #ifndef __CHECKER__
21 #include <sys/ioctl.h>
22 #include <sys/mount.h>
23 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <uuid/uuid.h>
31 #include "radix-tree.h"
32 #include <linux/fs.h>
33 #include "kerncompat.h"
34 #include "ctree.h"
35 #include "disk-io.h"
36 #include "transaction.h"
37
38 #ifdef __CHECKER__
39 #define BLKGETSIZE64 0
40 static inline int ioctl(int fd, int define, u64 *size) { return 0; }
41 #endif
42
43 static int __make_root_dir(struct btrfs_trans_handle *trans,
44                            struct btrfs_root *root, u64 objectid)
45 {
46         int ret;
47         char buf[8];
48         struct btrfs_key inode_map;
49         struct btrfs_inode_item inode_item;
50
51         buf[0] = '.';
52         buf[1] = '.';
53
54         inode_map.objectid = objectid;
55         btrfs_set_key_type(&inode_map, BTRFS_INODE_ITEM_KEY);
56         inode_map.offset = 0;
57
58         memset(&inode_item, 0, sizeof(inode_item));
59         btrfs_set_inode_generation(&inode_item, root->fs_info->generation);
60         btrfs_set_inode_size(&inode_item, 6);
61         btrfs_set_inode_nlink(&inode_item, 1);
62         btrfs_set_inode_nblocks(&inode_item, 1);
63         btrfs_set_inode_mode(&inode_item, S_IFDIR | 0555);
64
65         if (root->fs_info->tree_root == root)
66                 btrfs_set_super_root_dir(root->fs_info->disk_super, objectid);
67
68         ret = btrfs_insert_inode(trans, root, objectid, &inode_item);
69         if (ret)
70                 goto error;
71         ret = btrfs_insert_dir_item(trans, root, buf, 1, objectid,
72                                     &inode_map, BTRFS_FT_DIR);
73         if (ret)
74                 goto error;
75         ret = btrfs_insert_dir_item(trans, root, buf, 2, objectid,
76                                     &inode_map, BTRFS_FT_DIR);
77         if (ret)
78                 goto error;
79         btrfs_set_root_dirid(&root->root_item, objectid);
80         ret = 0;
81 error:
82         return ret;
83 }
84
85 static int make_block_groups(struct btrfs_trans_handle *trans,
86                              struct btrfs_root *root)
87 {
88         u64 group_size;
89         u64 total_bytes;
90         u64 cur_start;
91         int ret;
92         u64 nr = 0;
93         struct btrfs_block_group_cache *cache;
94
95         root = root->fs_info->extent_root;
96
97         /* first we bootstrap the things into cache */
98         group_size = BTRFS_BLOCK_GROUP_SIZE;
99         cache = malloc(sizeof(*cache));
100         cache->key.objectid = 0;
101         cache->key.offset = group_size;
102         btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY);
103
104         memset(&cache->item, 0, sizeof(cache->item));
105         btrfs_set_block_group_used(&cache->item,
106                            btrfs_super_bytes_used(root->fs_info->disk_super));
107         ret = radix_tree_insert(&root->fs_info->block_group_radix,
108                                 group_size - 1, (void *)cache);
109         BUG_ON(ret);
110
111         total_bytes = btrfs_super_total_bytes(root->fs_info->disk_super);
112         cur_start = group_size;
113         while(cur_start < total_bytes) {
114                 cache = malloc(sizeof(*cache));
115                 cache->key.objectid = cur_start;
116                 cache->key.offset = group_size;
117                 btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY);
118                 memset(&cache->item, 0, sizeof(cache->item));
119                 if (nr % 3)
120                         cache->item.flags |= BTRFS_BLOCK_GROUP_DATA;
121
122                 ret = radix_tree_insert(&root->fs_info->block_group_radix,
123                                         cur_start + group_size - 1,
124                                         (void *)cache);
125                 BUG_ON(ret);
126                 cur_start += group_size;
127                 nr++;
128         }
129         /* then insert all the items */
130         cur_start = 0;
131         while(cur_start < total_bytes) {
132                 cache = radix_tree_lookup(&root->fs_info->block_group_radix,
133                                           cur_start + group_size - 1);
134                 BUG_ON(!cache);
135                 ret = btrfs_insert_block_group(trans, root, &cache->key,
136                                                &cache->item);
137                 BUG_ON(ret);
138                 cur_start += group_size;
139         }
140         return 0;
141 }
142
143 static int make_root_dir(int fd) {
144         struct btrfs_root *root;
145         struct btrfs_super_block super;
146         struct btrfs_trans_handle *trans;
147         int ret;
148         struct btrfs_key location;
149
150         root = open_ctree_fd(fd, &super);
151
152         if (!root) {
153                 fprintf(stderr, "ctree init failed\n");
154                 return -1;
155         }
156         trans = btrfs_start_transaction(root, 1);
157         ret = make_block_groups(trans, root);
158         ret = __make_root_dir(trans, root->fs_info->tree_root,
159                               BTRFS_ROOT_TREE_DIR_OBJECTID);
160         if (ret)
161                 goto err;
162         ret = __make_root_dir(trans, root, BTRFS_FIRST_FREE_OBJECTID);
163         if (ret)
164                 goto err;
165         memcpy(&location, &root->fs_info->fs_root->root_key, sizeof(location));
166         location.offset = (u64)-1;
167         ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root,
168                         "default", 7,
169                         btrfs_super_root_dir(root->fs_info->disk_super),
170                         &location, BTRFS_FT_DIR);
171         if (ret)
172                 goto err;
173         btrfs_commit_transaction(trans, root, root->fs_info->disk_super);
174         ret = close_ctree(root, &super);
175 err:
176         return ret;
177 }
178
179 int mkfs(int fd, char *pathname, u64 num_bytes, u32 nodesize, u32 leafsize,
180          u32 sectorsize)
181 {
182         struct btrfs_super_block super;
183         struct btrfs_leaf *empty_leaf;
184         struct btrfs_root_item root_item;
185         struct btrfs_item item;
186         struct btrfs_extent_item extent_item;
187         struct btrfs_inode_item *inode_item;
188         char *block;
189         int ret;
190         u32 itemoff;
191         u32 start_block = BTRFS_SUPER_INFO_OFFSET;
192         u32 first_free = BTRFS_SUPER_INFO_OFFSET + sectorsize;
193
194         btrfs_set_super_generation(&super, 1);
195         btrfs_set_super_bytenr(&super, start_block);
196         btrfs_set_super_root_level(&super, 0);
197         btrfs_set_super_root(&super, first_free);
198         strcpy((char *)(&super.magic), BTRFS_MAGIC);
199
200 printf("blocksize is %d\n", leafsize);
201         btrfs_set_super_sectorsize(&super, sectorsize);
202         btrfs_set_super_leafsize(&super, leafsize);
203         btrfs_set_super_nodesize(&super, nodesize);
204
205         num_bytes = (num_bytes / sectorsize) * sectorsize;
206         btrfs_set_super_total_bytes(&super, num_bytes);
207         btrfs_set_super_bytes_used(&super, start_block + 3 * leafsize +
208                                    sectorsize);
209         uuid_generate(super.fsid);
210
211         block = malloc(sectorsize);
212         memset(block, 0, sectorsize);
213         BUG_ON(sizeof(super) > sectorsize);
214         memcpy(block, &super, sizeof(super));
215         ret = pwrite(fd, block, sectorsize, BTRFS_SUPER_INFO_OFFSET);
216         BUG_ON(ret != sectorsize);
217
218         /* create the tree of root objects */
219         empty_leaf = malloc(leafsize);
220         memset(empty_leaf, 0, leafsize);
221         btrfs_set_header_bytenr(&empty_leaf->header, first_free);
222         btrfs_set_header_nritems(&empty_leaf->header, 2);
223         btrfs_set_header_generation(&empty_leaf->header, 0);
224         btrfs_set_header_owner(&empty_leaf->header, BTRFS_ROOT_TREE_OBJECTID);
225         memcpy(empty_leaf->header.fsid, super.fsid,
226                sizeof(empty_leaf->header.fsid));
227
228         /* create the items for the root tree */
229         inode_item = &root_item.inode;
230         memset(inode_item, 0, sizeof(*inode_item));
231         btrfs_set_inode_generation(inode_item, 1);
232         btrfs_set_inode_size(inode_item, 3);
233         btrfs_set_inode_nlink(inode_item, 1);
234         btrfs_set_inode_nblocks(inode_item, 1);
235         btrfs_set_inode_mode(inode_item, S_IFDIR | 0755);
236
237         // memset(&root_item, 0, sizeof(root_item));
238         btrfs_set_root_dirid(&root_item, 0);
239         btrfs_set_root_refs(&root_item, 1);
240         btrfs_set_disk_key_offset(&item.key, 0);
241         btrfs_set_item_size(&item, sizeof(root_item));
242         btrfs_set_disk_key_type(&item.key, BTRFS_ROOT_ITEM_KEY);
243
244         itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) - sizeof(root_item);
245         btrfs_set_root_bytenr(&root_item, first_free + leafsize);
246         root_item.level = 0;
247         btrfs_set_item_offset(&item, itemoff);
248         btrfs_set_disk_key_objectid(&item.key, BTRFS_EXTENT_TREE_OBJECTID);
249         memcpy(empty_leaf->items, &item, sizeof(item));
250         memcpy(btrfs_leaf_data(empty_leaf) + itemoff,
251                 &root_item, sizeof(root_item));
252
253         btrfs_set_root_bytenr(&root_item, first_free + leafsize * 2);
254         btrfs_set_root_bytes_used(&root_item, 1);
255         itemoff = itemoff - sizeof(root_item);
256         btrfs_set_item_offset(&item, itemoff);
257         btrfs_set_disk_key_objectid(&item.key, BTRFS_FS_TREE_OBJECTID);
258         memcpy(empty_leaf->items + 1, &item, sizeof(item));
259         memcpy(btrfs_leaf_data(empty_leaf) + itemoff,
260                 &root_item, sizeof(root_item));
261         ret = pwrite(fd, empty_leaf, leafsize, first_free);
262
263         /* create the items for the extent tree */
264         btrfs_set_header_bytenr(&empty_leaf->header, first_free + leafsize);
265         btrfs_set_header_nritems(&empty_leaf->header, 4);
266
267         /* item1, reserve blocks 0-16 */
268         btrfs_set_disk_key_objectid(&item.key, 0);
269         btrfs_set_disk_key_offset(&item.key, first_free);
270         btrfs_set_disk_key_type(&item.key, 0);
271         btrfs_set_disk_key_type(&item.key, BTRFS_EXTENT_ITEM_KEY);
272         itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) -
273                         sizeof(struct btrfs_extent_item);
274         btrfs_set_item_offset(&item, itemoff);
275         btrfs_set_item_size(&item, sizeof(struct btrfs_extent_item));
276         btrfs_set_extent_refs(&extent_item, 1);
277         btrfs_set_extent_owner(&extent_item, BTRFS_ROOT_TREE_OBJECTID);
278         memcpy(empty_leaf->items, &item, sizeof(item));
279         memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item),
280                 &extent_item, btrfs_item_size(&item));
281
282         /* item2, give block 17 to the root */
283         btrfs_set_disk_key_objectid(&item.key, first_free);
284         btrfs_set_disk_key_offset(&item.key, leafsize);
285         itemoff = itemoff - sizeof(struct btrfs_extent_item);
286         btrfs_set_item_offset(&item, itemoff);
287         memcpy(empty_leaf->items + 1, &item, sizeof(item));
288         memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item),
289                 &extent_item, btrfs_item_size(&item));
290
291         /* item3, give block 18 to the extent root */
292         btrfs_set_disk_key_objectid(&item.key, first_free + leafsize);
293         btrfs_set_disk_key_offset(&item.key, leafsize);
294         itemoff = itemoff - sizeof(struct btrfs_extent_item);
295         btrfs_set_item_offset(&item, itemoff);
296         memcpy(empty_leaf->items + 2, &item, sizeof(item));
297         memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item),
298                 &extent_item, btrfs_item_size(&item));
299
300         /* item4, give block 19 to the FS root */
301         btrfs_set_disk_key_objectid(&item.key, first_free + leafsize * 2);
302         btrfs_set_disk_key_offset(&item.key, leafsize);
303         itemoff = itemoff - sizeof(struct btrfs_extent_item);
304         btrfs_set_item_offset(&item, itemoff);
305         memcpy(empty_leaf->items + 3, &item, sizeof(item));
306         memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item),
307                 &extent_item, btrfs_item_size(&item));
308         ret = pwrite(fd, empty_leaf, leafsize, first_free + leafsize);
309         if (ret != leafsize)
310                 return -1;
311
312         /* finally create the FS root */
313         btrfs_set_header_bytenr(&empty_leaf->header, first_free + leafsize * 2);
314         btrfs_set_header_nritems(&empty_leaf->header, 0);
315         ret = pwrite(fd, empty_leaf, leafsize, first_free + leafsize * 2);
316         if (ret != leafsize)
317                 return -1;
318         return 0;
319 }
320
321 u64 device_size(int fd, struct stat *st)
322 {
323         u64 size;
324         if (S_ISREG(st->st_mode)) {
325                 return st->st_size;
326         }
327         if (!S_ISBLK(st->st_mode)) {
328                 return 0;
329         }
330         if (ioctl(fd, BLKGETSIZE64, &size) >= 0) {
331                 return size;
332         }
333         return 0;
334 }
335
336 static void print_usage(void)
337 {
338         fprintf(stderr, "usage: mkfs.btrfs [ -l leafsize ] [ -n nodesize] dev [ blocks ]\n");
339         exit(1);
340 }
341
342 int main(int ac, char **av)
343 {
344         char *file;
345         u64 block_count = 0;
346         int fd;
347         struct stat st;
348         int ret;
349         int i;
350         u32 leafsize = 8 * 1024;
351         u32 sectorsize = 4096;
352         u32 nodesize = 8 * 1024;
353         char *buf = malloc(sectorsize);
354         char *realpath_name;
355
356         radix_tree_init();
357
358         while(1) {
359                 int c;
360                 c = getopt(ac, av, "l:n:");
361                 if (c < 0)
362                         break;
363                 switch(c) {
364                         case 'l':
365                                 leafsize = atol(optarg);
366                                 break;
367                         case 'n':
368                                 nodesize = atol(optarg);
369                                 break;
370                         default:
371                                 print_usage();
372                 }
373         }
374         if (leafsize < sectorsize || (leafsize & (sectorsize - 1))) {
375                 fprintf(stderr, "Illegal leafsize %u\n", leafsize);
376                 exit(1);
377         }
378         if (nodesize < sectorsize || (nodesize & (sectorsize - 1))) {
379                 fprintf(stderr, "Illegal nodesize %u\n", nodesize);
380                 exit(1);
381         }
382         ac = ac - optind;
383         if (ac >= 1) {
384                 file = av[optind];
385                 if (ac == 2) {
386                         block_count = atol(av[optind + 1]);
387                         if (!block_count) {
388                                 fprintf(stderr, "error finding block count\n");
389                                 exit(1);
390                         }
391                 }
392         } else {
393                 print_usage();
394         }
395         fd = open(file, O_RDWR);
396         if (fd < 0) {
397                 fprintf(stderr, "unable to open %s\n", file);
398                 exit(1);
399         }
400         ret = fstat(fd, &st);
401         if (ret < 0) {
402                 fprintf(stderr, "unable to stat %s\n", file);
403                 exit(1);
404         }
405         if (block_count == 0) {
406                 block_count = device_size(fd, &st);
407                 if (block_count == 0) {
408                         fprintf(stderr, "unable to find %s size\n", file);
409                         exit(1);
410                 }
411                 block_count /= sectorsize;
412         }
413         if (block_count < 256) {
414                 fprintf(stderr, "device %s is too small\n", file);
415                 exit(1);
416         }
417         block_count = block_count * sectorsize;
418         memset(buf, 0, sectorsize);
419         for(i = 0; i < 64; i++) {
420                 ret = write(fd, buf, sectorsize);
421                 if (ret != sectorsize) {
422                         fprintf(stderr, "unable to zero fill device\n");
423                         exit(1);
424                 }
425         }
426         realpath_name = realpath(file, NULL);
427         ret = mkfs(fd, realpath_name, block_count, nodesize, leafsize,
428                    sectorsize);
429         if (ret) {
430                 fprintf(stderr, "error during mkfs %d\n", ret);
431                 exit(1);
432         }
433         ret = make_root_dir(fd);
434         if (ret) {
435                 fprintf(stderr, "failed to setup the root directory\n");
436                 exit(1);
437         }
438         printf("fs created on %s nodesize %u leafsize %u sectorsize %u bytes %llu\n",
439                file, nodesize, leafsize, sectorsize,
440                (unsigned long long)block_count);
441         return 0;
442 }
443