diff --git a/ctree.h b/ctree.h index 1a4d1d6f..c9361d83 100644 --- a/ctree.h +++ b/ctree.h @@ -75,6 +75,7 @@ struct btrfs_super_block { __le64 root; __le64 total_blocks; __le64 blocks_used; + __le64 root_dir_objectid; } __attribute__ ((__packed__)); /* @@ -693,6 +694,17 @@ static inline void btrfs_set_super_blocksize(struct btrfs_super_block *s, s->blocksize = cpu_to_le32(val); } +static inline u64 btrfs_super_root_dir(struct btrfs_super_block *s) +{ + return le64_to_cpu(s->root_dir_objectid); +} + +static inline void btrfs_set_super_root_dir(struct btrfs_super_block *s, u64 + val) +{ + s->root_dir_objectid = cpu_to_le64(val); +} + static inline u8 *btrfs_leaf_data(struct btrfs_leaf *l) { return (u8 *)l->items; diff --git a/dir-item.c b/dir-item.c index 949c4e52..ec3e488a 100644 --- a/dir-item.c +++ b/dir-item.c @@ -21,7 +21,12 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root key.objectid = dir; key.flags = 0; btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); - ret = btrfs_name_hash(name, name_len, &key.offset); + if (name_len == 1 && *name == '.') + key.offset = 1; + else if (name_len == 2 && name[0] == '.' && name[1] == '.') + key.offset = 2; + else + ret = btrfs_name_hash(name, name_len, &key.offset); BUG_ON(ret); btrfs_init_path(&path); data_size = sizeof(*dir_item) + name_len; diff --git a/disk-io.c b/disk-io.c index 0322c551..05637f9f 100644 --- a/disk-io.c +++ b/disk-io.c @@ -266,20 +266,25 @@ static int find_and_setup_root(struct btrfs_super_block *super, } struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *super) +{ + int fp; + + fp = open(filename, O_CREAT | O_RDWR, 0600); + if (fp < 0) { + return NULL; + } + return open_ctree_fd(fp, super); +} + +struct btrfs_root *open_ctree_fd(int fp, struct btrfs_super_block *super) { struct btrfs_root *root = malloc(sizeof(struct btrfs_root)); struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root)); struct btrfs_root *tree_root = malloc(sizeof(struct btrfs_root)); struct btrfs_root *inode_root = malloc(sizeof(struct btrfs_root)); struct btrfs_fs_info *fs_info = malloc(sizeof(*fs_info)); - int fp; int ret; - fp = open(filename, O_CREAT | O_RDWR, 0600); - if (fp < 0) { - free(root); - return NULL; - } INIT_RADIX_TREE(&fs_info->cache_radix, GFP_KERNEL); INIT_RADIX_TREE(&fs_info->pinned_radix, GFP_KERNEL); INIT_LIST_HEAD(&fs_info->trans); diff --git a/disk-io.h b/disk-io.h index 24a9e77c..d888cf5c 100644 --- a/disk-io.h +++ b/disk-io.h @@ -24,6 +24,7 @@ int clean_tree_block(struct btrfs_trans_handle *trans, int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_super_block *s); struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *s); +struct btrfs_root *open_ctree_fd(int fp, struct btrfs_super_block *super); int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s); void btrfs_block_release(struct btrfs_root *root, struct btrfs_buffer *buf); int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root *root, diff --git a/mkfs.c b/mkfs.c index f7efc8a5..f6a6b770 100644 --- a/mkfs.c +++ b/mkfs.c @@ -13,17 +13,73 @@ #include "radix-tree.h" #include "ctree.h" #include "disk-io.h" +#include "transaction.h" #ifdef __CHECKER__ #define BLKGETSIZE64 0 static inline int ioctl(int fd, int define, u64 *size) { return 0; } #endif -#if 0 -#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64) -# define BLKGETSIZE64 _IOR(0x12, 114, __u64) -#endif -#endif +static int make_root_dir(int fd) { + struct btrfs_root *root; + struct btrfs_super_block super; + int ret; + char buf[8]; + u64 objectid; + struct btrfs_key inode_map; + struct btrfs_inode_item inode_item; + struct btrfs_trans_handle *trans; + + root = open_ctree_fd(fd, &super); + + if (!root) { + fprintf(stderr, "ctree init failed\n"); + return -1; + } + + buf[0] = '.'; + buf[1] = '.'; + + trans = btrfs_start_transaction(root, 1); + ret = btrfs_find_free_objectid(trans, root, 1, &objectid); + if (ret) + goto error; + + inode_map.objectid = objectid; + inode_map.flags = 0; + inode_map.offset = 0; + + ret = btrfs_insert_inode_map(trans, root, objectid, &inode_map); + if (ret) + goto error; + + memset(&inode_item, 0, sizeof(inode_item)); + btrfs_set_inode_generation(&inode_item, root->fs_info->generation); + btrfs_set_inode_size(&inode_item, 3); + btrfs_set_inode_nlink(&inode_item, 1); + btrfs_set_inode_nblocks(&inode_item, 1); + btrfs_set_inode_mode(&inode_item, S_IFDIR | 0711); + + btrfs_set_super_root_dir(&super, objectid); + + ret = btrfs_insert_inode(trans, root, objectid, &inode_item); + if (ret) + goto error; + ret = btrfs_insert_dir_item(trans, root, buf, 1, objectid, + objectid, 1); + if (ret) + goto error; + ret = btrfs_insert_dir_item(trans, root, buf, 2, objectid, + objectid, 1); + if (ret) + goto error; + ret = btrfs_commit_transaction(trans, root, &super); + if (ret) + goto error; + ret = close_ctree(root, &super); +error: + return ret; +} int mkfs(int fd, u64 num_blocks, u32 blocksize) { @@ -200,6 +256,9 @@ int main(int ac, char **av) int ret; int i; char *buf = malloc(4096); + + radix_tree_init(); + if (ac >= 2) { file = av[1]; if (ac == 3) { @@ -248,6 +307,11 @@ int main(int ac, char **av) 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 blocksize %d blocks %Lu\n", file, 4096, block_count); return 0; diff --git a/print-tree.c b/print-tree.c index f53b99da..caa07f5a 100644 --- a/print-tree.c +++ b/print-tree.c @@ -34,9 +34,10 @@ void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l) switch (type) { case BTRFS_INODE_ITEM_KEY: ii = btrfs_item_ptr(l, i, struct btrfs_inode_item); - printf("\t\tinode generation %Lu size %Lu\n", + printf("\t\tinode generation %Lu size %Lu mode %o\n", btrfs_inode_generation(ii), - btrfs_inode_size(ii)); + btrfs_inode_size(ii), + btrfs_inode_mode(ii)); break; case BTRFS_DIR_ITEM_KEY: di = btrfs_item_ptr(l, i, struct btrfs_dir_item);