Loading fs/btrfs/Makefile +2 −1 Original line number Diff line number Diff line Loading @@ -3,7 +3,8 @@ CFLAGS = -g -Wall -Werror headers = radix-tree.h ctree.h disk-io.h kerncompat.h print-tree.h list.h \ transaction.h objects = ctree.o disk-io.o radix-tree.o mkfs.o extent-tree.o print-tree.o \ root-tree.o dir-item.o hash.o file-item.o inode-item.o root-tree.o dir-item.o hash.o file-item.o inode-item.o \ inode-map.o \ # if you don't have sparse installed, use ls instead CHECKFLAGS=-D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \ Loading fs/btrfs/ctree.h +115 −14 Original line number Diff line number Diff line Loading @@ -10,7 +10,8 @@ struct btrfs_trans_handle; #define BTRFS_ROOT_TREE_OBJECTID 1 #define BTRFS_EXTENT_TREE_OBJECTID 2 #define BTRFS_FS_TREE_OBJECTID 3 #define BTRFS_INODE_MAP_OBJECTID 3 #define BTRFS_FS_TREE_OBJECTID 4 /* * the key defines the order in the tree, and so it also defines (optimal) Loading Loading @@ -178,31 +179,65 @@ struct btrfs_root_item { __le64 block_limit; __le64 blocks_used; __le32 refs; }; } __attribute__ ((__packed__)); struct btrfs_file_extent_item { /* * in ram representation of the tree. extent_root is used for all allocations * and for the extent tree extent_root root. current_insert is used * only for the extent tree. * disk space consumed by the extent, checksum blocks are included * in these numbers */ struct btrfs_root { struct btrfs_buffer *node; struct btrfs_buffer *commit_root; __le64 disk_blocknr; __le64 disk_num_blocks; /* * the logical offset in file bytes (no csums) * this extent record is for. This allows a file extent to point * into the middle of an existing extent on disk, sharing it * between two snapshots (useful if some bytes in the middle of the * extent have changed */ __le64 offset; /* * the logical number of file blocks (no csums included) */ __le64 num_blocks; } __attribute__ ((__packed__)); struct btrfs_inode_map_item { struct btrfs_disk_key key; } __attribute__ ((__packed__)); struct btrfs_fs_info { struct btrfs_root *fs_root; struct btrfs_root *extent_root; struct btrfs_root *tree_root; struct btrfs_root *inode_root; struct btrfs_key current_insert; struct btrfs_key last_insert; int fp; struct radix_tree_root cache_radix; struct radix_tree_root pinned_radix; struct list_head trans; struct list_head cache; u64 last_inode_alloc; u64 last_inode_alloc_dirid; int cache_size; int ref_cows; int fp; struct btrfs_trans_handle *running_transaction; }; /* * in ram representation of the tree. extent_root is used for all allocations * and for the extent tree extent_root root. current_insert is used * only for the extent tree. */ struct btrfs_root { struct btrfs_buffer *node; struct btrfs_buffer *commit_root; struct btrfs_root_item root_item; struct btrfs_key root_key; struct btrfs_fs_info *fs_info; u32 blocksize; struct btrfs_trans_handle *running_transaction; int ref_cows; u32 type; }; /* the lower bits in the key flags defines the item type */ Loading Loading @@ -240,11 +275,17 @@ struct btrfs_root { * are used, and how many references there are to each block */ #define BTRFS_EXTENT_ITEM_KEY 6 /* * the inode map records which inode numbers are in use and where * they actually live on disk */ #define BTRFS_INODE_MAP_ITEM_KEY 7 /* * string items are for debugging. They just store a short string of * data in the FS */ #define BTRFS_STRING_ITEM_KEY 7 #define BTRFS_STRING_ITEM_KEY 8 static inline u64 btrfs_inode_generation(struct btrfs_inode_item *i) { Loading Loading @@ -654,6 +695,57 @@ static inline u8 *btrfs_leaf_data(struct btrfs_leaf *l) { return (u8 *)l->items; } static inline u64 btrfs_file_extent_disk_blocknr(struct btrfs_file_extent_item *e) { return le64_to_cpu(e->disk_blocknr); } static inline void btrfs_set_file_extent_disk_blocknr(struct btrfs_file_extent_item *e, u64 val) { e->disk_blocknr = cpu_to_le64(val); } static inline u64 btrfs_file_extent_disk_num_blocks(struct btrfs_file_extent_item *e) { return le64_to_cpu(e->disk_num_blocks); } static inline void btrfs_set_file_extent_disk_num_blocks(struct btrfs_file_extent_item *e, u64 val) { e->disk_num_blocks = cpu_to_le64(val); } static inline u64 btrfs_file_extent_offset(struct btrfs_file_extent_item *e) { return le64_to_cpu(e->offset); } static inline void btrfs_set_file_extent_offset(struct btrfs_file_extent_item *e, u64 val) { e->offset = cpu_to_le64(val); } static inline u64 btrfs_file_extent_num_blocks(struct btrfs_file_extent_item *e) { return le64_to_cpu(e->num_blocks); } static inline void btrfs_set_file_extent_num_blocks(struct btrfs_file_extent_item *e, u64 val) { e->num_blocks = cpu_to_le64(val); } /* helper function to cast into the data area of the leaf. */ #define btrfs_item_ptr(leaf, slot, type) \ ((type *)(btrfs_leaf_data(leaf) + \ Loading Loading @@ -701,4 +793,13 @@ int btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root int name_len, int mod); int btrfs_match_dir_item_name(struct btrfs_root *root, struct btrfs_path *path, char *name, int name_len); int btrfs_find_free_objectid(struct btrfs_trans_handle *trans, struct btrfs_root *fs_root, u64 dirid, u64 *objectid); int btrfs_insert_inode_map(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, struct btrfs_key *location); int btrfs_lookup_inode_map(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 objectid, int mod); #endif fs/btrfs/debug-tree.c +7 −2 Original line number Diff line number Diff line Loading @@ -15,8 +15,13 @@ int main(int ac, char **av) { printf("fs tree\n"); btrfs_print_tree(root, root->node); printf("map tree\n"); btrfs_print_tree(root->extent_root, root->extent_root->node); btrfs_print_tree(root->fs_info->extent_root, root->fs_info->extent_root->node); printf("inode tree\n"); btrfs_print_tree(root->fs_info->inode_root, root->fs_info->inode_root->node); printf("root tree\n"); btrfs_print_tree(root->tree_root, root->tree_root->node); btrfs_print_tree(root->fs_info->tree_root, root->fs_info->tree_root->node); return 0; } fs/btrfs/dir-test.c +75 −16 Original line number Diff line number Diff line Loading @@ -45,13 +45,26 @@ static int ins_one(struct btrfs_trans_handle *trans, struct btrfs_root *root, int ret; char buf[128]; unsigned long oid; u64 objectid; struct btrfs_path path; struct btrfs_key inode_map; find_num(radix, &oid, 0); sprintf(buf, "str-%lu", oid); ret = btrfs_find_free_objectid(trans, root, dir_oid + 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; ret = btrfs_insert_dir_item(trans, root, buf, strlen(buf), dir_oid, file_oid, 1); objectid, 1); if (ret) goto error; Loading Loading @@ -120,6 +133,53 @@ static int insert_dup(struct btrfs_trans_handle *trans, struct btrfs_root return 0; } static int del_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct radix_tree_root *radix, unsigned long radix_index, struct btrfs_path *path) { int ret; unsigned long *ptr; u64 file_objectid; struct btrfs_dir_item *di; struct btrfs_path map_path; /* find the inode number of the file */ di = btrfs_item_ptr(&path->nodes[0]->leaf, path->slots[0], struct btrfs_dir_item); file_objectid = btrfs_dir_objectid(di); /* delete the directory item */ ret = btrfs_del_item(trans, root, path); if (ret) goto out; /* delete the inode mapping */ btrfs_init_path(&map_path); ret = btrfs_lookup_inode_map(trans, root, &map_path, file_objectid, -1); if (ret) goto out_release; ret = btrfs_del_item(trans, root->fs_info->inode_root, &map_path); if (ret) goto out_release; if (root->fs_info->last_inode_alloc > file_objectid) root->fs_info->last_inode_alloc = file_objectid; btrfs_release_path(root, &map_path); ptr = radix_tree_delete(radix, radix_index); if (!ptr) { ret = -5555; goto out; } return 0; out_release: btrfs_release_path(root, &map_path); out: printf("failed to delete %lu %d\n", radix_index, ret); return -1; } static int del_one(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct radix_tree_root *radix) { Loading @@ -127,7 +187,6 @@ static int del_one(struct btrfs_trans_handle *trans, struct btrfs_root *root, char buf[128]; unsigned long oid; struct btrfs_path path; unsigned long *ptr; ret = find_num(radix, &oid, 1); if (ret < 0) Loading @@ -138,19 +197,14 @@ static int del_one(struct btrfs_trans_handle *trans, struct btrfs_root *root, strlen(buf), -1); if (ret) goto out_release; ret = btrfs_del_item(trans, root, &path); ret = del_dir_item(trans, root, radix, oid, &path); if (ret) goto out_release; btrfs_release_path(root, &path); ptr = radix_tree_delete(radix, oid); if (!ptr) { ret = -5555; goto out; } return 0; return ret; out_release: btrfs_release_path(root, &path); out: printf("failed to delete %lu %d\n", oid, ret); return -1; } Loading @@ -162,6 +216,8 @@ static int lookup_item(struct btrfs_trans_handle *trans, struct btrfs_root char buf[128]; int ret; unsigned long oid; u64 objectid; struct btrfs_dir_item *di; ret = find_num(radix, &oid, 1); if (ret < 0) Loading @@ -170,6 +226,14 @@ static int lookup_item(struct btrfs_trans_handle *trans, struct btrfs_root btrfs_init_path(&path); ret = btrfs_lookup_dir_item(trans, root, &path, dir_oid, buf, strlen(buf), 0); if (!ret) { di = btrfs_item_ptr(&path.nodes[0]->leaf, path.slots[0], struct btrfs_dir_item); objectid = btrfs_dir_objectid(di); btrfs_release_path(root, &path); btrfs_init_path(&path); ret = btrfs_lookup_inode_map(trans, root, &path, objectid, 0); } btrfs_release_path(root, &path); if (ret) { printf("unable to find key %lu\n", oid); Loading Loading @@ -210,7 +274,6 @@ static int empty_tree(struct btrfs_trans_handle *trans, struct btrfs_root u32 found_len; int ret; int slot; int *ptr; int count = 0; char buf[128]; struct btrfs_dir_item *di; Loading Loading @@ -241,7 +304,7 @@ static int empty_tree(struct btrfs_trans_handle *trans, struct btrfs_root BUG_ON(found_len > 128); buf[found_len] = '\0'; found = atoi(buf + 4); ret = btrfs_del_item(trans, root, &path); ret = del_dir_item(trans, root, radix, found, &path); count++; if (ret) { fprintf(stderr, Loading @@ -250,14 +313,10 @@ static int empty_tree(struct btrfs_trans_handle *trans, struct btrfs_root return -1; } btrfs_release_path(root, &path); ptr = radix_tree_delete(radix, found); if (!ptr) goto error; if (!keep_running) break; } return 0; error: fprintf(stderr, "failed to delete from the radix %lu\n", found); return -1; } Loading fs/btrfs/disk-io.c +96 −80 Original line number Diff line number Diff line Loading @@ -28,15 +28,15 @@ static int free_some_buffers(struct btrfs_root *root) { struct list_head *node, *next; struct btrfs_buffer *b; if (root->cache_size < cache_max) if (root->fs_info->cache_size < cache_max) return 0; list_for_each_safe(node, next, &root->cache) { list_for_each_safe(node, next, &root->fs_info->cache) { b = list_entry(node, struct btrfs_buffer, cache); if (b->count == 1) { BUG_ON(!list_empty(&b->dirty)); list_del_init(&b->cache); btrfs_block_release(root, b); if (root->cache_size < cache_max) if (root->fs_info->cache_size < cache_max) break; } } Loading @@ -57,10 +57,10 @@ struct btrfs_buffer *alloc_tree_block(struct btrfs_root *root, u64 blocknr) INIT_LIST_HEAD(&buf->dirty); free_some_buffers(root); radix_tree_preload(GFP_KERNEL); ret = radix_tree_insert(&root->cache_radix, blocknr, buf); ret = radix_tree_insert(&root->fs_info->cache_radix, blocknr, buf); radix_tree_preload_end(); list_add_tail(&buf->cache, &root->cache); root->cache_size++; list_add_tail(&buf->cache, &root->fs_info->cache); root->fs_info->cache_size++; if (ret) { free(buf); return NULL; Loading @@ -71,7 +71,7 @@ struct btrfs_buffer *alloc_tree_block(struct btrfs_root *root, u64 blocknr) struct btrfs_buffer *find_tree_block(struct btrfs_root *root, u64 blocknr) { struct btrfs_buffer *buf; buf = radix_tree_lookup(&root->cache_radix, blocknr); buf = radix_tree_lookup(&root->fs_info->cache_radix, blocknr); if (buf) { buf->count++; } else { Loading @@ -90,14 +90,15 @@ struct btrfs_buffer *read_tree_block(struct btrfs_root *root, u64 blocknr) struct btrfs_buffer *buf; int ret; buf = radix_tree_lookup(&root->cache_radix, blocknr); buf = radix_tree_lookup(&root->fs_info->cache_radix, blocknr); if (buf) { buf->count++; } else { buf = alloc_tree_block(root, blocknr); if (!buf) return NULL; ret = pread(root->fp, &buf->node, root->blocksize, offset); ret = pread(root->fs_info->fp, &buf->node, root->blocksize, offset); if (ret != root->blocksize) { free(buf); return NULL; Loading @@ -113,7 +114,7 @@ int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, { if (!list_empty(&buf->dirty)) return 0; list_add_tail(&buf->dirty, &root->trans); list_add_tail(&buf->dirty, &root->fs_info->trans); buf->count++; return 0; } Loading @@ -137,7 +138,7 @@ int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, if (buf->blocknr != btrfs_header_blocknr(&buf->node.header)) BUG(); ret = pwrite(root->fp, &buf->node, root->blocksize, offset); ret = pwrite(root->fs_info->fp, &buf->node, root->blocksize, offset); if (ret != root->blocksize) return ret; return 0; Loading @@ -149,8 +150,9 @@ static int __commit_transaction(struct btrfs_trans_handle *trans, struct struct btrfs_buffer *b; int ret = 0; int wret; while(!list_empty(&root->trans)) { b = list_entry(root->trans.next, struct btrfs_buffer, dirty); while(!list_empty(&root->fs_info->trans)) { b = list_entry(root->fs_info->trans.next, struct btrfs_buffer, dirty); list_del_init(&b->dirty); wret = write_tree_block(trans, root, b); if (wret) Loading @@ -160,13 +162,21 @@ static int __commit_transaction(struct btrfs_trans_handle *trans, struct return ret; } static int commit_extent_and_tree_roots(struct btrfs_trans_handle *trans, struct btrfs_root *tree_root, struct btrfs_root *extent_root) static int commit_tree_roots(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info) { int ret; u64 old_extent_block; struct btrfs_root *tree_root = fs_info->tree_root; struct btrfs_root *extent_root = fs_info->extent_root; struct btrfs_root *inode_root = fs_info->inode_root; btrfs_set_root_blocknr(&inode_root->root_item, inode_root->node->blocknr); ret = btrfs_update_root(trans, tree_root, &inode_root->root_key, &inode_root->root_item); BUG_ON(ret); while(1) { old_extent_block = btrfs_root_blocknr(&extent_root->root_item); if (old_extent_block == extent_root->node->blocknr) Loading @@ -178,8 +188,6 @@ static int commit_extent_and_tree_roots(struct btrfs_trans_handle *trans, &extent_root->root_item); BUG_ON(ret); } __commit_transaction(trans, extent_root); __commit_transaction(trans, tree_root); return 0; } Loading @@ -190,9 +198,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct struct btrfs_buffer *snap = root->commit_root; struct btrfs_key snap_key; ret = __commit_transaction(trans, root); BUG_ON(ret); if (root->commit_root == root->node) return 0; Loading @@ -200,54 +205,55 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct root->root_key.offset++; btrfs_set_root_blocknr(&root->root_item, root->node->blocknr); ret = btrfs_insert_root(trans, root->tree_root, &root->root_key, &root->root_item); ret = btrfs_insert_root(trans, root->fs_info->tree_root, &root->root_key, &root->root_item); BUG_ON(ret); ret = commit_tree_roots(trans, root->fs_info); BUG_ON(ret); ret = commit_extent_and_tree_roots(trans, root->tree_root, root->extent_root); ret = __commit_transaction(trans, root); BUG_ON(ret); write_ctree_super(trans, root, s); btrfs_finish_extent_commit(trans, root->extent_root); btrfs_finish_extent_commit(trans, root->tree_root); btrfs_finish_extent_commit(trans, root->fs_info->extent_root); btrfs_finish_extent_commit(trans, root->fs_info->tree_root); root->commit_root = root->node; root->node->count++; ret = btrfs_drop_snapshot(trans, root, snap); BUG_ON(ret); ret = btrfs_del_root(trans, root->tree_root, &snap_key); ret = btrfs_del_root(trans, root->fs_info->tree_root, &snap_key); BUG_ON(ret); return ret; } static int __setup_root(struct btrfs_super_block *super, struct btrfs_root *root, u64 objectid, int fp) struct btrfs_root *root, struct btrfs_fs_info *fs_info, u64 objectid, int fp) { INIT_LIST_HEAD(&root->trans); INIT_LIST_HEAD(&root->cache); root->cache_size = 0; root->fp = fp; root->node = NULL; root->commit_root = NULL; root->blocksize = btrfs_super_blocksize(super); root->ref_cows = 0; memset(&root->current_insert, 0, sizeof(root->current_insert)); memset(&root->last_insert, 0, sizeof(root->last_insert)); root->fs_info = fs_info; memset(&root->root_key, 0, sizeof(root->root_key)); memset(&root->root_item, 0, sizeof(root->root_item)); return 0; } static int find_and_setup_root(struct btrfs_super_block *super, struct btrfs_root *tree_root, u64 objectid, struct btrfs_root *tree_root, struct btrfs_fs_info *fs_info, u64 objectid, struct btrfs_root *root, int fp) { int ret; __setup_root(super, root, objectid, fp); __setup_root(super, root, fs_info, objectid, fp); ret = btrfs_find_last_root(tree_root, objectid, &root->root_item, &root->root_key); BUG_ON(ret); Loading @@ -263,29 +269,31 @@ struct btrfs_root *open_ctree(char *filename, 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; root->extent_root = extent_root; root->tree_root = tree_root; extent_root->extent_root = extent_root; extent_root->tree_root = tree_root; tree_root->extent_root = extent_root; tree_root->tree_root = tree_root; fp = open(filename, O_CREAT | O_RDWR, 0600); if (fp < 0) { free(root); return NULL; } INIT_RADIX_TREE(&root->cache_radix, GFP_KERNEL); INIT_RADIX_TREE(&root->pinned_radix, GFP_KERNEL); INIT_RADIX_TREE(&extent_root->pinned_radix, GFP_KERNEL); INIT_RADIX_TREE(&extent_root->cache_radix, GFP_KERNEL); INIT_RADIX_TREE(&tree_root->pinned_radix, GFP_KERNEL); INIT_RADIX_TREE(&tree_root->cache_radix, GFP_KERNEL); INIT_RADIX_TREE(&fs_info->cache_radix, GFP_KERNEL); INIT_RADIX_TREE(&fs_info->pinned_radix, GFP_KERNEL); INIT_LIST_HEAD(&fs_info->trans); INIT_LIST_HEAD(&fs_info->cache); fs_info->cache_size = 0; fs_info->fp = fp; fs_info->running_transaction = NULL; fs_info->fs_root = root; fs_info->tree_root = tree_root; fs_info->extent_root = extent_root; fs_info->inode_root = inode_root; fs_info->last_inode_alloc = 0; fs_info->last_inode_alloc_dirid = 0; memset(&fs_info->current_insert, 0, sizeof(fs_info->current_insert)); memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert)); ret = pread(fp, super, sizeof(struct btrfs_super_block), BTRFS_SUPER_INFO_OFFSET); Loading @@ -301,16 +309,20 @@ struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *super) } BUG_ON(ret < 0); __setup_root(super, tree_root, BTRFS_ROOT_TREE_OBJECTID, fp); __setup_root(super, tree_root, fs_info, BTRFS_ROOT_TREE_OBJECTID, fp); tree_root->node = read_tree_block(tree_root, btrfs_super_root(super)); BUG_ON(!tree_root->node); ret = find_and_setup_root(super, tree_root, BTRFS_EXTENT_TREE_OBJECTID, extent_root, fp); ret = find_and_setup_root(super, tree_root, fs_info, BTRFS_EXTENT_TREE_OBJECTID, extent_root, fp); BUG_ON(ret); ret = find_and_setup_root(super, tree_root, BTRFS_FS_TREE_OBJECTID, root, fp); ret = find_and_setup_root(super, tree_root, fs_info, BTRFS_INODE_MAP_OBJECTID, inode_root, fp); BUG_ON(ret); ret = find_and_setup_root(super, tree_root, fs_info, BTRFS_FS_TREE_OBJECTID, root, fp); BUG_ON(ret); root->commit_root = root->node; Loading @@ -323,8 +335,8 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_super_block *s) { int ret; btrfs_set_super_root(s, root->tree_root->node->blocknr); ret = pwrite(root->fp, s, sizeof(*s), btrfs_set_super_root(s, root->fs_info->tree_root->node->blocknr); ret = pwrite(root->fs_info->fp, s, sizeof(*s), BTRFS_SUPER_INFO_OFFSET); if (ret != sizeof(*s)) { fprintf(stderr, "failed to write new super block err %d\n", ret); Loading @@ -335,9 +347,10 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root static int drop_cache(struct btrfs_root *root) { while(!list_empty(&root->cache)) { struct btrfs_buffer *b = list_entry(root->cache.next, struct btrfs_buffer, cache); while(!list_empty(&root->fs_info->cache)) { struct btrfs_buffer *b = list_entry(root->fs_info->cache.next, struct btrfs_buffer, cache); list_del_init(&b->cache); btrfs_block_release(root, b); } Loading @@ -348,26 +361,28 @@ int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s) int ret; struct btrfs_trans_handle *trans; trans = root->running_transaction; trans = root->fs_info->running_transaction; btrfs_commit_transaction(trans, root, s); ret = commit_extent_and_tree_roots(trans, root->tree_root, root->extent_root); ret = commit_tree_roots(trans, root->fs_info); BUG_ON(ret); ret = __commit_transaction(trans, root); BUG_ON(ret); write_ctree_super(trans, root, s); drop_cache(root->extent_root); drop_cache(root->tree_root); drop_cache(root); BUG_ON(!list_empty(&root->trans)); BUG_ON(!list_empty(&root->extent_root->trans)); BUG_ON(!list_empty(&root->tree_root->trans)); BUG_ON(!list_empty(&root->fs_info->trans)); close(root->fp); close(root->fs_info->fp); if (root->node) btrfs_block_release(root, root->node); if (root->extent_root->node) btrfs_block_release(root->extent_root, root->extent_root->node); if (root->tree_root->node) btrfs_block_release(root->tree_root, root->tree_root->node); if (root->fs_info->extent_root->node) btrfs_block_release(root->fs_info->extent_root, root->fs_info->extent_root->node); if (root->fs_info->inode_root->node) btrfs_block_release(root->fs_info->inode_root, root->fs_info->inode_root->node); if (root->fs_info->tree_root->node) btrfs_block_release(root->fs_info->tree_root, root->fs_info->tree_root->node); btrfs_block_release(root, root->commit_root); free(root); printf("on close %d blocks are allocated\n", allocated_blocks); Loading @@ -382,15 +397,16 @@ void btrfs_block_release(struct btrfs_root *root, struct btrfs_buffer *buf) if (buf->count == 0) { BUG_ON(!list_empty(&buf->cache)); BUG_ON(!list_empty(&buf->dirty)); if (!radix_tree_lookup(&root->cache_radix, buf->blocknr)) if (!radix_tree_lookup(&root->fs_info->cache_radix, buf->blocknr)) BUG(); radix_tree_delete(&root->cache_radix, buf->blocknr); radix_tree_delete(&root->fs_info->cache_radix, buf->blocknr); memset(buf, 0, sizeof(*buf)); free(buf); BUG_ON(allocated_blocks == 0); allocated_blocks--; BUG_ON(root->cache_size == 0); root->cache_size--; BUG_ON(root->fs_info->cache_size == 0); root->fs_info->cache_size--; } } Loading
fs/btrfs/Makefile +2 −1 Original line number Diff line number Diff line Loading @@ -3,7 +3,8 @@ CFLAGS = -g -Wall -Werror headers = radix-tree.h ctree.h disk-io.h kerncompat.h print-tree.h list.h \ transaction.h objects = ctree.o disk-io.o radix-tree.o mkfs.o extent-tree.o print-tree.o \ root-tree.o dir-item.o hash.o file-item.o inode-item.o root-tree.o dir-item.o hash.o file-item.o inode-item.o \ inode-map.o \ # if you don't have sparse installed, use ls instead CHECKFLAGS=-D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \ Loading
fs/btrfs/ctree.h +115 −14 Original line number Diff line number Diff line Loading @@ -10,7 +10,8 @@ struct btrfs_trans_handle; #define BTRFS_ROOT_TREE_OBJECTID 1 #define BTRFS_EXTENT_TREE_OBJECTID 2 #define BTRFS_FS_TREE_OBJECTID 3 #define BTRFS_INODE_MAP_OBJECTID 3 #define BTRFS_FS_TREE_OBJECTID 4 /* * the key defines the order in the tree, and so it also defines (optimal) Loading Loading @@ -178,31 +179,65 @@ struct btrfs_root_item { __le64 block_limit; __le64 blocks_used; __le32 refs; }; } __attribute__ ((__packed__)); struct btrfs_file_extent_item { /* * in ram representation of the tree. extent_root is used for all allocations * and for the extent tree extent_root root. current_insert is used * only for the extent tree. * disk space consumed by the extent, checksum blocks are included * in these numbers */ struct btrfs_root { struct btrfs_buffer *node; struct btrfs_buffer *commit_root; __le64 disk_blocknr; __le64 disk_num_blocks; /* * the logical offset in file bytes (no csums) * this extent record is for. This allows a file extent to point * into the middle of an existing extent on disk, sharing it * between two snapshots (useful if some bytes in the middle of the * extent have changed */ __le64 offset; /* * the logical number of file blocks (no csums included) */ __le64 num_blocks; } __attribute__ ((__packed__)); struct btrfs_inode_map_item { struct btrfs_disk_key key; } __attribute__ ((__packed__)); struct btrfs_fs_info { struct btrfs_root *fs_root; struct btrfs_root *extent_root; struct btrfs_root *tree_root; struct btrfs_root *inode_root; struct btrfs_key current_insert; struct btrfs_key last_insert; int fp; struct radix_tree_root cache_radix; struct radix_tree_root pinned_radix; struct list_head trans; struct list_head cache; u64 last_inode_alloc; u64 last_inode_alloc_dirid; int cache_size; int ref_cows; int fp; struct btrfs_trans_handle *running_transaction; }; /* * in ram representation of the tree. extent_root is used for all allocations * and for the extent tree extent_root root. current_insert is used * only for the extent tree. */ struct btrfs_root { struct btrfs_buffer *node; struct btrfs_buffer *commit_root; struct btrfs_root_item root_item; struct btrfs_key root_key; struct btrfs_fs_info *fs_info; u32 blocksize; struct btrfs_trans_handle *running_transaction; int ref_cows; u32 type; }; /* the lower bits in the key flags defines the item type */ Loading Loading @@ -240,11 +275,17 @@ struct btrfs_root { * are used, and how many references there are to each block */ #define BTRFS_EXTENT_ITEM_KEY 6 /* * the inode map records which inode numbers are in use and where * they actually live on disk */ #define BTRFS_INODE_MAP_ITEM_KEY 7 /* * string items are for debugging. They just store a short string of * data in the FS */ #define BTRFS_STRING_ITEM_KEY 7 #define BTRFS_STRING_ITEM_KEY 8 static inline u64 btrfs_inode_generation(struct btrfs_inode_item *i) { Loading Loading @@ -654,6 +695,57 @@ static inline u8 *btrfs_leaf_data(struct btrfs_leaf *l) { return (u8 *)l->items; } static inline u64 btrfs_file_extent_disk_blocknr(struct btrfs_file_extent_item *e) { return le64_to_cpu(e->disk_blocknr); } static inline void btrfs_set_file_extent_disk_blocknr(struct btrfs_file_extent_item *e, u64 val) { e->disk_blocknr = cpu_to_le64(val); } static inline u64 btrfs_file_extent_disk_num_blocks(struct btrfs_file_extent_item *e) { return le64_to_cpu(e->disk_num_blocks); } static inline void btrfs_set_file_extent_disk_num_blocks(struct btrfs_file_extent_item *e, u64 val) { e->disk_num_blocks = cpu_to_le64(val); } static inline u64 btrfs_file_extent_offset(struct btrfs_file_extent_item *e) { return le64_to_cpu(e->offset); } static inline void btrfs_set_file_extent_offset(struct btrfs_file_extent_item *e, u64 val) { e->offset = cpu_to_le64(val); } static inline u64 btrfs_file_extent_num_blocks(struct btrfs_file_extent_item *e) { return le64_to_cpu(e->num_blocks); } static inline void btrfs_set_file_extent_num_blocks(struct btrfs_file_extent_item *e, u64 val) { e->num_blocks = cpu_to_le64(val); } /* helper function to cast into the data area of the leaf. */ #define btrfs_item_ptr(leaf, slot, type) \ ((type *)(btrfs_leaf_data(leaf) + \ Loading Loading @@ -701,4 +793,13 @@ int btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root int name_len, int mod); int btrfs_match_dir_item_name(struct btrfs_root *root, struct btrfs_path *path, char *name, int name_len); int btrfs_find_free_objectid(struct btrfs_trans_handle *trans, struct btrfs_root *fs_root, u64 dirid, u64 *objectid); int btrfs_insert_inode_map(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, struct btrfs_key *location); int btrfs_lookup_inode_map(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 objectid, int mod); #endif
fs/btrfs/debug-tree.c +7 −2 Original line number Diff line number Diff line Loading @@ -15,8 +15,13 @@ int main(int ac, char **av) { printf("fs tree\n"); btrfs_print_tree(root, root->node); printf("map tree\n"); btrfs_print_tree(root->extent_root, root->extent_root->node); btrfs_print_tree(root->fs_info->extent_root, root->fs_info->extent_root->node); printf("inode tree\n"); btrfs_print_tree(root->fs_info->inode_root, root->fs_info->inode_root->node); printf("root tree\n"); btrfs_print_tree(root->tree_root, root->tree_root->node); btrfs_print_tree(root->fs_info->tree_root, root->fs_info->tree_root->node); return 0; }
fs/btrfs/dir-test.c +75 −16 Original line number Diff line number Diff line Loading @@ -45,13 +45,26 @@ static int ins_one(struct btrfs_trans_handle *trans, struct btrfs_root *root, int ret; char buf[128]; unsigned long oid; u64 objectid; struct btrfs_path path; struct btrfs_key inode_map; find_num(radix, &oid, 0); sprintf(buf, "str-%lu", oid); ret = btrfs_find_free_objectid(trans, root, dir_oid + 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; ret = btrfs_insert_dir_item(trans, root, buf, strlen(buf), dir_oid, file_oid, 1); objectid, 1); if (ret) goto error; Loading Loading @@ -120,6 +133,53 @@ static int insert_dup(struct btrfs_trans_handle *trans, struct btrfs_root return 0; } static int del_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct radix_tree_root *radix, unsigned long radix_index, struct btrfs_path *path) { int ret; unsigned long *ptr; u64 file_objectid; struct btrfs_dir_item *di; struct btrfs_path map_path; /* find the inode number of the file */ di = btrfs_item_ptr(&path->nodes[0]->leaf, path->slots[0], struct btrfs_dir_item); file_objectid = btrfs_dir_objectid(di); /* delete the directory item */ ret = btrfs_del_item(trans, root, path); if (ret) goto out; /* delete the inode mapping */ btrfs_init_path(&map_path); ret = btrfs_lookup_inode_map(trans, root, &map_path, file_objectid, -1); if (ret) goto out_release; ret = btrfs_del_item(trans, root->fs_info->inode_root, &map_path); if (ret) goto out_release; if (root->fs_info->last_inode_alloc > file_objectid) root->fs_info->last_inode_alloc = file_objectid; btrfs_release_path(root, &map_path); ptr = radix_tree_delete(radix, radix_index); if (!ptr) { ret = -5555; goto out; } return 0; out_release: btrfs_release_path(root, &map_path); out: printf("failed to delete %lu %d\n", radix_index, ret); return -1; } static int del_one(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct radix_tree_root *radix) { Loading @@ -127,7 +187,6 @@ static int del_one(struct btrfs_trans_handle *trans, struct btrfs_root *root, char buf[128]; unsigned long oid; struct btrfs_path path; unsigned long *ptr; ret = find_num(radix, &oid, 1); if (ret < 0) Loading @@ -138,19 +197,14 @@ static int del_one(struct btrfs_trans_handle *trans, struct btrfs_root *root, strlen(buf), -1); if (ret) goto out_release; ret = btrfs_del_item(trans, root, &path); ret = del_dir_item(trans, root, radix, oid, &path); if (ret) goto out_release; btrfs_release_path(root, &path); ptr = radix_tree_delete(radix, oid); if (!ptr) { ret = -5555; goto out; } return 0; return ret; out_release: btrfs_release_path(root, &path); out: printf("failed to delete %lu %d\n", oid, ret); return -1; } Loading @@ -162,6 +216,8 @@ static int lookup_item(struct btrfs_trans_handle *trans, struct btrfs_root char buf[128]; int ret; unsigned long oid; u64 objectid; struct btrfs_dir_item *di; ret = find_num(radix, &oid, 1); if (ret < 0) Loading @@ -170,6 +226,14 @@ static int lookup_item(struct btrfs_trans_handle *trans, struct btrfs_root btrfs_init_path(&path); ret = btrfs_lookup_dir_item(trans, root, &path, dir_oid, buf, strlen(buf), 0); if (!ret) { di = btrfs_item_ptr(&path.nodes[0]->leaf, path.slots[0], struct btrfs_dir_item); objectid = btrfs_dir_objectid(di); btrfs_release_path(root, &path); btrfs_init_path(&path); ret = btrfs_lookup_inode_map(trans, root, &path, objectid, 0); } btrfs_release_path(root, &path); if (ret) { printf("unable to find key %lu\n", oid); Loading Loading @@ -210,7 +274,6 @@ static int empty_tree(struct btrfs_trans_handle *trans, struct btrfs_root u32 found_len; int ret; int slot; int *ptr; int count = 0; char buf[128]; struct btrfs_dir_item *di; Loading Loading @@ -241,7 +304,7 @@ static int empty_tree(struct btrfs_trans_handle *trans, struct btrfs_root BUG_ON(found_len > 128); buf[found_len] = '\0'; found = atoi(buf + 4); ret = btrfs_del_item(trans, root, &path); ret = del_dir_item(trans, root, radix, found, &path); count++; if (ret) { fprintf(stderr, Loading @@ -250,14 +313,10 @@ static int empty_tree(struct btrfs_trans_handle *trans, struct btrfs_root return -1; } btrfs_release_path(root, &path); ptr = radix_tree_delete(radix, found); if (!ptr) goto error; if (!keep_running) break; } return 0; error: fprintf(stderr, "failed to delete from the radix %lu\n", found); return -1; } Loading
fs/btrfs/disk-io.c +96 −80 Original line number Diff line number Diff line Loading @@ -28,15 +28,15 @@ static int free_some_buffers(struct btrfs_root *root) { struct list_head *node, *next; struct btrfs_buffer *b; if (root->cache_size < cache_max) if (root->fs_info->cache_size < cache_max) return 0; list_for_each_safe(node, next, &root->cache) { list_for_each_safe(node, next, &root->fs_info->cache) { b = list_entry(node, struct btrfs_buffer, cache); if (b->count == 1) { BUG_ON(!list_empty(&b->dirty)); list_del_init(&b->cache); btrfs_block_release(root, b); if (root->cache_size < cache_max) if (root->fs_info->cache_size < cache_max) break; } } Loading @@ -57,10 +57,10 @@ struct btrfs_buffer *alloc_tree_block(struct btrfs_root *root, u64 blocknr) INIT_LIST_HEAD(&buf->dirty); free_some_buffers(root); radix_tree_preload(GFP_KERNEL); ret = radix_tree_insert(&root->cache_radix, blocknr, buf); ret = radix_tree_insert(&root->fs_info->cache_radix, blocknr, buf); radix_tree_preload_end(); list_add_tail(&buf->cache, &root->cache); root->cache_size++; list_add_tail(&buf->cache, &root->fs_info->cache); root->fs_info->cache_size++; if (ret) { free(buf); return NULL; Loading @@ -71,7 +71,7 @@ struct btrfs_buffer *alloc_tree_block(struct btrfs_root *root, u64 blocknr) struct btrfs_buffer *find_tree_block(struct btrfs_root *root, u64 blocknr) { struct btrfs_buffer *buf; buf = radix_tree_lookup(&root->cache_radix, blocknr); buf = radix_tree_lookup(&root->fs_info->cache_radix, blocknr); if (buf) { buf->count++; } else { Loading @@ -90,14 +90,15 @@ struct btrfs_buffer *read_tree_block(struct btrfs_root *root, u64 blocknr) struct btrfs_buffer *buf; int ret; buf = radix_tree_lookup(&root->cache_radix, blocknr); buf = radix_tree_lookup(&root->fs_info->cache_radix, blocknr); if (buf) { buf->count++; } else { buf = alloc_tree_block(root, blocknr); if (!buf) return NULL; ret = pread(root->fp, &buf->node, root->blocksize, offset); ret = pread(root->fs_info->fp, &buf->node, root->blocksize, offset); if (ret != root->blocksize) { free(buf); return NULL; Loading @@ -113,7 +114,7 @@ int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, { if (!list_empty(&buf->dirty)) return 0; list_add_tail(&buf->dirty, &root->trans); list_add_tail(&buf->dirty, &root->fs_info->trans); buf->count++; return 0; } Loading @@ -137,7 +138,7 @@ int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, if (buf->blocknr != btrfs_header_blocknr(&buf->node.header)) BUG(); ret = pwrite(root->fp, &buf->node, root->blocksize, offset); ret = pwrite(root->fs_info->fp, &buf->node, root->blocksize, offset); if (ret != root->blocksize) return ret; return 0; Loading @@ -149,8 +150,9 @@ static int __commit_transaction(struct btrfs_trans_handle *trans, struct struct btrfs_buffer *b; int ret = 0; int wret; while(!list_empty(&root->trans)) { b = list_entry(root->trans.next, struct btrfs_buffer, dirty); while(!list_empty(&root->fs_info->trans)) { b = list_entry(root->fs_info->trans.next, struct btrfs_buffer, dirty); list_del_init(&b->dirty); wret = write_tree_block(trans, root, b); if (wret) Loading @@ -160,13 +162,21 @@ static int __commit_transaction(struct btrfs_trans_handle *trans, struct return ret; } static int commit_extent_and_tree_roots(struct btrfs_trans_handle *trans, struct btrfs_root *tree_root, struct btrfs_root *extent_root) static int commit_tree_roots(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info) { int ret; u64 old_extent_block; struct btrfs_root *tree_root = fs_info->tree_root; struct btrfs_root *extent_root = fs_info->extent_root; struct btrfs_root *inode_root = fs_info->inode_root; btrfs_set_root_blocknr(&inode_root->root_item, inode_root->node->blocknr); ret = btrfs_update_root(trans, tree_root, &inode_root->root_key, &inode_root->root_item); BUG_ON(ret); while(1) { old_extent_block = btrfs_root_blocknr(&extent_root->root_item); if (old_extent_block == extent_root->node->blocknr) Loading @@ -178,8 +188,6 @@ static int commit_extent_and_tree_roots(struct btrfs_trans_handle *trans, &extent_root->root_item); BUG_ON(ret); } __commit_transaction(trans, extent_root); __commit_transaction(trans, tree_root); return 0; } Loading @@ -190,9 +198,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct struct btrfs_buffer *snap = root->commit_root; struct btrfs_key snap_key; ret = __commit_transaction(trans, root); BUG_ON(ret); if (root->commit_root == root->node) return 0; Loading @@ -200,54 +205,55 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct root->root_key.offset++; btrfs_set_root_blocknr(&root->root_item, root->node->blocknr); ret = btrfs_insert_root(trans, root->tree_root, &root->root_key, &root->root_item); ret = btrfs_insert_root(trans, root->fs_info->tree_root, &root->root_key, &root->root_item); BUG_ON(ret); ret = commit_tree_roots(trans, root->fs_info); BUG_ON(ret); ret = commit_extent_and_tree_roots(trans, root->tree_root, root->extent_root); ret = __commit_transaction(trans, root); BUG_ON(ret); write_ctree_super(trans, root, s); btrfs_finish_extent_commit(trans, root->extent_root); btrfs_finish_extent_commit(trans, root->tree_root); btrfs_finish_extent_commit(trans, root->fs_info->extent_root); btrfs_finish_extent_commit(trans, root->fs_info->tree_root); root->commit_root = root->node; root->node->count++; ret = btrfs_drop_snapshot(trans, root, snap); BUG_ON(ret); ret = btrfs_del_root(trans, root->tree_root, &snap_key); ret = btrfs_del_root(trans, root->fs_info->tree_root, &snap_key); BUG_ON(ret); return ret; } static int __setup_root(struct btrfs_super_block *super, struct btrfs_root *root, u64 objectid, int fp) struct btrfs_root *root, struct btrfs_fs_info *fs_info, u64 objectid, int fp) { INIT_LIST_HEAD(&root->trans); INIT_LIST_HEAD(&root->cache); root->cache_size = 0; root->fp = fp; root->node = NULL; root->commit_root = NULL; root->blocksize = btrfs_super_blocksize(super); root->ref_cows = 0; memset(&root->current_insert, 0, sizeof(root->current_insert)); memset(&root->last_insert, 0, sizeof(root->last_insert)); root->fs_info = fs_info; memset(&root->root_key, 0, sizeof(root->root_key)); memset(&root->root_item, 0, sizeof(root->root_item)); return 0; } static int find_and_setup_root(struct btrfs_super_block *super, struct btrfs_root *tree_root, u64 objectid, struct btrfs_root *tree_root, struct btrfs_fs_info *fs_info, u64 objectid, struct btrfs_root *root, int fp) { int ret; __setup_root(super, root, objectid, fp); __setup_root(super, root, fs_info, objectid, fp); ret = btrfs_find_last_root(tree_root, objectid, &root->root_item, &root->root_key); BUG_ON(ret); Loading @@ -263,29 +269,31 @@ struct btrfs_root *open_ctree(char *filename, 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; root->extent_root = extent_root; root->tree_root = tree_root; extent_root->extent_root = extent_root; extent_root->tree_root = tree_root; tree_root->extent_root = extent_root; tree_root->tree_root = tree_root; fp = open(filename, O_CREAT | O_RDWR, 0600); if (fp < 0) { free(root); return NULL; } INIT_RADIX_TREE(&root->cache_radix, GFP_KERNEL); INIT_RADIX_TREE(&root->pinned_radix, GFP_KERNEL); INIT_RADIX_TREE(&extent_root->pinned_radix, GFP_KERNEL); INIT_RADIX_TREE(&extent_root->cache_radix, GFP_KERNEL); INIT_RADIX_TREE(&tree_root->pinned_radix, GFP_KERNEL); INIT_RADIX_TREE(&tree_root->cache_radix, GFP_KERNEL); INIT_RADIX_TREE(&fs_info->cache_radix, GFP_KERNEL); INIT_RADIX_TREE(&fs_info->pinned_radix, GFP_KERNEL); INIT_LIST_HEAD(&fs_info->trans); INIT_LIST_HEAD(&fs_info->cache); fs_info->cache_size = 0; fs_info->fp = fp; fs_info->running_transaction = NULL; fs_info->fs_root = root; fs_info->tree_root = tree_root; fs_info->extent_root = extent_root; fs_info->inode_root = inode_root; fs_info->last_inode_alloc = 0; fs_info->last_inode_alloc_dirid = 0; memset(&fs_info->current_insert, 0, sizeof(fs_info->current_insert)); memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert)); ret = pread(fp, super, sizeof(struct btrfs_super_block), BTRFS_SUPER_INFO_OFFSET); Loading @@ -301,16 +309,20 @@ struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *super) } BUG_ON(ret < 0); __setup_root(super, tree_root, BTRFS_ROOT_TREE_OBJECTID, fp); __setup_root(super, tree_root, fs_info, BTRFS_ROOT_TREE_OBJECTID, fp); tree_root->node = read_tree_block(tree_root, btrfs_super_root(super)); BUG_ON(!tree_root->node); ret = find_and_setup_root(super, tree_root, BTRFS_EXTENT_TREE_OBJECTID, extent_root, fp); ret = find_and_setup_root(super, tree_root, fs_info, BTRFS_EXTENT_TREE_OBJECTID, extent_root, fp); BUG_ON(ret); ret = find_and_setup_root(super, tree_root, BTRFS_FS_TREE_OBJECTID, root, fp); ret = find_and_setup_root(super, tree_root, fs_info, BTRFS_INODE_MAP_OBJECTID, inode_root, fp); BUG_ON(ret); ret = find_and_setup_root(super, tree_root, fs_info, BTRFS_FS_TREE_OBJECTID, root, fp); BUG_ON(ret); root->commit_root = root->node; Loading @@ -323,8 +335,8 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_super_block *s) { int ret; btrfs_set_super_root(s, root->tree_root->node->blocknr); ret = pwrite(root->fp, s, sizeof(*s), btrfs_set_super_root(s, root->fs_info->tree_root->node->blocknr); ret = pwrite(root->fs_info->fp, s, sizeof(*s), BTRFS_SUPER_INFO_OFFSET); if (ret != sizeof(*s)) { fprintf(stderr, "failed to write new super block err %d\n", ret); Loading @@ -335,9 +347,10 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root static int drop_cache(struct btrfs_root *root) { while(!list_empty(&root->cache)) { struct btrfs_buffer *b = list_entry(root->cache.next, struct btrfs_buffer, cache); while(!list_empty(&root->fs_info->cache)) { struct btrfs_buffer *b = list_entry(root->fs_info->cache.next, struct btrfs_buffer, cache); list_del_init(&b->cache); btrfs_block_release(root, b); } Loading @@ -348,26 +361,28 @@ int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s) int ret; struct btrfs_trans_handle *trans; trans = root->running_transaction; trans = root->fs_info->running_transaction; btrfs_commit_transaction(trans, root, s); ret = commit_extent_and_tree_roots(trans, root->tree_root, root->extent_root); ret = commit_tree_roots(trans, root->fs_info); BUG_ON(ret); ret = __commit_transaction(trans, root); BUG_ON(ret); write_ctree_super(trans, root, s); drop_cache(root->extent_root); drop_cache(root->tree_root); drop_cache(root); BUG_ON(!list_empty(&root->trans)); BUG_ON(!list_empty(&root->extent_root->trans)); BUG_ON(!list_empty(&root->tree_root->trans)); BUG_ON(!list_empty(&root->fs_info->trans)); close(root->fp); close(root->fs_info->fp); if (root->node) btrfs_block_release(root, root->node); if (root->extent_root->node) btrfs_block_release(root->extent_root, root->extent_root->node); if (root->tree_root->node) btrfs_block_release(root->tree_root, root->tree_root->node); if (root->fs_info->extent_root->node) btrfs_block_release(root->fs_info->extent_root, root->fs_info->extent_root->node); if (root->fs_info->inode_root->node) btrfs_block_release(root->fs_info->inode_root, root->fs_info->inode_root->node); if (root->fs_info->tree_root->node) btrfs_block_release(root->fs_info->tree_root, root->fs_info->tree_root->node); btrfs_block_release(root, root->commit_root); free(root); printf("on close %d blocks are allocated\n", allocated_blocks); Loading @@ -382,15 +397,16 @@ void btrfs_block_release(struct btrfs_root *root, struct btrfs_buffer *buf) if (buf->count == 0) { BUG_ON(!list_empty(&buf->cache)); BUG_ON(!list_empty(&buf->dirty)); if (!radix_tree_lookup(&root->cache_radix, buf->blocknr)) if (!radix_tree_lookup(&root->fs_info->cache_radix, buf->blocknr)) BUG(); radix_tree_delete(&root->cache_radix, buf->blocknr); radix_tree_delete(&root->fs_info->cache_radix, buf->blocknr); memset(buf, 0, sizeof(*buf)); free(buf); BUG_ON(allocated_blocks == 0); allocated_blocks--; BUG_ON(root->cache_size == 0); root->cache_size--; BUG_ON(root->fs_info->cache_size == 0); root->fs_info->cache_size--; } }