Btrfs-progs: Update man page for mixed data+metadata option.
[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 #define _GNU_SOURCE
21
22 #ifndef __CHECKER__
23 #include <sys/ioctl.h>
24 #include <sys/mount.h>
25 #include "ioctl.h"
26 #endif
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <getopt.h>
35 #include <uuid/uuid.h>
36 #include <linux/fs.h>
37 #include <ctype.h>
38 #include "kerncompat.h"
39 #include "ctree.h"
40 #include "disk-io.h"
41 #include "volumes.h"
42 #include "transaction.h"
43 #include "utils.h"
44 #include "version.h"
45
46 static u64 parse_size(char *s)
47 {
48         int len = strlen(s);
49         char c;
50         u64 mult = 1;
51
52         if (!isdigit(s[len - 1])) {
53                 c = tolower(s[len - 1]);
54                 switch (c) {
55                 case 'g':
56                         mult *= 1024;
57                 case 'm':
58                         mult *= 1024;
59                 case 'k':
60                         mult *= 1024;
61                 case 'b':
62                         break;
63                 default:
64                         fprintf(stderr, "Unknown size descriptor %c\n", c);
65                         exit(1);
66                 }
67                 s[len - 1] = '\0';
68         }
69         return atol(s) * mult;
70 }
71
72 static int make_root_dir(struct btrfs_root *root, int mixed)
73 {
74         struct btrfs_trans_handle *trans;
75         struct btrfs_key location;
76         u64 bytes_used;
77         u64 chunk_start = 0;
78         u64 chunk_size = 0;
79         int ret;
80
81         trans = btrfs_start_transaction(root, 1);
82         bytes_used = btrfs_super_bytes_used(&root->fs_info->super_copy);
83
84         root->fs_info->system_allocs = 1;
85         ret = btrfs_make_block_group(trans, root, bytes_used,
86                                      BTRFS_BLOCK_GROUP_SYSTEM,
87                                      BTRFS_FIRST_CHUNK_TREE_OBJECTID,
88                                      0, BTRFS_MKFS_SYSTEM_GROUP_SIZE);
89         BUG_ON(ret);
90
91         if (mixed) {
92                 ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root,
93                                         &chunk_start, &chunk_size,
94                                         BTRFS_BLOCK_GROUP_METADATA |
95                                         BTRFS_BLOCK_GROUP_DATA);
96                 BUG_ON(ret);
97                 ret = btrfs_make_block_group(trans, root, 0,
98                                              BTRFS_BLOCK_GROUP_METADATA |
99                                              BTRFS_BLOCK_GROUP_DATA,
100                                              BTRFS_FIRST_CHUNK_TREE_OBJECTID,
101                                              chunk_start, chunk_size);
102                 BUG_ON(ret);
103                 printf("Created a data/metadata chunk of size %llu\n", chunk_size);
104         } else {
105                 ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root,
106                                         &chunk_start, &chunk_size,
107                                         BTRFS_BLOCK_GROUP_METADATA);
108                 BUG_ON(ret);
109                 ret = btrfs_make_block_group(trans, root, 0,
110                                              BTRFS_BLOCK_GROUP_METADATA,
111                                              BTRFS_FIRST_CHUNK_TREE_OBJECTID,
112                                              chunk_start, chunk_size);
113                 BUG_ON(ret);
114         }
115
116         root->fs_info->system_allocs = 0;
117         btrfs_commit_transaction(trans, root);
118         trans = btrfs_start_transaction(root, 1);
119         BUG_ON(!trans);
120
121         if (!mixed) {
122                 ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root,
123                                         &chunk_start, &chunk_size,
124                                         BTRFS_BLOCK_GROUP_DATA);
125                 BUG_ON(ret);
126                 ret = btrfs_make_block_group(trans, root, 0,
127                                              BTRFS_BLOCK_GROUP_DATA,
128                                              BTRFS_FIRST_CHUNK_TREE_OBJECTID,
129                                              chunk_start, chunk_size);
130                 BUG_ON(ret);
131         }
132
133         ret = btrfs_make_root_dir(trans, root->fs_info->tree_root,
134                               BTRFS_ROOT_TREE_DIR_OBJECTID);
135         if (ret)
136                 goto err;
137         ret = btrfs_make_root_dir(trans, root, BTRFS_FIRST_FREE_OBJECTID);
138         if (ret)
139                 goto err;
140         memcpy(&location, &root->fs_info->fs_root->root_key, sizeof(location));
141         location.offset = (u64)-1;
142         ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root,
143                         "default", 7,
144                         btrfs_super_root_dir(&root->fs_info->super_copy),
145                         &location, BTRFS_FT_DIR, 0);
146         if (ret)
147                 goto err;
148
149         ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root,
150                              "default", 7, location.objectid,
151                              BTRFS_ROOT_TREE_DIR_OBJECTID, 0);
152         if (ret)
153                 goto err;
154
155         btrfs_commit_transaction(trans, root);
156 err:
157         return ret;
158 }
159
160 static int recow_roots(struct btrfs_trans_handle *trans,
161                        struct btrfs_root *root)
162 {
163         int ret;
164         struct extent_buffer *tmp;
165         struct btrfs_fs_info *info = root->fs_info;
166
167         ret = __btrfs_cow_block(trans, info->fs_root, info->fs_root->node,
168                                 NULL, 0, &tmp, 0, 0);
169         BUG_ON(ret);
170         free_extent_buffer(tmp);
171
172         ret = __btrfs_cow_block(trans, info->tree_root, info->tree_root->node,
173                                 NULL, 0, &tmp, 0, 0);
174         BUG_ON(ret);
175         free_extent_buffer(tmp);
176
177         ret = __btrfs_cow_block(trans, info->extent_root,
178                                 info->extent_root->node, NULL, 0, &tmp, 0, 0);
179         BUG_ON(ret);
180         free_extent_buffer(tmp);
181
182         ret = __btrfs_cow_block(trans, info->chunk_root, info->chunk_root->node,
183                                 NULL, 0, &tmp, 0, 0);
184         BUG_ON(ret);
185         free_extent_buffer(tmp);
186
187
188         ret = __btrfs_cow_block(trans, info->dev_root, info->dev_root->node,
189                                 NULL, 0, &tmp, 0, 0);
190         BUG_ON(ret);
191         free_extent_buffer(tmp);
192
193         ret = __btrfs_cow_block(trans, info->csum_root, info->csum_root->node,
194                                 NULL, 0, &tmp, 0, 0);
195         BUG_ON(ret);
196         free_extent_buffer(tmp);
197
198         return 0;
199 }
200
201 static int create_one_raid_group(struct btrfs_trans_handle *trans,
202                               struct btrfs_root *root, u64 type)
203 {
204         u64 chunk_start;
205         u64 chunk_size;
206         int ret;
207
208         ret = btrfs_alloc_chunk(trans, root->fs_info->extent_root,
209                                 &chunk_start, &chunk_size, type);
210         BUG_ON(ret);
211         ret = btrfs_make_block_group(trans, root->fs_info->extent_root, 0,
212                                      type, BTRFS_FIRST_CHUNK_TREE_OBJECTID,
213                                      chunk_start, chunk_size);
214         BUG_ON(ret);
215         return ret;
216 }
217
218 static int create_raid_groups(struct btrfs_trans_handle *trans,
219                               struct btrfs_root *root, u64 data_profile,
220                               u64 metadata_profile, int mixed)
221 {
222         u64 num_devices = btrfs_super_num_devices(&root->fs_info->super_copy);
223         u64 allowed;
224         int ret;
225
226         if (num_devices == 1)
227                 allowed = BTRFS_BLOCK_GROUP_DUP;
228         else if (num_devices >= 4) {
229                 allowed = BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
230                         BTRFS_BLOCK_GROUP_RAID10;
231         } else
232                 allowed = BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1;
233
234         if (allowed & metadata_profile) {
235                 u64 meta_flags = BTRFS_BLOCK_GROUP_METADATA;
236
237                 ret = create_one_raid_group(trans, root,
238                                             BTRFS_BLOCK_GROUP_SYSTEM |
239                                             (allowed & metadata_profile));
240                 BUG_ON(ret);
241
242                 if (mixed)
243                         meta_flags |= BTRFS_BLOCK_GROUP_DATA;
244
245                 ret = create_one_raid_group(trans, root, meta_flags |
246                                             (allowed & metadata_profile));
247                 BUG_ON(ret);
248
249                 ret = recow_roots(trans, root);
250                 BUG_ON(ret);
251         }
252         if (!mixed && num_devices > 1 && (allowed & data_profile)) {
253                 ret = create_one_raid_group(trans, root,
254                                             BTRFS_BLOCK_GROUP_DATA |
255                                             (allowed & data_profile));
256                 BUG_ON(ret);
257         }
258         return 0;
259 }
260
261 static int create_data_reloc_tree(struct btrfs_trans_handle *trans,
262                                   struct btrfs_root *root)
263 {
264         struct btrfs_key location;
265         struct btrfs_root_item root_item;
266         struct extent_buffer *tmp;
267         u64 objectid = BTRFS_DATA_RELOC_TREE_OBJECTID;
268         int ret;
269
270         ret = btrfs_copy_root(trans, root, root->node, &tmp, objectid);
271         BUG_ON(ret);
272
273         memcpy(&root_item, &root->root_item, sizeof(root_item));
274         btrfs_set_root_bytenr(&root_item, tmp->start);
275         btrfs_set_root_level(&root_item, btrfs_header_level(tmp));
276         btrfs_set_root_generation(&root_item, trans->transid);
277         free_extent_buffer(tmp);
278
279         location.objectid = objectid;
280         location.type = BTRFS_ROOT_ITEM_KEY;
281         location.offset = 0;
282         ret = btrfs_insert_root(trans, root->fs_info->tree_root,
283                                 &location, &root_item);
284         BUG_ON(ret);
285         return 0;
286 }
287
288 static void print_usage(void)
289 {
290         fprintf(stderr, "usage: mkfs.btrfs [options] dev [ dev ... ]\n");
291         fprintf(stderr, "options:\n");
292         fprintf(stderr, "\t -A --alloc-start the offset to start the FS\n");
293         fprintf(stderr, "\t -b --byte-count total number of bytes in the FS\n");
294         fprintf(stderr, "\t -d --data data profile, raid0, raid1, raid10 or single\n");
295         fprintf(stderr, "\t -l --leafsize size of btree leaves\n");
296         fprintf(stderr, "\t -L --label set a label\n");
297         fprintf(stderr, "\t -m --metadata metadata profile, values like data profile\n");
298         fprintf(stderr, "\t -M --mixed mix metadata and data together\n");
299         fprintf(stderr, "\t -n --nodesize size of btree nodes\n");
300         fprintf(stderr, "\t -s --sectorsize min block allocation\n");
301         fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION);
302         exit(1);
303 }
304
305 static void print_version(void)
306 {
307         fprintf(stderr, "mkfs.btrfs, part of %s\n", BTRFS_BUILD_VERSION);
308         exit(0);
309 }
310
311 static u64 parse_profile(char *s)
312 {
313         if (strcmp(s, "raid0") == 0) {
314                 return BTRFS_BLOCK_GROUP_RAID0;
315         } else if (strcmp(s, "raid1") == 0) {
316                 return BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP;
317         } else if (strcmp(s, "raid10") == 0) {
318                 return BTRFS_BLOCK_GROUP_RAID10 | BTRFS_BLOCK_GROUP_DUP;
319         } else if (strcmp(s, "single") == 0) {
320                 return 0;
321         } else {
322                 fprintf(stderr, "Unknown option %s\n", s);
323                 print_usage();
324         }
325         return 0;
326 }
327
328 static char *parse_label(char *input)
329 {
330         int i;
331         int len = strlen(input);
332
333         if (len > BTRFS_LABEL_SIZE) {
334                 fprintf(stderr, "Label %s is too long (max %d)\n", input,
335                         BTRFS_LABEL_SIZE);
336                 exit(1);
337         }
338         for (i = 0; i < len; i++) {
339                 if (input[i] == '/' || input[i] == '\\') {
340                         fprintf(stderr, "invalid label %s\n", input);
341                         exit(1);
342                 }
343         }
344         return strdup(input);
345 }
346
347 static struct option long_options[] = {
348         { "alloc-start", 1, NULL, 'A'},
349         { "byte-count", 1, NULL, 'b' },
350         { "leafsize", 1, NULL, 'l' },
351         { "label", 1, NULL, 'L'},
352         { "metadata", 1, NULL, 'm' },
353         { "mixed", 0, NULL, 'M' },
354         { "nodesize", 1, NULL, 'n' },
355         { "sectorsize", 1, NULL, 's' },
356         { "data", 1, NULL, 'd' },
357         { "version", 0, NULL, 'V' },
358         { 0, 0, 0, 0}
359 };
360
361 int main(int ac, char **av)
362 {
363         char *file;
364         struct btrfs_root *root;
365         struct btrfs_trans_handle *trans;
366         char *label = NULL;
367         char *first_file;
368         u64 block_count = 0;
369         u64 dev_block_count = 0;
370         u64 blocks[7];
371         u64 alloc_start = 0;
372         u64 metadata_profile = BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP;
373         u64 data_profile = BTRFS_BLOCK_GROUP_RAID0;
374         u32 leafsize = getpagesize();
375         u32 sectorsize = 4096;
376         u32 nodesize = leafsize;
377         u32 stripesize = 4096;
378         int zero_end = 1;
379         int option_index = 0;
380         int fd;
381         int first_fd;
382         int ret;
383         int i;
384         int mixed = 0;
385         int data_profile_opt = 0;
386         int metadata_profile_opt = 0;
387
388         while(1) {
389                 int c;
390                 c = getopt_long(ac, av, "A:b:l:n:s:m:d:L:VM", long_options,
391                                 &option_index);
392                 if (c < 0)
393                         break;
394                 switch(c) {
395                         case 'A':
396                                 alloc_start = parse_size(optarg);
397                                 break;
398                         case 'd':
399                                 data_profile = parse_profile(optarg);
400                                 data_profile_opt = 1;
401                                 break;
402                         case 'l':
403                                 leafsize = parse_size(optarg);
404                                 break;
405                         case 'L':
406                                 label = parse_label(optarg);
407                                 break;
408                         case 'm':
409                                 metadata_profile = parse_profile(optarg);
410                                 metadata_profile_opt = 1;
411                                 break;
412                         case 'M':
413                                 mixed = 1;
414                                 break;
415                         case 'n':
416                                 nodesize = parse_size(optarg);
417                                 break;
418                         case 's':
419                                 sectorsize = parse_size(optarg);
420                                 break;
421                         case 'b':
422                                 block_count = parse_size(optarg);
423                                 if (block_count <= 1024*1024*1024) {
424                                         printf("SMALL VOLUME: forcing mixed "
425                                                "metadata/data groups\n");
426                                         mixed = 1;
427                                 }
428                                 zero_end = 0;
429                                 break;
430                         case 'V':
431                                 print_version();
432                                 break;
433                         default:
434                                 print_usage();
435                 }
436         }
437         sectorsize = max(sectorsize, (u32)getpagesize());
438         if (leafsize < sectorsize || (leafsize & (sectorsize - 1))) {
439                 fprintf(stderr, "Illegal leafsize %u\n", leafsize);
440                 exit(1);
441         }
442         if (nodesize < sectorsize || (nodesize & (sectorsize - 1))) {
443                 fprintf(stderr, "Illegal nodesize %u\n", nodesize);
444                 exit(1);
445         }
446         ac = ac - optind;
447         if (ac == 0)
448                 print_usage();
449
450         printf("\nWARNING! - %s IS EXPERIMENTAL\n", BTRFS_BUILD_VERSION);
451         printf("WARNING! - see http://btrfs.wiki.kernel.org before using\n\n");
452
453         file = av[optind++];
454         ret = check_mounted(file);
455         if (ret < 0) {
456                 fprintf(stderr, "error checking %s mount status\n", file);
457                 exit(1);
458         }
459         if (ret == 1) {
460                 fprintf(stderr, "%s is mounted\n", file);
461                 exit(1);
462         }
463         ac--;
464         fd = open(file, O_RDWR);
465         if (fd < 0) {
466                 fprintf(stderr, "unable to open %s\n", file);
467                 exit(1);
468         }
469         first_fd = fd;
470         first_file = file;
471         ret = btrfs_prepare_device(fd, file, zero_end, &dev_block_count,
472                                    &mixed);
473         if (block_count == 0)
474                 block_count = dev_block_count;
475         if (mixed) {
476                 if (!metadata_profile_opt)
477                         metadata_profile = 0;
478                 if (!data_profile_opt)
479                         data_profile = 0;
480
481                 if (metadata_profile != data_profile) {
482                         fprintf(stderr, "With mixed block groups data and metadata "
483                                 "profiles must be the same\n");
484                         exit(1);
485                 }
486         }
487
488         blocks[0] = BTRFS_SUPER_INFO_OFFSET;
489         for (i = 1; i < 7; i++) {
490                 blocks[i] = BTRFS_SUPER_INFO_OFFSET + 1024 * 1024 +
491                         leafsize * i;
492         }
493
494         ret = make_btrfs(fd, file, label, blocks, block_count,
495                          nodesize, leafsize,
496                          sectorsize, stripesize);
497         if (ret) {
498                 fprintf(stderr, "error during mkfs %d\n", ret);
499                 exit(1);
500         }
501         root = open_ctree(file, 0, O_RDWR);
502         root->fs_info->alloc_start = alloc_start;
503
504         ret = make_root_dir(root, mixed);
505         if (ret) {
506                 fprintf(stderr, "failed to setup the root directory\n");
507                 exit(1);
508         }
509
510         trans = btrfs_start_transaction(root, 1);
511
512         if (ac == 0)
513                 goto raid_groups;
514
515         btrfs_register_one_device(file);
516         if (!root) {
517                 fprintf(stderr, "ctree init failed\n");
518                 return -1;
519         }
520
521         zero_end = 1;
522         while(ac-- > 0) {
523                 int old_mixed = mixed;
524
525                 file = av[optind++];
526                 ret = check_mounted(file);
527                 if (ret < 0) {
528                         fprintf(stderr, "error checking %s mount status\n",
529                                 file);
530                         exit(1);
531                 }
532                 if (ret == 1) {
533                         fprintf(stderr, "%s is mounted\n", file);
534                         exit(1);
535                 }
536                 fd = open(file, O_RDWR);
537                 if (fd < 0) {
538                         fprintf(stderr, "unable to open %s\n", file);
539                         exit(1);
540                 }
541                 ret = btrfs_device_already_in_root(root, fd,
542                                                    BTRFS_SUPER_INFO_OFFSET);
543                 if (ret) {
544                         fprintf(stderr, "skipping duplicate device %s in FS\n",
545                                 file);
546                         close(fd);
547                         continue;
548                 }
549                 ret = btrfs_prepare_device(fd, file, zero_end,
550                                            &dev_block_count, &mixed);
551                 mixed = old_mixed;
552                 BUG_ON(ret);
553
554                 ret = btrfs_add_to_fsid(trans, root, fd, file, dev_block_count,
555                                         sectorsize, sectorsize, sectorsize);
556                 BUG_ON(ret);
557                 btrfs_register_one_device(file);
558         }
559
560 raid_groups:
561         ret = create_raid_groups(trans, root, data_profile,
562                                  metadata_profile, mixed);
563         BUG_ON(ret);
564
565         ret = create_data_reloc_tree(trans, root);
566         BUG_ON(ret);
567
568         if (mixed) {
569                 struct btrfs_super_block *super = &root->fs_info->super_copy;
570                 u64 flags = btrfs_super_incompat_flags(super);
571
572                 flags |= BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS;
573                 btrfs_set_super_incompat_flags(super, flags);
574         }
575
576         printf("fs created label %s on %s\n\tnodesize %u leafsize %u "
577             "sectorsize %u size %s\n",
578             label, first_file, nodesize, leafsize, sectorsize,
579             pretty_sizes(btrfs_super_total_bytes(&root->fs_info->super_copy)));
580
581         printf("%s\n", BTRFS_BUILD_VERSION);
582         btrfs_commit_transaction(trans, root);
583         ret = close_ctree(root);
584         BUG_ON(ret);
585
586         free(label);
587         return 0;
588 }
589