add defrag ioctl
[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         inode_map.flags = 0;
56         btrfs_set_key_type(&inode_map, BTRFS_INODE_ITEM_KEY);
57         inode_map.offset = 0;
58
59         memset(&inode_item, 0, sizeof(inode_item));
60         btrfs_set_inode_generation(&inode_item, root->fs_info->generation);
61         btrfs_set_inode_size(&inode_item, 6);
62         btrfs_set_inode_nlink(&inode_item, 1);
63         btrfs_set_inode_nblocks(&inode_item, 1);
64         btrfs_set_inode_mode(&inode_item, S_IFDIR | 0555);
65
66         if (root->fs_info->tree_root == root)
67                 btrfs_set_super_root_dir(root->fs_info->disk_super, objectid);
68
69         ret = btrfs_insert_inode(trans, root, objectid, &inode_item);
70         if (ret)
71                 goto error;
72         ret = btrfs_insert_dir_item(trans, root, buf, 1, objectid,
73                                     &inode_map, BTRFS_FT_DIR);
74         if (ret)
75                 goto error;
76         ret = btrfs_insert_dir_item(trans, root, buf, 2, objectid,
77                                     &inode_map, BTRFS_FT_DIR);
78         if (ret)
79                 goto error;
80         btrfs_set_root_dirid(&root->root_item, objectid);
81         ret = 0;
82 error:
83         return ret;
84 }
85
86 static int make_block_groups(struct btrfs_trans_handle *trans,
87                              struct btrfs_root *root)
88 {
89         u64 group_size_blocks;
90         u64 total_blocks;
91         u64 cur_start;
92         int ret;
93         u64 nr = 0;
94         struct btrfs_block_group_cache *cache;
95
96         root = root->fs_info->extent_root;
97         /* first we bootstrap the things into cache */
98         group_size_blocks = BTRFS_BLOCK_GROUP_SIZE / root->blocksize;
99         cache = malloc(sizeof(*cache));
100         cache->key.objectid = 0;
101         cache->key.offset = group_size_blocks;
102         cache->key.flags = 0;
103         btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY);
104         memset(&cache->item, 0, sizeof(cache->item));
105         btrfs_set_block_group_used(&cache->item,
106                            btrfs_super_blocks_used(root->fs_info->disk_super));
107         ret = radix_tree_insert(&root->fs_info->block_group_radix,
108                                 group_size_blocks - 1, (void *)cache);
109         BUG_ON(ret);
110
111         total_blocks = btrfs_super_total_blocks(root->fs_info->disk_super);
112         cur_start = group_size_blocks;
113         while(cur_start < total_blocks) {
114                 cache = malloc(sizeof(*cache));
115                 cache->key.objectid = cur_start;
116                 cache->key.offset = group_size_blocks;
117                 cache->key.flags = 0;
118                 btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY);
119                 memset(&cache->item, 0, sizeof(cache->item));
120                 if (nr % 3)
121                         cache->item.flags |= BTRFS_BLOCK_GROUP_DATA;
122
123                 ret = radix_tree_insert(&root->fs_info->block_group_radix,
124                                         cur_start + group_size_blocks - 1,
125                                         (void *)cache);
126                 BUG_ON(ret);
127                 cur_start += group_size_blocks;
128                 nr++;
129         }
130         /* then insert all the items */
131         cur_start = 0;
132         while(cur_start < total_blocks) {
133                 cache = radix_tree_lookup(&root->fs_info->block_group_radix,
134                                           cur_start + group_size_blocks - 1);
135                 BUG_ON(!cache);
136                 ret = btrfs_insert_block_group(trans, root, &cache->key,
137                                                &cache->item);
138                 BUG_ON(ret);
139                 cur_start += group_size_blocks;
140         }
141         return 0;
142 }
143
144 static int make_root_dir(int fd) {
145         struct btrfs_root *root;
146         struct btrfs_super_block super;
147         struct btrfs_trans_handle *trans;
148         int ret;
149         struct btrfs_key location;
150
151         root = open_ctree_fd(fd, &super);
152
153         if (!root) {
154                 fprintf(stderr, "ctree init failed\n");
155                 return -1;
156         }
157         trans = btrfs_start_transaction(root, 1);
158         ret = make_block_groups(trans, root);
159         ret = __make_root_dir(trans, root->fs_info->tree_root,
160                               BTRFS_ROOT_TREE_DIR_OBJECTID);
161         if (ret)
162                 goto err;
163         ret = __make_root_dir(trans, root, BTRFS_FIRST_FREE_OBJECTID);
164         if (ret)
165                 goto err;
166         memcpy(&location, &root->fs_info->fs_root->root_key, sizeof(location));
167         location.offset = (u64)-1;
168         ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root,
169                         "default", strlen("default"),
170                         btrfs_super_root_dir(root->fs_info->disk_super),
171                         &location, BTRFS_FT_DIR);
172         if (ret)
173                 goto err;
174         btrfs_commit_transaction(trans, root, root->fs_info->disk_super);
175         ret = close_ctree(root, &super);
176 err:
177         return ret;
178 }
179
180 int mkfs(int fd, char *pathname, u64 num_blocks, u32 blocksize)
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 / blocksize;
192
193         btrfs_set_super_generation(&super, 1);
194         btrfs_set_super_blocknr(&super, start_block);
195         btrfs_set_super_root(&super, start_block + 1);
196         strcpy((char *)(&super.magic), BTRFS_MAGIC);
197         btrfs_set_super_blocksize(&super, blocksize);
198         btrfs_set_super_total_blocks(&super, num_blocks);
199         btrfs_set_super_blocks_used(&super, start_block + 4);
200         uuid_generate(super.fsid);
201
202         block = malloc(blocksize);
203         memset(block, 0, blocksize);
204         BUG_ON(sizeof(super) > blocksize);
205         memcpy(block, &super, sizeof(super));
206         ret = pwrite(fd, block, blocksize, BTRFS_SUPER_INFO_OFFSET);
207         BUG_ON(ret != blocksize);
208
209         /* create the tree of root objects */
210         empty_leaf = malloc(blocksize);
211         memset(empty_leaf, 0, blocksize);
212         btrfs_set_header_blocknr(&empty_leaf->header, start_block + 1);
213         btrfs_set_header_nritems(&empty_leaf->header, 2);
214         btrfs_set_header_generation(&empty_leaf->header, 0);
215         btrfs_set_header_owner(&empty_leaf->header, BTRFS_ROOT_TREE_OBJECTID);
216         memcpy(empty_leaf->header.fsid, super.fsid,
217                sizeof(empty_leaf->header.fsid));
218
219         /* create the items for the root tree */
220         inode_item = &root_item.inode;
221         memset(inode_item, 0, sizeof(*inode_item));
222         btrfs_set_inode_generation(inode_item, 1);
223         btrfs_set_inode_size(inode_item, 3);
224         btrfs_set_inode_nlink(inode_item, 1);
225         btrfs_set_inode_nblocks(inode_item, 1);
226         btrfs_set_inode_mode(inode_item, S_IFDIR | 0755);
227
228         // memset(&root_item, 0, sizeof(root_item));
229         btrfs_set_root_dirid(&root_item, 0);
230         btrfs_set_root_refs(&root_item, 1);
231         btrfs_set_disk_key_offset(&item.key, 0);
232         btrfs_set_disk_key_flags(&item.key, 0);
233         btrfs_set_item_size(&item, sizeof(root_item));
234         btrfs_set_disk_key_type(&item.key, BTRFS_ROOT_ITEM_KEY);
235
236         itemoff = __BTRFS_LEAF_DATA_SIZE(blocksize) - sizeof(root_item);
237         btrfs_set_root_blocknr(&root_item, start_block + 2);
238         btrfs_set_item_offset(&item, itemoff);
239         btrfs_set_disk_key_objectid(&item.key, BTRFS_EXTENT_TREE_OBJECTID);
240         memcpy(empty_leaf->items, &item, sizeof(item));
241         memcpy(btrfs_leaf_data(empty_leaf) + itemoff,
242                 &root_item, sizeof(root_item));
243
244         btrfs_set_root_blocknr(&root_item, start_block + 3);
245         itemoff = itemoff - sizeof(root_item);
246         btrfs_set_item_offset(&item, itemoff);
247         btrfs_set_disk_key_objectid(&item.key, BTRFS_FS_TREE_OBJECTID);
248         memcpy(empty_leaf->items + 1, &item, sizeof(item));
249         memcpy(btrfs_leaf_data(empty_leaf) + itemoff,
250                 &root_item, sizeof(root_item));
251         ret = pwrite(fd, empty_leaf, blocksize, (start_block + 1) * blocksize);
252
253         /* create the items for the extent tree */
254         btrfs_set_header_blocknr(&empty_leaf->header, start_block + 2);
255         btrfs_set_header_nritems(&empty_leaf->header, 4);
256
257         /* item1, reserve blocks 0-16 */
258         btrfs_set_disk_key_objectid(&item.key, 0);
259         btrfs_set_disk_key_offset(&item.key, start_block + 1);
260         btrfs_set_disk_key_flags(&item.key, 0);
261         btrfs_set_disk_key_type(&item.key, BTRFS_EXTENT_ITEM_KEY);
262         itemoff = __BTRFS_LEAF_DATA_SIZE(blocksize) -
263                         sizeof(struct btrfs_extent_item);
264         btrfs_set_item_offset(&item, itemoff);
265         btrfs_set_item_size(&item, sizeof(struct btrfs_extent_item));
266         btrfs_set_extent_refs(&extent_item, 1);
267         btrfs_set_extent_owner(&extent_item, BTRFS_ROOT_TREE_OBJECTID);
268         memcpy(empty_leaf->items, &item, sizeof(item));
269         memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item),
270                 &extent_item, btrfs_item_size(&item));
271
272         /* item2, give block 17 to the root */
273         btrfs_set_disk_key_objectid(&item.key, start_block + 1);
274         btrfs_set_disk_key_offset(&item.key, 1);
275         itemoff = itemoff - sizeof(struct btrfs_extent_item);
276         btrfs_set_item_offset(&item, itemoff);
277         memcpy(empty_leaf->items + 1, &item, sizeof(item));
278         memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item),
279                 &extent_item, btrfs_item_size(&item));
280
281         /* item3, give block 18 to the extent root */
282         btrfs_set_disk_key_objectid(&item.key, start_block + 2);
283         btrfs_set_disk_key_offset(&item.key, 1);
284         itemoff = itemoff - sizeof(struct btrfs_extent_item);
285         btrfs_set_item_offset(&item, itemoff);
286         memcpy(empty_leaf->items + 2, &item, sizeof(item));
287         memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item),
288                 &extent_item, btrfs_item_size(&item));
289
290         /* item4, give block 19 to the FS root */
291         btrfs_set_disk_key_objectid(&item.key, start_block + 3);
292         btrfs_set_disk_key_offset(&item.key, 1);
293         itemoff = itemoff - sizeof(struct btrfs_extent_item);
294         btrfs_set_item_offset(&item, itemoff);
295         memcpy(empty_leaf->items + 3, &item, sizeof(item));
296         memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item),
297                 &extent_item, btrfs_item_size(&item));
298         ret = pwrite(fd, empty_leaf, blocksize, (start_block + 2) * blocksize);
299         if (ret != blocksize)
300                 return -1;
301
302         /* finally create the FS root */
303         btrfs_set_header_blocknr(&empty_leaf->header, start_block + 3);
304         btrfs_set_header_nritems(&empty_leaf->header, 0);
305         ret = pwrite(fd, empty_leaf, blocksize, (start_block + 3) * blocksize);
306         if (ret != blocksize)
307                 return -1;
308         return 0;
309 }
310
311 u64 device_size(int fd, struct stat *st)
312 {
313         u64 size;
314         if (S_ISREG(st->st_mode)) {
315                 return st->st_size;
316         }
317         if (!S_ISBLK(st->st_mode)) {
318                 return 0;
319         }
320         if (ioctl(fd, BLKGETSIZE64, &size) >= 0) {
321                 return size;
322         }
323         return 0; }
324
325 int main(int ac, char **av)
326 {
327         char *file;
328         u64 block_count = 0;
329         int fd;
330         struct stat st;
331         int ret;
332         int i;
333         char *buf = malloc(4096);
334         char *realpath_name;
335
336         radix_tree_init();
337
338         if (ac >= 2) {
339                 file = av[1];
340                 if (ac == 3) {
341                         block_count = atoi(av[2]);
342                         if (!block_count) {
343                                 fprintf(stderr, "error finding block count\n");
344                                 exit(1);
345                         }
346                 }
347         } else {
348                 fprintf(stderr, "usage: mkfs.btrfs file [block count]\n");
349                 exit(1);
350         }
351         fd = open(file, O_RDWR);
352         if (fd < 0) {
353                 fprintf(stderr, "unable to open %s\n", file);
354                 exit(1);
355         }
356         ret = fstat(fd, &st);
357         if (ret < 0) {
358                 fprintf(stderr, "unable to stat %s\n", file);
359                 exit(1);
360         }
361         if (block_count == 0) {
362                 block_count = device_size(fd, &st);
363                 if (block_count == 0) {
364                         fprintf(stderr, "unable to find %s size\n", file);
365                         exit(1);
366                 }
367                 block_count /= 4096;
368         }
369         if (block_count < 256) {
370                 fprintf(stderr, "device %s is too small\n", file);
371                 exit(1);
372         }
373         memset(buf, 0, 4096);
374         for(i = 0; i < 64; i++) {
375                 ret = write(fd, buf, 4096);
376                 if (ret != 4096) {
377                         fprintf(stderr, "unable to zero fill device\n");
378                         exit(1);
379                 }
380         }
381         realpath_name = realpath(file, NULL);
382         ret = mkfs(fd, realpath_name, block_count, 4096);
383         if (ret) {
384                 fprintf(stderr, "error during mkfs %d\n", ret);
385                 exit(1);
386         }
387         ret = make_root_dir(fd);
388         if (ret) {
389                 fprintf(stderr, "failed to setup the root directory\n");
390                 exit(1);
391         }
392         printf("fs created on %s blocksize %d blocks %llu\n",
393                file, 4096, (unsigned long long)block_count);
394         return 0;
395 }
396