mirror of
https://github.com/torvalds/linux.git
synced 2026-06-06 05:27:07 +02:00
btrfs: fix inode list leak during backref walking at resolve_indirect_refs()
[ Upstream commit5614dc3a47] During backref walking, at resolve_indirect_refs(), if we get an error we jump to the 'out' label and call ulist_free() on the 'parents' ulist, which frees all the elements in the ulist - however that does not free any inode lists that may be attached to elements, through the 'aux' field of a ulist node, so we end up leaking lists if we have any attached to the unodes. Fix this by calling free_leaf_list() instead of ulist_free() when we exit from resolve_indirect_refs(). The static function free_leaf_list() is moved up for this to be possible and it's slightly simplified by removing unnecessary code. Fixes:3301958b7c("Btrfs: add inodes before dropping the extent lock in find_all_leafs") Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
81204283ea
commit
a52e24c7fc
|
|
@ -647,6 +647,18 @@ unode_aux_to_inode_list(struct ulist_node *node)
|
||||||
return (struct extent_inode_elem *)(uintptr_t)node->aux;
|
return (struct extent_inode_elem *)(uintptr_t)node->aux;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void free_leaf_list(struct ulist *ulist)
|
||||||
|
{
|
||||||
|
struct ulist_node *node;
|
||||||
|
struct ulist_iterator uiter;
|
||||||
|
|
||||||
|
ULIST_ITER_INIT(&uiter);
|
||||||
|
while ((node = ulist_next(ulist, &uiter)))
|
||||||
|
free_inode_elem_list(unode_aux_to_inode_list(node));
|
||||||
|
|
||||||
|
ulist_free(ulist);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We maintain three separate rbtrees: one for direct refs, one for
|
* We maintain three separate rbtrees: one for direct refs, one for
|
||||||
* indirect refs which have a key, and one for indirect refs which do not
|
* indirect refs which have a key, and one for indirect refs which do not
|
||||||
|
|
@ -761,7 +773,11 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info,
|
||||||
cond_resched();
|
cond_resched();
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
ulist_free(parents);
|
/*
|
||||||
|
* We may have inode lists attached to refs in the parents ulist, so we
|
||||||
|
* must free them before freeing the ulist and its refs.
|
||||||
|
*/
|
||||||
|
free_leaf_list(parents);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1413,24 +1429,6 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_leaf_list(struct ulist *blocks)
|
|
||||||
{
|
|
||||||
struct ulist_node *node = NULL;
|
|
||||||
struct extent_inode_elem *eie;
|
|
||||||
struct ulist_iterator uiter;
|
|
||||||
|
|
||||||
ULIST_ITER_INIT(&uiter);
|
|
||||||
while ((node = ulist_next(blocks, &uiter))) {
|
|
||||||
if (!node->aux)
|
|
||||||
continue;
|
|
||||||
eie = unode_aux_to_inode_list(node);
|
|
||||||
free_inode_elem_list(eie);
|
|
||||||
node->aux = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ulist_free(blocks);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finds all leafs with a reference to the specified combination of bytenr and
|
* Finds all leafs with a reference to the specified combination of bytenr and
|
||||||
* offset. key_list_head will point to a list of corresponding keys (caller must
|
* offset. key_list_head will point to a list of corresponding keys (caller must
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user