Commit 9f5fae2f authored by Chris Mason's avatar Chris Mason Committed by David Woodhouse
Browse files

Btrfs: Add inode map, and the start of file extent items

parent 631d7d95
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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 \
+115 −14
Original line number Diff line number Diff line
@@ -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)
@@ -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 */
@@ -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)
{
@@ -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) + \
@@ -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
+7 −2
Original line number Diff line number Diff line
@@ -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;
}
+75 −16
Original line number Diff line number Diff line
@@ -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;

@@ -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)
{
@@ -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)
@@ -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;
}
@@ -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)
@@ -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);
@@ -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;
@@ -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,
@@ -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;
}
+96 −80
Original line number Diff line number Diff line
@@ -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;
		}
	}
@@ -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;
@@ -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 {
@@ -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;
@@ -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;
}
@@ -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;
@@ -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)
@@ -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)
@@ -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;
}

@@ -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;

@@ -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);
@@ -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);
@@ -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;
@@ -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);
@@ -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);
	}
@@ -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);
@@ -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