Btrfs: dynamic allocation of path struct

Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c
index f55c894..baceb1d 100644
--- a/fs/btrfs/dir-item.c
+++ b/fs/btrfs/dir-item.c
@@ -9,7 +9,7 @@
 			  objectid, u8 type)
 {
 	int ret = 0;
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	struct btrfs_dir_item *dir_item;
 	char *name_ptr;
 	struct btrfs_key key;
@@ -20,24 +20,26 @@
 	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
 	ret = btrfs_name_hash(name, name_len, &key.offset);
 	BUG_ON(ret);
-	btrfs_init_path(&path);
+	path = btrfs_alloc_path();
+	btrfs_init_path(path);
 	data_size = sizeof(*dir_item) + name_len;
-	ret = btrfs_insert_empty_item(trans, root, &path, &key, data_size);
+	ret = btrfs_insert_empty_item(trans, root, path, &key, data_size);
 	if (ret)
 		goto out;
 
-	dir_item = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]),
-				  path.slots[0],
+	dir_item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
+				  path->slots[0],
 				  struct btrfs_dir_item);
 	btrfs_set_dir_objectid(dir_item, objectid);
 	btrfs_set_dir_type(dir_item, type);
 	btrfs_set_dir_flags(dir_item, 0);
 	btrfs_set_dir_name_len(dir_item, name_len);
 	name_ptr = (char *)(dir_item + 1);
-	btrfs_memcpy(root, path.nodes[0]->b_data, name_ptr, name, name_len);
-	btrfs_mark_buffer_dirty(path.nodes[0]);
+	btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
+	btrfs_mark_buffer_dirty(path->nodes[0]);
 out:
-	btrfs_release_path(root, &path);
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
 	return ret;
 }
 
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 37b87e2..d785b72 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -15,7 +15,7 @@
 static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
 			 *root, u64 blocknr, u64 num_blocks)
 {
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	int ret;
 	struct btrfs_key key;
 	struct btrfs_leaf *l;
@@ -25,23 +25,26 @@
 
 	find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1,
 			 &ins);
-	btrfs_init_path(&path);
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	btrfs_init_path(path);
 	key.objectid = blocknr;
 	key.flags = 0;
 	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
 	key.offset = num_blocks;
-	ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, &path,
+	ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path,
 				0, 1);
 	if (ret != 0)
 		BUG();
 	BUG_ON(ret != 0);
-	l = btrfs_buffer_leaf(path.nodes[0]);
-	item = btrfs_item_ptr(l, path.slots[0], struct btrfs_extent_item);
+	l = btrfs_buffer_leaf(path->nodes[0]);
+	item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
 	refs = btrfs_extent_refs(item);
 	btrfs_set_extent_refs(item, refs + 1);
-	btrfs_mark_buffer_dirty(path.nodes[0]);
+	btrfs_mark_buffer_dirty(path->nodes[0]);
 
-	btrfs_release_path(root->fs_info->extent_root, &path);
+	btrfs_release_path(root->fs_info->extent_root, path);
+	btrfs_free_path(path);
 	finish_current_insert(trans, root->fs_info->extent_root);
 	del_pending_extents(trans, root->fs_info->extent_root);
 	return 0;
@@ -50,24 +53,27 @@
 static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
 			    *root, u64 blocknr, u64 num_blocks, u32 *refs)
 {
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	int ret;
 	struct btrfs_key key;
 	struct btrfs_leaf *l;
 	struct btrfs_extent_item *item;
-	btrfs_init_path(&path);
+
+	path = btrfs_alloc_path();
+	btrfs_init_path(path);
 	key.objectid = blocknr;
 	key.offset = num_blocks;
 	key.flags = 0;
 	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
-	ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, &path,
+	ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path,
 				0, 0);
 	if (ret != 0)
 		BUG();
-	l = btrfs_buffer_leaf(path.nodes[0]);
-	item = btrfs_item_ptr(l, path.slots[0], struct btrfs_extent_item);
+	l = btrfs_buffer_leaf(path->nodes[0]);
+	item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
 	*refs = btrfs_extent_refs(item);
-	btrfs_release_path(root->fs_info->extent_root, &path);
+	btrfs_release_path(root->fs_info->extent_root, path);
+	btrfs_free_path(path);
 	return 0;
 }
 
@@ -200,7 +206,7 @@
 static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
 			 *root, u64 blocknr, u64 num_blocks, int pin)
 {
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	struct btrfs_key key;
 	struct btrfs_fs_info *info = root->fs_info;
 	struct btrfs_root *extent_root = info->extent_root;
@@ -215,20 +221,22 @@
 	key.offset = num_blocks;
 
 	find_free_extent(trans, root, 0, 0, (u64)-1, &ins);
-	btrfs_init_path(&path);
-	ret = btrfs_search_slot(trans, extent_root, &key, &path, -1, 1);
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	btrfs_init_path(path);
+	ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1);
 	if (ret) {
 		printk("failed to find %Lu\n", key.objectid);
 		btrfs_print_tree(extent_root, extent_root->node);
 		printk("failed to find %Lu\n", key.objectid);
 		BUG();
 	}
-	ei = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), path.slots[0],
+	ei = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
 			    struct btrfs_extent_item);
 	BUG_ON(ei->refs == 0);
 	refs = btrfs_extent_refs(ei) - 1;
 	btrfs_set_extent_refs(ei, refs);
-	btrfs_mark_buffer_dirty(path.nodes[0]);
+	btrfs_mark_buffer_dirty(path->nodes[0]);
 	if (refs == 0) {
 		u64 super_blocks_used;
 
@@ -240,13 +248,14 @@
 		super_blocks_used = btrfs_super_blocks_used(info->disk_super);
 		btrfs_set_super_blocks_used(info->disk_super,
 					    super_blocks_used - num_blocks);
-		ret = btrfs_del_item(trans, extent_root, &path);
+		ret = btrfs_del_item(trans, extent_root, path);
 		if (extent_root->fs_info->last_insert.objectid > blocknr)
 			extent_root->fs_info->last_insert.objectid = blocknr;
 		if (ret)
 			BUG();
 	}
-	btrfs_release_path(extent_root, &path);
+	btrfs_release_path(extent_root, path);
+	btrfs_free_path(path);
 	finish_current_insert(trans, extent_root);
 	return ret;
 }
@@ -319,7 +328,7 @@
 			    *orig_root, u64 num_blocks, u64 search_start, u64
 			    search_end, struct btrfs_key *ins)
 {
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	struct btrfs_key key;
 	int ret;
 	u64 hole_size = 0;
@@ -339,24 +348,25 @@
 
 	ins->flags = 0;
 	btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
+	path = btrfs_alloc_path();
 
 check_failed:
-	btrfs_init_path(&path);
+	btrfs_init_path(path);
 	ins->objectid = search_start;
 	ins->offset = 0;
 	start_found = 0;
-	ret = btrfs_search_slot(trans, root, ins, &path, 0, 0);
+	ret = btrfs_search_slot(trans, root, ins, path, 0, 0);
 	if (ret < 0)
 		goto error;
 
-	if (path.slots[0] > 0)
-		path.slots[0]--;
+	if (path->slots[0] > 0)
+		path->slots[0]--;
 
 	while (1) {
-		l = btrfs_buffer_leaf(path.nodes[0]);
-		slot = path.slots[0];
+		l = btrfs_buffer_leaf(path->nodes[0]);
+		slot = path->slots[0];
 		if (slot >= btrfs_header_nritems(&l->header)) {
-			ret = btrfs_next_leaf(root, &path);
+			ret = btrfs_next_leaf(root, path);
 			if (ret == 0)
 				continue;
 			if (ret < 0)
@@ -387,14 +397,14 @@
 		}
 		start_found = 1;
 		last_block = key.objectid + key.offset;
-		path.slots[0]++;
+		path->slots[0]++;
 	}
 	// FIXME -ENOSPC
 check_pending:
 	/* we have to make sure we didn't find an extent that has already
 	 * been allocated by the map tree or the original allocation
 	 */
-	btrfs_release_path(root, &path);
+	btrfs_release_path(root, path);
 	BUG_ON(ins->objectid < search_start);
 	for (test_block = ins->objectid;
 	     test_block < ins->objectid + total_needed; test_block++) {
@@ -410,9 +420,11 @@
 	root->fs_info->current_insert.flags = 0;
 	root->fs_info->last_insert.objectid = ins->objectid;
 	ins->offset = num_blocks;
+	btrfs_free_path(path);
 	return 0;
 error:
-	btrfs_release_path(root, &path);
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
 	return ret;
 }
 
@@ -533,6 +545,8 @@
 	int ret;
 	u32 refs;
 
+	WARN_ON(*level < 0);
+	WARN_ON(*level >= BTRFS_MAX_LEVEL);
 	ret = lookup_block_ref(trans, root, path->nodes[*level]->b_blocknr,
 			       1, &refs);
 	BUG_ON(ret);
@@ -542,6 +556,8 @@
 	 * walk down to the last node level and free all the leaves
 	 */
 	while(*level >= 0) {
+		WARN_ON(*level < 0);
+		WARN_ON(*level >= BTRFS_MAX_LEVEL);
 		cur = path->nodes[*level];
 		if (btrfs_header_level(btrfs_buffer_header(cur)) != *level)
 			WARN_ON(1);
@@ -564,6 +580,7 @@
 			continue;
 		}
 		next = read_tree_block(root, blocknr);
+		WARN_ON(*level <= 0);
 		if (path->nodes[*level-1])
 			btrfs_block_release(root, path->nodes[*level-1]);
 		path->nodes[*level-1] = next;
@@ -571,6 +588,8 @@
 		path->slots[*level] = 0;
 	}
 out:
+	WARN_ON(*level < 0);
+	WARN_ON(*level >= BTRFS_MAX_LEVEL);
 	ret = btrfs_free_extent(trans, root,
 				path->nodes[*level]->b_blocknr, 1, 1);
 	btrfs_block_release(root, path->nodes[*level]);
@@ -622,33 +641,36 @@
 	int ret = 0;
 	int wret;
 	int level;
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	int i;
 	int orig_level;
 
-	btrfs_init_path(&path);
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	btrfs_init_path(path);
 
 	level = btrfs_header_level(btrfs_buffer_header(snap));
 	orig_level = level;
-	path.nodes[level] = snap;
-	path.slots[level] = 0;
+	path->nodes[level] = snap;
+	path->slots[level] = 0;
 	while(1) {
-		wret = walk_down_tree(trans, root, &path, &level);
+		wret = walk_down_tree(trans, root, path, &level);
 		if (wret > 0)
 			break;
 		if (wret < 0)
 			ret = wret;
 
-		wret = walk_up_tree(trans, root, &path, &level);
+		wret = walk_up_tree(trans, root, path, &level);
 		if (wret > 0)
 			break;
 		if (wret < 0)
 			ret = wret;
 	}
 	for (i = 0; i <= orig_level; i++) {
-		if (path.nodes[i]) {
-			btrfs_block_release(root, path.nodes[i]);
+		if (path->nodes[i]) {
+			btrfs_block_release(root, path->nodes[i]);
 		}
 	}
+	btrfs_free_path(path);
 	return ret;
 }
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index c3992b7..e7510ac 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -13,9 +13,11 @@
 	int ret = 0;
 	struct btrfs_file_extent_item *item;
 	struct btrfs_key file_key;
-	struct btrfs_path path;
+	struct btrfs_path *path;
 
-	btrfs_init_path(&path);
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	btrfs_init_path(path);
 	ret = btrfs_alloc_extent(trans, root, num_blocks, hint_block,
 				 (u64)-1, objectid, &ins);
 	BUG_ON(ret);
@@ -24,19 +26,20 @@
 	file_key.flags = 0;
 	btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
 
-	ret = btrfs_insert_empty_item(trans, root, &path, &file_key,
+	ret = btrfs_insert_empty_item(trans, root, path, &file_key,
 				      sizeof(*item));
 	BUG_ON(ret);
-	item = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), path.slots[0],
+	item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
 			      struct btrfs_file_extent_item);
 	btrfs_set_file_extent_disk_blocknr(item, ins.objectid);
 	btrfs_set_file_extent_disk_num_blocks(item, ins.offset);
 	btrfs_set_file_extent_offset(item, 0);
 	btrfs_set_file_extent_num_blocks(item, ins.offset);
 	btrfs_set_file_extent_generation(item, trans->transid);
-	btrfs_mark_buffer_dirty(path.nodes[0]);
+	btrfs_mark_buffer_dirty(path->nodes[0]);
 	*result = ins.objectid;
-	btrfs_release_path(root, &path);
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
 	return 0;
 }
 
@@ -65,25 +68,28 @@
 {
 	int ret;
 	struct btrfs_key file_key;
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	struct btrfs_csum_item *item;
 
-	btrfs_init_path(&path);
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	btrfs_init_path(path);
 	file_key.objectid = objectid;
 	file_key.offset = offset;
 	file_key.flags = 0;
 	btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
-	ret = btrfs_insert_empty_item(trans, root, &path, &file_key,
+	ret = btrfs_insert_empty_item(trans, root, path, &file_key,
 				      BTRFS_CSUM_SIZE);
 	if (ret != 0 && ret != -EEXIST)
 		goto fail;
-	item = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), path.slots[0],
+	item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
 			      struct btrfs_csum_item);
 	ret = 0;
 	ret = btrfs_csum_data(root, data, len, item->csum);
-	btrfs_mark_buffer_dirty(path.nodes[0]);
+	btrfs_mark_buffer_dirty(path->nodes[0]);
 fail:
-	btrfs_release_path(root, &path);
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
 	return ret;
 }
 
@@ -93,19 +99,21 @@
 {
 	int ret;
 	struct btrfs_key file_key;
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	struct btrfs_csum_item *item;
 	char result[BTRFS_CSUM_SIZE];
 
-	btrfs_init_path(&path);
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	btrfs_init_path(path);
 	file_key.objectid = objectid;
 	file_key.offset = offset;
 	file_key.flags = 0;
 	btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
-	ret = btrfs_search_slot(NULL, root, &file_key, &path, 0, 0);
+	ret = btrfs_search_slot(NULL, root, &file_key, path, 0, 0);
 	if (ret)
 		goto fail;
-	item = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), path.slots[0],
+	item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
 			      struct btrfs_csum_item);
 	ret = 0;
 	ret = btrfs_csum_data(root, data, len, result);
@@ -113,7 +121,8 @@
 	if (memcmp(result, item->csum, BTRFS_CSUM_SIZE))
 		ret = 1;
 fail:
-	btrfs_release_path(root, &path);
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
 	return ret;
 }
 
diff --git a/fs/btrfs/inode-item.c b/fs/btrfs/inode-item.c
index 8d8c26a..6bfa980 100644
--- a/fs/btrfs/inode-item.c
+++ b/fs/btrfs/inode-item.c
@@ -7,7 +7,7 @@
 		       *root, u64 objectid, struct btrfs_inode_item
 		       *inode_item)
 {
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	struct btrfs_key key;
 	int ret;
 	key.objectid = objectid;
@@ -15,10 +15,13 @@
 	btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
 	key.offset = 0;
 
-	btrfs_init_path(&path);
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	btrfs_init_path(path);
 	ret = btrfs_insert_item(trans, root, &key, inode_item,
 				sizeof(*inode_item));
-	btrfs_release_path(root, &path);
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
 	return ret;
 }
 
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c
index f37dab8..ddc1c13 100644
--- a/fs/btrfs/root-tree.c
+++ b/fs/btrfs/root-tree.c
@@ -6,7 +6,7 @@
 int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
 			struct btrfs_root_item *item, struct btrfs_key *key)
 {
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	struct btrfs_key search_key;
 	struct btrfs_leaf *l;
 	int ret;
@@ -16,14 +16,16 @@
 	search_key.flags = (u32)-1;
 	search_key.offset = (u32)-1;
 
-	btrfs_init_path(&path);
-	ret = btrfs_search_slot(NULL, root, &search_key, &path, 0, 0);
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	btrfs_init_path(path);
+	ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
 	if (ret < 0)
 		goto out;
 	BUG_ON(ret == 0);
-	l = btrfs_buffer_leaf(path.nodes[0]);
-	BUG_ON(path.slots[0] == 0);
-	slot = path.slots[0] - 1;
+	l = btrfs_buffer_leaf(path->nodes[0]);
+	BUG_ON(path->slots[0] == 0);
+	slot = path->slots[0] - 1;
 	if (btrfs_disk_key_objectid(&l->items[slot].key) != objectid) {
 		ret = 1;
 		goto out;
@@ -31,9 +33,10 @@
 	memcpy(item, btrfs_item_ptr(l, slot, struct btrfs_root_item),
 		sizeof(*item));
 	btrfs_disk_key_to_cpu(key, &l->items[slot].key);
-	btrfs_release_path(root, &path);
 	ret = 0;
 out:
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
 	return ret;
 }
 
@@ -41,24 +44,27 @@
 		      *root, struct btrfs_key *key, struct btrfs_root_item
 		      *item)
 {
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	struct btrfs_leaf *l;
 	int ret;
 	int slot;
 	struct btrfs_root_item *update_item;
 
-	btrfs_init_path(&path);
-	ret = btrfs_search_slot(trans, root, key, &path, 0, 1);
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	btrfs_init_path(path);
+	ret = btrfs_search_slot(trans, root, key, path, 0, 1);
 	if (ret < 0)
 		goto out;
 	BUG_ON(ret != 0);
-	l = btrfs_buffer_leaf(path.nodes[0]);
-	slot = path.slots[0];
+	l = btrfs_buffer_leaf(path->nodes[0]);
+	slot = path->slots[0];
 	update_item = btrfs_item_ptr(l, slot, struct btrfs_root_item);
 	btrfs_memcpy(root, l, update_item, item, sizeof(*item));
-	btrfs_mark_buffer_dirty(path.nodes[0]);
+	btrfs_mark_buffer_dirty(path->nodes[0]);
 out:
-	btrfs_release_path(root, &path);
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
 	return ret;
 }
 
@@ -75,16 +81,19 @@
 int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 		   struct btrfs_key *key)
 {
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	int ret;
 
-	btrfs_init_path(&path);
-	ret = btrfs_search_slot(trans, root, key, &path, -1, 1);
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	btrfs_init_path(path);
+	ret = btrfs_search_slot(trans, root, key, path, -1, 1);
 	if (ret < 0)
 		goto out;
 	BUG_ON(ret != 0);
-	ret = btrfs_del_item(trans, root, &path);
+	ret = btrfs_del_item(trans, root, path);
 out:
-	btrfs_release_path(root, &path);
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
 	return ret;
 }
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 6969b67..c260fca 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -35,25 +35,27 @@
 
 static void btrfs_read_locked_inode(struct inode *inode)
 {
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	struct btrfs_inode_item *inode_item;
 	struct btrfs_root *root = btrfs_sb(inode->i_sb);
 	int ret;
 
-	btrfs_init_path(&path);
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	btrfs_init_path(path);
 	mutex_lock(&root->fs_info->fs_mutex);
 
 	check_inode(inode);
-	ret = btrfs_lookup_inode(NULL, root, &path, inode->i_ino, 0);
+	ret = btrfs_lookup_inode(NULL, root, path, inode->i_ino, 0);
 	if (ret) {
-		btrfs_release_path(root, &path);
+		btrfs_release_path(root, path);
 		mutex_unlock(&root->fs_info->fs_mutex);
 		make_bad_inode(inode);
 		return;
 	}
 	check_inode(inode);
-	inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]),
-				  path.slots[0],
+	inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
+				  path->slots[0],
 				  struct btrfs_inode_item);
 
 	inode->i_mode = btrfs_inode_mode(inode_item);
@@ -69,7 +71,11 @@
 	inode->i_ctime.tv_nsec = btrfs_timespec_nsec(&inode_item->ctime);
 	inode->i_blocks = btrfs_inode_nblocks(inode_item);
 	inode->i_generation = btrfs_inode_generation(inode_item);
-	btrfs_release_path(root, &path);
+
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
+	inode_item = NULL;
+
 	mutex_unlock(&root->fs_info->fs_mutex);
 	check_inode(inode);
 	switch (inode->i_mode & S_IFMT) {
@@ -101,15 +107,17 @@
 			      struct inode *dir,
 			      struct dentry *dentry)
 {
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	const char *name = dentry->d_name.name;
 	int name_len = dentry->d_name.len;
 	int ret;
 	u64 objectid;
 	struct btrfs_dir_item *di;
 
-	btrfs_init_path(&path);
-	ret = btrfs_lookup_dir_item(trans, root, &path, dir->i_ino,
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	btrfs_init_path(path);
+	ret = btrfs_lookup_dir_item(trans, root, path, dir->i_ino,
 				    name, name_len, -1);
 	if (ret < 0)
 		goto err;
@@ -117,15 +125,16 @@
 		ret = -ENOENT;
 		goto err;
 	}
-	di = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), path.slots[0],
+	di = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
 			    struct btrfs_dir_item);
 	objectid = btrfs_dir_objectid(di);
 
-	ret = btrfs_del_item(trans, root, &path);
+	ret = btrfs_del_item(trans, root, path);
 	BUG_ON(ret);
 	dentry->d_inode->i_ctime = dir->i_ctime;
 err:
-	btrfs_release_path(root, &path);
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
 	if (ret == 0)
 		inode_dec_link_count(dentry->d_inode);
 	return ret;
@@ -152,30 +161,32 @@
 	int err;
 	int ret;
 	struct btrfs_root *root = btrfs_sb(dir->i_sb);
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	struct btrfs_key key;
 	struct btrfs_trans_handle *trans;
 	struct btrfs_disk_key *found_key;
 	struct btrfs_leaf *leaf;
 
-	btrfs_init_path(&path);
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	btrfs_init_path(path);
 	mutex_lock(&root->fs_info->fs_mutex);
 	trans = btrfs_start_transaction(root, 1);
 	key.objectid = inode->i_ino;
 	key.offset = (u64)-1;
 	key.flags = 0;
 	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
-	ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
+	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
 	if (ret < 0) {
 		err = ret;
 		goto out;
 	}
 
 	BUG_ON(ret == 0);
-	BUG_ON(path.slots[0] == 0);
-	path.slots[0]--;
-	leaf = btrfs_buffer_leaf(path.nodes[0]);
-	found_key = &leaf->items[path.slots[0]].key;
+	BUG_ON(path->slots[0] == 0);
+	path->slots[0]--;
+	leaf = btrfs_buffer_leaf(path->nodes[0]);
+	found_key = &leaf->items[path->slots[0]].key;
 	if (btrfs_disk_key_objectid(found_key) != inode->i_ino) {
 		err = -ENOENT;
 		goto out;
@@ -185,11 +196,11 @@
 		err = -ENOTEMPTY;
 		goto out;
 	}
-	ret = btrfs_del_item(trans, root, &path);
+	ret = btrfs_del_item(trans, root, path);
 	BUG_ON(ret);
-	btrfs_release_path(root, &path);
+	btrfs_release_path(root, path);
 	key.offset = 1;
-	ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
+	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
 	if (ret < 0) {
 		err = ret;
 		goto out;
@@ -198,12 +209,13 @@
 		err = -ENOTEMPTY;
 		goto out;
 	}
-	ret = btrfs_del_item(trans, root, &path);
+	ret = btrfs_del_item(trans, root, path);
 	if (ret) {
 		err = ret;
 		goto out;
 	}
-	btrfs_release_path(root, &path);
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
 
 	/* now the directory is empty */
 	err = btrfs_unlink_trans(trans, root, dir, dentry);
@@ -223,33 +235,36 @@
 			    struct inode *inode)
 {
 	u64 objectid = inode->i_ino;
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	struct btrfs_inode_map_item *map;
 	struct btrfs_key stat_data_key;
 	int ret;
+
 	clear_inode(inode);
-	btrfs_init_path(&path);
-	ret = btrfs_lookup_inode_map(trans, root, &path, objectid, -1);
+
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	btrfs_init_path(path);
+	ret = btrfs_lookup_inode_map(trans, root, path, objectid, -1);
 	if (ret) {
 		if (ret > 0)
 			ret = -ENOENT;
-		btrfs_release_path(root, &path);
 		goto error;
 	}
-	map = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), path.slots[0],
+	map = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
 			    struct btrfs_inode_map_item);
 	btrfs_disk_key_to_cpu(&stat_data_key, &map->key);
-	ret = btrfs_del_item(trans, root->fs_info->inode_root, &path);
+	ret = btrfs_del_item(trans, root->fs_info->inode_root, path);
 	BUG_ON(ret);
-	btrfs_release_path(root, &path);
-	btrfs_init_path(&path);
+	btrfs_release_path(root, path);
 
-	ret = btrfs_lookup_inode(trans, root, &path, objectid, -1);
+	ret = btrfs_lookup_inode(trans, root, path, objectid, -1);
 	BUG_ON(ret);
-	ret = btrfs_del_item(trans, root, &path);
+	ret = btrfs_del_item(trans, root, path);
 	BUG_ON(ret);
-	btrfs_release_path(root, &path);
 error:
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
 	return ret;
 }
 
@@ -258,7 +273,7 @@
 				   struct inode *inode)
 {
 	int ret;
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	struct btrfs_key key;
 	struct btrfs_disk_key *found_key;
 	struct btrfs_leaf *leaf;
@@ -267,24 +282,25 @@
 	u64 extent_num_blocks = 0;
 	int found_extent;
 
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
 	/* FIXME, add redo link to tree so we don't leak on crash */
 	key.objectid = inode->i_ino;
 	key.offset = (u64)-1;
 	key.flags = 0;
 	btrfs_set_key_type(&key, BTRFS_CSUM_ITEM_KEY);
 	while(1) {
-		btrfs_init_path(&path);
-		ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
+		btrfs_init_path(path);
+		ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
 		if (ret < 0) {
-			btrfs_release_path(root, &path);
 			goto error;
 		}
 		if (ret > 0) {
-			BUG_ON(path.slots[0] == 0);
-			path.slots[0]--;
+			BUG_ON(path->slots[0] == 0);
+			path->slots[0]--;
 		}
-		leaf = btrfs_buffer_leaf(path.nodes[0]);
-		found_key = &leaf->items[path.slots[0]].key;
+		leaf = btrfs_buffer_leaf(path->nodes[0]);
+		found_key = &leaf->items[path->slots[0]].key;
 		if (btrfs_disk_key_objectid(found_key) != inode->i_ino)
 			break;
 		if (btrfs_disk_key_type(found_key) != BTRFS_CSUM_ITEM_KEY &&
@@ -293,8 +309,8 @@
 		if (btrfs_disk_key_offset(found_key) < inode->i_size)
 			break;
 		if (btrfs_disk_key_type(found_key) == BTRFS_EXTENT_DATA_KEY) {
-			fi = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]),
-					    path.slots[0],
+			fi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
+					    path->slots[0],
 					    struct btrfs_file_extent_item);
 			extent_start = btrfs_file_extent_disk_blocknr(fi);
 			extent_num_blocks =
@@ -305,18 +321,19 @@
 		} else {
 			found_extent = 0;
 		}
-		ret = btrfs_del_item(trans, root, &path);
+		ret = btrfs_del_item(trans, root, path);
 		BUG_ON(ret);
-		btrfs_release_path(root, &path);
+		btrfs_release_path(root, path);
 		if (found_extent) {
 			ret = btrfs_free_extent(trans, root, extent_start,
 						extent_num_blocks, 0);
 			BUG_ON(ret);
 		}
 	}
-	btrfs_release_path(root, &path);
 	ret = 0;
 error:
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
 	return ret;
 }
 
@@ -351,23 +368,26 @@
 	const char *name = dentry->d_name.name;
 	int namelen = dentry->d_name.len;
 	struct btrfs_dir_item *di;
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	struct btrfs_root *root = btrfs_sb(dir->i_sb);
 	int ret;
 
-	btrfs_init_path(&path);
-	ret = btrfs_lookup_dir_item(NULL, root, &path, dir->i_ino, name,
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	btrfs_init_path(path);
+	ret = btrfs_lookup_dir_item(NULL, root, path, dir->i_ino, name,
 				    namelen, 0);
-	if (ret || !btrfs_match_dir_item_name(root, &path, name, namelen)) {
+	if (ret || !btrfs_match_dir_item_name(root, path, name, namelen)) {
 		*ino = 0;
 		ret = 0;
 		goto out;
 	}
-	di = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), path.slots[0],
+	di = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
 			    struct btrfs_dir_item);
 	*ino = btrfs_dir_objectid(di);
 out:
-	btrfs_release_path(root, &path);
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
 	check_inode(dir);
 	return ret;
 }
@@ -405,7 +425,7 @@
 	struct btrfs_item *item;
 	struct btrfs_dir_item *di;
 	struct btrfs_key key;
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	int ret;
 	u32 nritems;
 	struct btrfs_leaf *leaf;
@@ -419,27 +439,28 @@
 	key.flags = 0;
 	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
 	key.offset = filp->f_pos;
-	btrfs_init_path(&path);
-	ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
+	path = btrfs_alloc_path();
+	btrfs_init_path(path);
+	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
 	if (ret < 0) {
 		goto err;
 	}
 	advance = 0;
 	while(1) {
-		leaf = btrfs_buffer_leaf(path.nodes[0]);
+		leaf = btrfs_buffer_leaf(path->nodes[0]);
 		nritems = btrfs_header_nritems(&leaf->header);
-		slot = path.slots[0];
+		slot = path->slots[0];
 		if (advance || slot >= nritems) {
 			if (slot >= nritems -1) {
-				ret = btrfs_next_leaf(root, &path);
+				ret = btrfs_next_leaf(root, path);
 				if (ret)
 					break;
-				leaf = btrfs_buffer_leaf(path.nodes[0]);
+				leaf = btrfs_buffer_leaf(path->nodes[0]);
 				nritems = btrfs_header_nritems(&leaf->header);
-				slot = path.slots[0];
+				slot = path->slots[0];
 			} else {
 				slot++;
-				path.slots[0]++;
+				path->slots[0]++;
 			}
 		}
 		advance = 1;
@@ -465,7 +486,8 @@
 	}
 	ret = 0;
 err:
-	btrfs_release_path(root, &path);
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
 	mutex_unlock(&root->fs_info->fs_mutex);
 	return ret;
 }
@@ -548,26 +570,29 @@
 			      struct inode *inode)
 {
 	struct btrfs_inode_item *inode_item;
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	int ret;
 
-	btrfs_init_path(&path);
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	btrfs_init_path(path);
 
-	ret = btrfs_lookup_inode(trans, root, &path, inode->i_ino, 1);
+	ret = btrfs_lookup_inode(trans, root, path, inode->i_ino, 1);
 	if (ret) {
 		if (ret > 0)
 			ret = -ENOENT;
 		goto failed;
 	}
 
-	inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]),
-				  path.slots[0],
+	inode_item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
+				  path->slots[0],
 				  struct btrfs_inode_item);
 
 	fill_inode_item(inode_item, inode);
-	btrfs_mark_buffer_dirty(path.nodes[0]);
+	btrfs_mark_buffer_dirty(path->nodes[0]);
 failed:
-	btrfs_release_path(root, &path);
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
 	check_inode(inode);
 	return 0;
 }
@@ -799,38 +824,39 @@
 	u64 extent_start = 0;
 	u64 extent_end = 0;
 	u64 objectid = inode->i_ino;
-	struct btrfs_path path;
+	struct btrfs_path *path;
 	struct btrfs_root *root = btrfs_sb(inode->i_sb);
 	struct btrfs_trans_handle *trans = NULL;
 	struct btrfs_file_extent_item *item;
 	struct btrfs_leaf *leaf;
 	struct btrfs_disk_key *found_key;
 
-	btrfs_init_path(&path);
+	path = btrfs_alloc_path();
+	BUG_ON(!path);
+	btrfs_init_path(path);
 	if (create)
 		trans = btrfs_start_transaction(root, 1);
 
 
-	ret = btrfs_lookup_file_extent(trans, root, &path,
+	ret = btrfs_lookup_file_extent(trans, root, path,
 				       inode->i_ino,
 				       iblock << inode->i_blkbits, 0);
 	if (ret < 0) {
-		btrfs_release_path(root, &path);
 		err = ret;
 		goto out;
 	}
 
 	if (ret != 0) {
-		if (path.slots[0] == 0) {
-			btrfs_release_path(root, &path);
+		if (path->slots[0] == 0) {
+			btrfs_release_path(root, path);
 			goto allocate;
 		}
-		path.slots[0]--;
+		path->slots[0]--;
 	}
 
-	item = btrfs_item_ptr(btrfs_buffer_leaf(path.nodes[0]), path.slots[0],
+	item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
 			      struct btrfs_file_extent_item);
-	leaf = btrfs_buffer_leaf(path.nodes[0]);
+	leaf = btrfs_buffer_leaf(path->nodes[0]);
 	blocknr = btrfs_file_extent_disk_blocknr(item);
 	blocknr += btrfs_file_extent_offset(item);
 
@@ -838,25 +864,23 @@
 	if (ret == 0) {
 		err = 0;
 		map_bh(result, inode->i_sb, blocknr);
-		btrfs_release_path(root, &path);
 		goto out;
 	}
 
 	/* are we inside the extent that was found? */
-	found_key = &leaf->items[path.slots[0]].key;
+	found_key = &leaf->items[path->slots[0]].key;
 	if (btrfs_disk_key_objectid(found_key) != objectid ||
 	    btrfs_disk_key_type(found_key) != BTRFS_EXTENT_DATA_KEY) {
 		extent_end = 0;
 		extent_start = 0;
-		btrfs_release_path(root, &path);
+		btrfs_release_path(root, path);
 		goto allocate;
 	}
 
-	extent_start = btrfs_disk_key_offset(&leaf->items[path.slots[0]].key);
+	extent_start = btrfs_disk_key_offset(&leaf->items[path->slots[0]].key);
 	extent_start = extent_start >> inode->i_blkbits;
 	extent_start += btrfs_file_extent_offset(item);
 	extent_end = extent_start + btrfs_file_extent_num_blocks(item);
-	btrfs_release_path(root, &path);
 	if (iblock >= extent_start && iblock < extent_end) {
 		err = 0;
 		map_bh(result, inode->i_sb, blocknr + iblock - extent_start);
@@ -880,6 +904,8 @@
 	map_bh(result, inode->i_sb, blocknr);
 
 out:
+	btrfs_release_path(root, path);
+	btrfs_free_path(path);
 	if (trans)
 		btrfs_end_transaction(trans, root);
 	return err;