/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #define _XOPEN_SOURCE 500 #ifndef __CHECKER__ #include #include #endif #include #include #include #include #include #include #include #include #include #include "kerncompat.h" #include "ctree.h" #include "disk-io.h" #include "transaction.h" #include "utils.h" #ifdef __CHECKER__ #define BLKGETSIZE64 0 static inline int ioctl(int fd, int define, u64 *size) { return 0; } #endif static u64 parse_size(char *s) { int len = strlen(s); char c; u64 mult = 1; if (!isdigit(s[len - 1])) { c = tolower(s[len - 1]); switch (c) { case 'g': mult *= 1024; case 'm': mult *= 1024; case 'k': mult *= 1024; case 'b': break; default: fprintf(stderr, "Unknown size descriptor %c\n", c); exit(1); } s[len - 1] = '\0'; } return atol(s) * mult; } static int make_root_dir(int fd) { struct btrfs_root *root; struct btrfs_trans_handle *trans; struct btrfs_key location; int ret; root = open_ctree_fd(fd, 0); if (!root) { fprintf(stderr, "ctree init failed\n"); return -1; } trans = btrfs_start_transaction(root, 1); ret = btrfs_make_block_groups(trans, root); ret = btrfs_make_root_dir(trans, root->fs_info->tree_root, BTRFS_ROOT_TREE_DIR_OBJECTID); if (ret) goto err; ret = btrfs_make_root_dir(trans, root, BTRFS_FIRST_FREE_OBJECTID); if (ret) goto err; memcpy(&location, &root->fs_info->fs_root->root_key, sizeof(location)); location.offset = (u64)-1; ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root, "default", 7, btrfs_super_root_dir(&root->fs_info->super_copy), &location, BTRFS_FT_DIR); if (ret) goto err; ret = btrfs_insert_inode_ref(trans, root->fs_info->tree_root, "default", 7, location.objectid, BTRFS_ROOT_TREE_DIR_OBJECTID); if (ret) goto err; btrfs_commit_transaction(trans, root); ret = close_ctree(root); err: return ret; } u64 device_size(int fd, struct stat *st) { u64 size; if (S_ISREG(st->st_mode)) { return st->st_size; } if (!S_ISBLK(st->st_mode)) { return 0; } if (ioctl(fd, BLKGETSIZE64, &size) >= 0) { return size; } return 0; } static void print_usage(void) { fprintf(stderr, "usage: mkfs.btrfs [ -l leafsize ] [ -n nodesize] dev [ blocks ]\n"); exit(1); } int main(int ac, char **av) { char *file; u64 block_count = 0; int fd; struct stat st; int ret; int i; u32 leafsize = 16 * 1024; u32 sectorsize = 4096; u32 nodesize = 16 * 1024; u32 stripesize = 4096; u64 blocks[4]; char *buf = malloc(sectorsize); while(1) { int c; c = getopt(ac, av, "l:n:s:"); if (c < 0) break; switch(c) { case 'l': leafsize = parse_size(optarg); break; case 'n': nodesize = parse_size(optarg); break; case 's': stripesize = parse_size(optarg); break; default: print_usage(); } } if (leafsize < sectorsize || (leafsize & (sectorsize - 1))) { fprintf(stderr, "Illegal leafsize %u\n", leafsize); exit(1); } if (nodesize < sectorsize || (nodesize & (sectorsize - 1))) { fprintf(stderr, "Illegal nodesize %u\n", nodesize); exit(1); } ac = ac - optind; if (ac >= 1) { file = av[optind]; if (ac == 2) { block_count = parse_size(av[optind + 1]); if (!block_count) { fprintf(stderr, "error finding block count\n"); exit(1); } } } else { print_usage(); } fd = open(file, O_RDWR); if (fd < 0) { fprintf(stderr, "unable to open %s\n", file); exit(1); } ret = fstat(fd, &st); if (ret < 0) { fprintf(stderr, "unable to stat %s\n", file); exit(1); } if (block_count == 0) { block_count = device_size(fd, &st); if (block_count == 0) { fprintf(stderr, "unable to find %s size\n", file); exit(1); } } block_count /= sectorsize; block_count *= sectorsize; if (block_count < 256 * 1024 * 1024) { fprintf(stderr, "device %s is too small\n", file); exit(1); } memset(buf, 0, sectorsize); for(i = 0; i < 64; i++) { ret = write(fd, buf, sectorsize); if (ret != sectorsize) { fprintf(stderr, "unable to zero fill device\n"); exit(1); } } for (i = 0; i < 4; i++) blocks[i] = BTRFS_SUPER_INFO_OFFSET + leafsize * i; ret = make_btrfs(fd, blocks, block_count, nodesize, leafsize, sectorsize, stripesize); if (ret) { fprintf(stderr, "error during mkfs %d\n", ret); exit(1); } ret = make_root_dir(fd); if (ret) { fprintf(stderr, "failed to setup the root directory\n"); exit(1); } printf("fs created on %s nodesize %u leafsize %u sectorsize %u bytes %llu\n", file, nodesize, leafsize, sectorsize, (unsigned long long)block_count); return 0; }