Btrfs: fix memory leaks on walking backrefs failure
When walking backrefs, we may iterate every inode's extent and add/merge them into ulist, and the caller will free memory from ulist. However, if we fail to allocate inode's extents element memory or ulist_add() fail to allocate memory, we won't add allocated memory into ulist, and the caller won't free some allocated memory thus memory leaks happen. Signed-off-by: Wang Shilong <wangsl.fnst@cn.fujitsu.com> Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: Chris Mason <clm@fb.com>
This commit is contained in:
parent
bf54f412f0
commit
f05c474688
|
@ -66,6 +66,16 @@ static int check_extent_in_eb(struct btrfs_key *key, struct extent_buffer *eb,
|
||||||
return 0;
|
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,
|
static int find_extent_in_eb(struct extent_buffer *eb, u64 wanted_disk_byte,
|
||||||
u64 extent_item_pos,
|
u64 extent_item_pos,
|
||||||
struct extent_inode_elem **eie)
|
struct extent_inode_elem **eie)
|
||||||
|
@ -275,6 +285,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
|
||||||
old = old->next;
|
old = old->next;
|
||||||
old->next = eie;
|
old->next = eie;
|
||||||
}
|
}
|
||||||
|
eie = NULL;
|
||||||
}
|
}
|
||||||
next:
|
next:
|
||||||
ret = btrfs_next_old_item(root, path, time_seq);
|
ret = btrfs_next_old_item(root, path, time_seq);
|
||||||
|
@ -282,6 +293,8 @@ next:
|
||||||
|
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
else if (ret < 0)
|
||||||
|
free_inode_elem_list(eie);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -845,6 +858,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
|
||||||
struct list_head prefs_delayed;
|
struct list_head prefs_delayed;
|
||||||
struct list_head prefs;
|
struct list_head prefs;
|
||||||
struct __prelim_ref *ref;
|
struct __prelim_ref *ref;
|
||||||
|
struct extent_inode_elem *eie = NULL;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&prefs);
|
INIT_LIST_HEAD(&prefs);
|
||||||
INIT_LIST_HEAD(&prefs_delayed);
|
INIT_LIST_HEAD(&prefs_delayed);
|
||||||
|
@ -958,7 +972,6 @@ again:
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (ref->count && ref->parent) {
|
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) {
|
||||||
u32 bsz;
|
u32 bsz;
|
||||||
struct extent_buffer *eb;
|
struct extent_buffer *eb;
|
||||||
|
@ -993,6 +1006,7 @@ again:
|
||||||
eie = eie->next;
|
eie = eie->next;
|
||||||
eie->next = ref->inode_list;
|
eie->next = ref->inode_list;
|
||||||
}
|
}
|
||||||
|
eie = NULL;
|
||||||
}
|
}
|
||||||
list_del(&ref->list);
|
list_del(&ref->list);
|
||||||
kmem_cache_free(btrfs_prelim_ref_cache, ref);
|
kmem_cache_free(btrfs_prelim_ref_cache, ref);
|
||||||
|
@ -1011,7 +1025,8 @@ out:
|
||||||
list_del(&ref->list);
|
list_del(&ref->list);
|
||||||
kmem_cache_free(btrfs_prelim_ref_cache, ref);
|
kmem_cache_free(btrfs_prelim_ref_cache, ref);
|
||||||
}
|
}
|
||||||
|
if (ret < 0)
|
||||||
|
free_inode_elem_list(eie);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1019,7 +1034,6 @@ static void free_leaf_list(struct ulist *blocks)
|
||||||
{
|
{
|
||||||
struct ulist_node *node = NULL;
|
struct ulist_node *node = NULL;
|
||||||
struct extent_inode_elem *eie;
|
struct extent_inode_elem *eie;
|
||||||
struct extent_inode_elem *eie_next;
|
|
||||||
struct ulist_iterator uiter;
|
struct ulist_iterator uiter;
|
||||||
|
|
||||||
ULIST_ITER_INIT(&uiter);
|
ULIST_ITER_INIT(&uiter);
|
||||||
|
@ -1027,10 +1041,7 @@ static void free_leaf_list(struct ulist *blocks)
|
||||||
if (!node->aux)
|
if (!node->aux)
|
||||||
continue;
|
continue;
|
||||||
eie = (struct extent_inode_elem *)(uintptr_t)node->aux;
|
eie = (struct extent_inode_elem *)(uintptr_t)node->aux;
|
||||||
for (; eie; eie = eie_next) {
|
free_inode_elem_list(eie);
|
||||||
eie_next = eie->next;
|
|
||||||
kfree(eie);
|
|
||||||
}
|
|
||||||
node->aux = 0;
|
node->aux = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue