diff options
Diffstat (limited to 'fs/btrfs/backref.c')
| -rw-r--r-- | fs/btrfs/backref.c | 281 | 
1 files changed, 160 insertions, 121 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 0552a599b28..e25564bfcb4 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -66,6 +66,16 @@ static int check_extent_in_eb(struct btrfs_key *key, struct extent_buffer *eb,  	return 0;  } +static void free_inode_elem_list(struct extent_inode_elem *eie) +{ +	struct extent_inode_elem *eie_next; + +	for (; eie; eie = eie_next) { +		eie_next = eie->next; +		kfree(eie); +	} +} +  static int find_extent_in_eb(struct extent_buffer *eb, u64 wanted_disk_byte,  				u64 extent_item_pos,  				struct extent_inode_elem **eie) @@ -185,6 +195,9 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id,  {  	struct __prelim_ref *ref; +	if (root_id == BTRFS_DATA_RELOC_TREE_OBJECTID) +		return 0; +  	ref = kmem_cache_alloc(btrfs_prelim_ref_cache, gfp_mask);  	if (!ref)  		return -ENOMEM; @@ -206,18 +219,20 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id,  }  static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, -				struct ulist *parents, int level, -				struct btrfs_key *key_for_search, u64 time_seq, -				u64 wanted_disk_byte, -				const u64 *extent_item_pos) +			   struct ulist *parents, struct __prelim_ref *ref, +			   int level, u64 time_seq, const u64 *extent_item_pos, +			   u64 total_refs)  {  	int ret = 0;  	int slot;  	struct extent_buffer *eb;  	struct btrfs_key key; +	struct btrfs_key *key_for_search = &ref->key_for_search;  	struct btrfs_file_extent_item *fi;  	struct extent_inode_elem *eie = NULL, *old = NULL;  	u64 disk_byte; +	u64 wanted_disk_byte = ref->wanted_disk_byte; +	u64 count = 0;  	if (level != 0) {  		eb = path->nodes[level]; @@ -235,7 +250,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,  	if (path->slots[0] >= btrfs_header_nritems(path->nodes[0]))  		ret = btrfs_next_old_leaf(root, path, time_seq); -	while (!ret) { +	while (!ret && count < total_refs) {  		eb = path->nodes[0];  		slot = path->slots[0]; @@ -251,6 +266,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,  		if (disk_byte == wanted_disk_byte) {  			eie = NULL;  			old = NULL; +			count++;  			if (extent_item_pos) {  				ret = check_extent_in_eb(&key, eb, fi,  						*extent_item_pos, @@ -270,6 +286,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,  					old = old->next;  				old->next = eie;  			} +			eie = NULL;  		}  next:  		ret = btrfs_next_old_item(root, path, time_seq); @@ -277,6 +294,8 @@ next:  	if (ret > 0)  		ret = 0; +	else if (ret < 0) +		free_inode_elem_list(eie);  	return ret;  } @@ -288,7 +307,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,  				  struct btrfs_path *path, u64 time_seq,  				  struct __prelim_ref *ref,  				  struct ulist *parents, -				  const u64 *extent_item_pos) +				  const u64 *extent_item_pos, u64 total_refs)  {  	struct btrfs_root *root;  	struct btrfs_key root_key; @@ -296,23 +315,37 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,  	int ret = 0;  	int root_level;  	int level = ref->level; +	int index;  	root_key.objectid = ref->root_id;  	root_key.type = BTRFS_ROOT_ITEM_KEY;  	root_key.offset = (u64)-1; + +	index = srcu_read_lock(&fs_info->subvol_srcu); +  	root = btrfs_read_fs_root_no_name(fs_info, &root_key);  	if (IS_ERR(root)) { +		srcu_read_unlock(&fs_info->subvol_srcu, index);  		ret = PTR_ERR(root);  		goto out;  	} -	root_level = btrfs_old_root_level(root, time_seq); +	if (path->search_commit_root) +		root_level = btrfs_header_level(root->commit_root); +	else +		root_level = btrfs_old_root_level(root, time_seq); -	if (root_level + 1 == level) +	if (root_level + 1 == level) { +		srcu_read_unlock(&fs_info->subvol_srcu, index);  		goto out; +	}  	path->lowest_level = level;  	ret = btrfs_search_old_slot(root, &ref->key_for_search, path, time_seq); + +	/* root node has been locked, we can release @subvol_srcu safely here */ +	srcu_read_unlock(&fs_info->subvol_srcu, index); +  	pr_debug("search slot in root %llu (level %d, ref count %d) returned "  		 "%d for key (%llu %u %llu)\n",  		 ref->root_id, level, ref->count, ret, @@ -323,8 +356,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,  	eb = path->nodes[level];  	while (!eb) { -		if (!level) { -			WARN_ON(1); +		if (WARN_ON(!level)) {  			ret = 1;  			goto out;  		} @@ -332,9 +364,8 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,  		eb = path->nodes[level];  	} -	ret = add_all_parents(root, path, parents, level, &ref->key_for_search, -				time_seq, ref->wanted_disk_byte, -				extent_item_pos); +	ret = add_all_parents(root, path, parents, ref, level, time_seq, +			      extent_item_pos, total_refs);  out:  	path->lowest_level = 0;  	btrfs_release_path(path); @@ -347,7 +378,7 @@ out:  static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,  				   struct btrfs_path *path, u64 time_seq,  				   struct list_head *head, -				   const u64 *extent_item_pos) +				   const u64 *extent_item_pos, u64 total_refs)  {  	int err;  	int ret = 0; @@ -373,11 +404,18 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,  		if (ref->count == 0)  			continue;  		err = __resolve_indirect_ref(fs_info, path, time_seq, ref, -					     parents, extent_item_pos); -		if (err == -ENOMEM) -			goto out; -		if (err) +					     parents, extent_item_pos, +					     total_refs); +		/* +		 * we can only tolerate ENOENT,otherwise,we should catch error +		 * and return directly. +		 */ +		if (err == -ENOENT) {  			continue; +		} else if (err) { +			ret = err; +			goto out; +		}  		/* we put the first parent into the ref at hand */  		ULIST_ITER_INIT(&uiter); @@ -524,7 +562,7 @@ static void __merge_refs(struct list_head *head, int mode)   * smaller or equal that seq to the list   */  static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, -			      struct list_head *prefs) +			      struct list_head *prefs, u64 *total_refs)  {  	struct btrfs_delayed_extent_op *extent_op = head->extent_op;  	struct rb_node *n = &head->node.rb_node; @@ -536,14 +574,13 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,  	if (extent_op && extent_op->update_key)  		btrfs_disk_key_to_cpu(&op_key, &extent_op->key); -	while ((n = rb_prev(n))) { +	spin_lock(&head->lock); +	n = rb_first(&head->ref_root); +	while (n) {  		struct btrfs_delayed_ref_node *node;  		node = rb_entry(n, struct btrfs_delayed_ref_node,  				rb_node); -		if (node->bytenr != head->node.bytenr) -			break; -		WARN_ON(node->is_head); - +		n = rb_next(n);  		if (node->seq > seq)  			continue; @@ -561,6 +598,7 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,  		default:  			BUG_ON(1);  		} +		*total_refs += (node->ref_mod * sgn);  		switch (node->type) {  		case BTRFS_TREE_BLOCK_REF_KEY: {  			struct btrfs_delayed_tree_ref *ref; @@ -610,10 +648,10 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,  			WARN_ON(1);  		}  		if (ret) -			return ret; +			break;  	} - -	return 0; +	spin_unlock(&head->lock); +	return ret;  }  /* @@ -621,7 +659,8 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,   */  static int __add_inline_refs(struct btrfs_fs_info *fs_info,  			     struct btrfs_path *path, u64 bytenr, -			     int *info_level, struct list_head *prefs) +			     int *info_level, struct list_head *prefs, +			     u64 *total_refs)  {  	int ret = 0;  	int slot; @@ -645,6 +684,7 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info,  	ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item);  	flags = btrfs_extent_flags(leaf, ei); +	*total_refs += btrfs_extent_refs(leaf, ei);  	btrfs_item_key_to_cpu(leaf, &found_key, slot);  	ptr = (unsigned long)(ei + 1); @@ -826,6 +866,8 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,  	struct list_head prefs_delayed;  	struct list_head prefs;  	struct __prelim_ref *ref; +	struct extent_inode_elem *eie = NULL; +	u64 total_refs = 0;  	INIT_LIST_HEAD(&prefs);  	INIT_LIST_HEAD(&prefs_delayed); @@ -840,8 +882,10 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,  	path = btrfs_alloc_path();  	if (!path)  		return -ENOMEM; -	if (!trans) +	if (!trans) {  		path->search_commit_root = 1; +		path->skip_locking = 1; +	}  	/*  	 * grab both a lock on the path and a lock on the delayed ref head. @@ -856,7 +900,11 @@ again:  		goto out;  	BUG_ON(ret == 0); +#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS +	if (trans && likely(trans->type != __TRANS_DUMMY)) { +#else  	if (trans) { +#endif  		/*  		 * look if there are updates for this ref queued and lock the  		 * head @@ -880,15 +928,15 @@ again:  				btrfs_put_delayed_ref(&head->node);  				goto again;  			} +			spin_unlock(&delayed_refs->lock);  			ret = __add_delayed_refs(head, time_seq, -						 &prefs_delayed); +						 &prefs_delayed, &total_refs);  			mutex_unlock(&head->mutex); -			if (ret) { -				spin_unlock(&delayed_refs->lock); +			if (ret)  				goto out; -			} +		} else { +			spin_unlock(&delayed_refs->lock);  		} -		spin_unlock(&delayed_refs->lock);  	}  	if (path->slots[0]) { @@ -903,7 +951,8 @@ again:  		    (key.type == BTRFS_EXTENT_ITEM_KEY ||  		     key.type == BTRFS_METADATA_ITEM_KEY)) {  			ret = __add_inline_refs(fs_info, path, bytenr, -						&info_level, &prefs); +						&info_level, &prefs, +						&total_refs);  			if (ret)  				goto out;  			ret = __add_keyed_refs(fs_info, path, bytenr, @@ -923,7 +972,7 @@ again:  	__merge_refs(&prefs, 1);  	ret = __resolve_indirect_refs(fs_info, path, time_seq, &prefs, -				      extent_item_pos); +				      extent_item_pos, total_refs);  	if (ret)  		goto out; @@ -932,19 +981,19 @@ again:  	while (!list_empty(&prefs)) {  		ref = list_first_entry(&prefs, struct __prelim_ref, list);  		WARN_ON(ref->count < 0); -		if (ref->count && ref->root_id && ref->parent == 0) { +		if (roots && ref->count && ref->root_id && ref->parent == 0) {  			/* no parent == root of tree */  			ret = ulist_add(roots, ref->root_id, 0, GFP_NOFS);  			if (ret < 0)  				goto out;  		}  		if (ref->count && ref->parent) { -			struct extent_inode_elem *eie = NULL; -			if (extent_item_pos && !ref->inode_list) { +			if (extent_item_pos && !ref->inode_list && +			    ref->level == 0) {  				u32 bsz;  				struct extent_buffer *eb;  				bsz = btrfs_level_size(fs_info->extent_root, -							info_level); +							ref->level);  				eb = read_tree_block(fs_info->extent_root,  							   ref->parent, bsz, 0);  				if (!eb || !extent_buffer_uptodate(eb)) { @@ -974,6 +1023,7 @@ again:  					eie = eie->next;  				eie->next = ref->inode_list;  			} +			eie = NULL;  		}  		list_del(&ref->list);  		kmem_cache_free(btrfs_prelim_ref_cache, ref); @@ -992,7 +1042,8 @@ out:  		list_del(&ref->list);  		kmem_cache_free(btrfs_prelim_ref_cache, ref);  	} - +	if (ret < 0) +		free_inode_elem_list(eie);  	return ret;  } @@ -1000,7 +1051,6 @@ static void free_leaf_list(struct ulist *blocks)  {  	struct ulist_node *node = NULL;  	struct extent_inode_elem *eie; -	struct extent_inode_elem *eie_next;  	struct ulist_iterator uiter;  	ULIST_ITER_INIT(&uiter); @@ -1008,10 +1058,7 @@ static void free_leaf_list(struct ulist *blocks)  		if (!node->aux)  			continue;  		eie = (struct extent_inode_elem *)(uintptr_t)node->aux; -		for (; eie; eie = eie_next) { -			eie_next = eie->next; -			kfree(eie); -		} +		free_inode_elem_list(eie);  		node->aux = 0;  	} @@ -1031,22 +1078,14 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,  				u64 time_seq, struct ulist **leafs,  				const u64 *extent_item_pos)  { -	struct ulist *tmp;  	int ret; -	tmp = ulist_alloc(GFP_NOFS); -	if (!tmp) -		return -ENOMEM;  	*leafs = ulist_alloc(GFP_NOFS); -	if (!*leafs) { -		ulist_free(tmp); +	if (!*leafs)  		return -ENOMEM; -	}  	ret = find_parent_nodes(trans, fs_info, bytenr, -				time_seq, *leafs, tmp, extent_item_pos); -	ulist_free(tmp); - +				time_seq, *leafs, NULL, extent_item_pos);  	if (ret < 0 && ret != -ENOENT) {  		free_leaf_list(*leafs);  		return ret; @@ -1068,9 +1107,9 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,   *   * returns 0 on success, < 0 on error.   */ -int btrfs_find_all_roots(struct btrfs_trans_handle *trans, -				struct btrfs_fs_info *fs_info, u64 bytenr, -				u64 time_seq, struct ulist **roots) +static int __btrfs_find_all_roots(struct btrfs_trans_handle *trans, +				  struct btrfs_fs_info *fs_info, u64 bytenr, +				  u64 time_seq, struct ulist **roots)  {  	struct ulist *tmp;  	struct ulist_node *node = NULL; @@ -1099,42 +1138,25 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,  		if (!node)  			break;  		bytenr = node->val; +		cond_resched();  	}  	ulist_free(tmp);  	return 0;  } - -static int __inode_info(u64 inum, u64 ioff, u8 key_type, -			struct btrfs_root *fs_root, struct btrfs_path *path, -			struct btrfs_key *found_key) +int btrfs_find_all_roots(struct btrfs_trans_handle *trans, +			 struct btrfs_fs_info *fs_info, u64 bytenr, +			 u64 time_seq, struct ulist **roots)  {  	int ret; -	struct btrfs_key key; -	struct extent_buffer *eb; - -	key.type = key_type; -	key.objectid = inum; -	key.offset = ioff; -	ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0); -	if (ret < 0) -		return ret; - -	eb = path->nodes[0]; -	if (ret && path->slots[0] >= btrfs_header_nritems(eb)) { -		ret = btrfs_next_leaf(fs_root, path); -		if (ret) -			return ret; -		eb = path->nodes[0]; -	} - -	btrfs_item_key_to_cpu(eb, found_key, path->slots[0]); -	if (found_key->type != key.type || found_key->objectid != key.objectid) -		return 1; - -	return 0; +	if (!trans) +		down_read(&fs_info->commit_root_sem); +	ret = __btrfs_find_all_roots(trans, fs_info, bytenr, time_seq, roots); +	if (!trans) +		up_read(&fs_info->commit_root_sem); +	return ret;  }  /* @@ -1144,16 +1166,16 @@ int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,  			struct btrfs_path *path)  {  	struct btrfs_key key; -	return __inode_info(inum, ioff, BTRFS_INODE_ITEM_KEY, fs_root, path, -				&key); +	return btrfs_find_item(fs_root, path, inum, ioff, +			BTRFS_INODE_ITEM_KEY, &key);  }  static int inode_ref_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,  				struct btrfs_path *path,  				struct btrfs_key *found_key)  { -	return __inode_info(inum, ioff, BTRFS_INODE_REF_KEY, fs_root, path, -				found_key); +	return btrfs_find_item(fs_root, path, inum, ioff, +			BTRFS_INODE_REF_KEY, found_key);  }  int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid, @@ -1333,20 +1355,20 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,  	ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0);  	if (ret < 0)  		return ret; -	ret = btrfs_previous_item(fs_info->extent_root, path, -					0, BTRFS_EXTENT_ITEM_KEY); -	if (ret < 0) -		return ret; +	ret = btrfs_previous_extent_item(fs_info->extent_root, path, 0); +	if (ret) { +		if (ret > 0) +			ret = -ENOENT; +		return ret; +	}  	btrfs_item_key_to_cpu(path->nodes[0], found_key, path->slots[0]);  	if (found_key->type == BTRFS_METADATA_ITEM_KEY)  		size = fs_info->extent_root->leafsize;  	else if (found_key->type == BTRFS_EXTENT_ITEM_KEY)  		size = found_key->offset; -	if ((found_key->type != BTRFS_EXTENT_ITEM_KEY && -	     found_key->type != BTRFS_METADATA_ITEM_KEY) || -	    found_key->objectid > logical || +	if (found_key->objectid > logical ||  	    found_key->objectid + size <= logical) {  		pr_debug("logical %llu is not within any extent\n", logical);  		return -ENOENT; @@ -1387,9 +1409,10 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,   * returns <0 on error   */  static int __get_extent_inline_ref(unsigned long *ptr, struct extent_buffer *eb, -				struct btrfs_extent_item *ei, u32 item_size, -				struct btrfs_extent_inline_ref **out_eiref, -				int *out_type) +				   struct btrfs_key *key, +				   struct btrfs_extent_item *ei, u32 item_size, +				   struct btrfs_extent_inline_ref **out_eiref, +				   int *out_type)  {  	unsigned long end;  	u64 flags; @@ -1399,19 +1422,26 @@ static int __get_extent_inline_ref(unsigned long *ptr, struct extent_buffer *eb,  		/* first call */  		flags = btrfs_extent_flags(eb, ei);  		if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { -			info = (struct btrfs_tree_block_info *)(ei + 1); -			*out_eiref = -				(struct btrfs_extent_inline_ref *)(info + 1); +			if (key->type == BTRFS_METADATA_ITEM_KEY) { +				/* a skinny metadata extent */ +				*out_eiref = +				     (struct btrfs_extent_inline_ref *)(ei + 1); +			} else { +				WARN_ON(key->type != BTRFS_EXTENT_ITEM_KEY); +				info = (struct btrfs_tree_block_info *)(ei + 1); +				*out_eiref = +				   (struct btrfs_extent_inline_ref *)(info + 1); +			}  		} else {  			*out_eiref = (struct btrfs_extent_inline_ref *)(ei + 1);  		}  		*ptr = (unsigned long)*out_eiref; -		if ((void *)*ptr >= (void *)ei + item_size) +		if ((unsigned long)(*ptr) >= (unsigned long)ei + item_size)  			return -ENOENT;  	}  	end = (unsigned long)ei + item_size; -	*out_eiref = (struct btrfs_extent_inline_ref *)*ptr; +	*out_eiref = (struct btrfs_extent_inline_ref *)(*ptr);  	*out_type = btrfs_extent_inline_ref_type(eb, *out_eiref);  	*ptr += btrfs_extent_inline_ref_size(*out_type); @@ -1430,8 +1460,8 @@ static int __get_extent_inline_ref(unsigned long *ptr, struct extent_buffer *eb,   * <0 on error.   */  int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb, -				struct btrfs_extent_item *ei, u32 item_size, -				u64 *out_root, u8 *out_level) +			    struct btrfs_key *key, struct btrfs_extent_item *ei, +			    u32 item_size, u64 *out_root, u8 *out_level)  {  	int ret;  	int type; @@ -1442,8 +1472,8 @@ int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,  		return 1;  	while (1) { -		ret = __get_extent_inline_ref(ptr, eb, ei, item_size, -						&eiref, &type); +		ret = __get_extent_inline_ref(ptr, eb, key, ei, item_size, +					      &eiref, &type);  		if (ret < 0)  			return ret; @@ -1516,6 +1546,8 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,  		if (IS_ERR(trans))  			return PTR_ERR(trans);  		btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem); +	} else { +		down_read(&fs_info->commit_root_sem);  	}  	ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid, @@ -1526,8 +1558,8 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,  	ULIST_ITER_INIT(&ref_uiter);  	while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) { -		ret = btrfs_find_all_roots(trans, fs_info, ref_node->val, -					   tree_mod_seq_elem.seq, &roots); +		ret = __btrfs_find_all_roots(trans, fs_info, ref_node->val, +					     tree_mod_seq_elem.seq, &roots);  		if (ret)  			break;  		ULIST_ITER_INIT(&root_uiter); @@ -1549,6 +1581,8 @@ out:  	if (!search_commit_root) {  		btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem);  		btrfs_end_transaction(trans, fs_info->extent_root); +	} else { +		up_read(&fs_info->commit_root_sem);  	}  	return ret; @@ -1599,7 +1633,6 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root,  	struct btrfs_key found_key;  	while (!ret) { -		path->leave_spinning = 1;  		ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path,  				     &found_key);  		if (ret < 0) @@ -1612,14 +1645,17 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root,  		parent = found_key.offset;  		slot = path->slots[0]; -		eb = path->nodes[0]; -		/* make sure we can use eb after releasing the path */ -		atomic_inc(&eb->refs); +		eb = btrfs_clone_extent_buffer(path->nodes[0]); +		if (!eb) { +			ret = -ENOMEM; +			break; +		} +		extent_buffer_get(eb);  		btrfs_tree_read_lock(eb);  		btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);  		btrfs_release_path(path); -		item = btrfs_item_nr(eb, slot); +		item = btrfs_item_nr(slot);  		iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref);  		for (cur = 0; cur < btrfs_item_size(eb, item); cur += len) { @@ -1672,17 +1708,20 @@ static int iterate_inode_extrefs(u64 inum, struct btrfs_root *fs_root,  		++found;  		slot = path->slots[0]; -		eb = path->nodes[0]; -		/* make sure we can use eb after releasing the path */ -		atomic_inc(&eb->refs); +		eb = btrfs_clone_extent_buffer(path->nodes[0]); +		if (!eb) { +			ret = -ENOMEM; +			break; +		} +		extent_buffer_get(eb);  		btrfs_tree_read_lock(eb);  		btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);  		btrfs_release_path(path);  		leaf = path->nodes[0]; -		item_size = btrfs_item_size_nr(leaf, path->slots[0]); -		ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); +		item_size = btrfs_item_size_nr(leaf, slot); +		ptr = btrfs_item_ptr_offset(leaf, slot);  		cur_offset = 0;  		while (cur_offset < item_size) {  | 
