diff options
author | Wang Shilong <wangsl.fnst@cn.fujitsu.com> | 2014-01-28 06:13:38 -0500 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2014-01-29 10:06:26 -0500 |
commit | f05c474688762f186b16a26366755b6ef0bfed0c (patch) | |
tree | bc808f97ce526c8eaf80473ca5dd5de8a8fece8e /fs/btrfs | |
parent | bf54f412f0624786ac8a115110b5203430a9eebb (diff) |
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>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/backref.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 7966acd5dc7f..aded3ef3d3d4 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, | |||
66 | return 0; | 66 | return 0; |
67 | } | 67 | } |
68 | 68 | ||
69 | static void free_inode_elem_list(struct extent_inode_elem *eie) | ||
70 | { | ||
71 | struct extent_inode_elem *eie_next; | ||
72 | |||
73 | for (; eie; eie = eie_next) { | ||
74 | eie_next = eie->next; | ||
75 | kfree(eie); | ||
76 | } | ||
77 | } | ||
78 | |||
69 | static int find_extent_in_eb(struct extent_buffer *eb, u64 wanted_disk_byte, | 79 | static int find_extent_in_eb(struct extent_buffer *eb, u64 wanted_disk_byte, |
70 | u64 extent_item_pos, | 80 | u64 extent_item_pos, |
71 | struct extent_inode_elem **eie) | 81 | struct extent_inode_elem **eie) |
@@ -275,6 +285,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, | |||
275 | old = old->next; | 285 | old = old->next; |
276 | old->next = eie; | 286 | old->next = eie; |
277 | } | 287 | } |
288 | eie = NULL; | ||
278 | } | 289 | } |
279 | next: | 290 | next: |
280 | ret = btrfs_next_old_item(root, path, time_seq); | 291 | ret = btrfs_next_old_item(root, path, time_seq); |
@@ -282,6 +293,8 @@ next: | |||
282 | 293 | ||
283 | if (ret > 0) | 294 | if (ret > 0) |
284 | ret = 0; | 295 | ret = 0; |
296 | else if (ret < 0) | ||
297 | free_inode_elem_list(eie); | ||
285 | return ret; | 298 | return ret; |
286 | } | 299 | } |
287 | 300 | ||
@@ -845,6 +858,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, | |||
845 | struct list_head prefs_delayed; | 858 | struct list_head prefs_delayed; |
846 | struct list_head prefs; | 859 | struct list_head prefs; |
847 | struct __prelim_ref *ref; | 860 | struct __prelim_ref *ref; |
861 | struct extent_inode_elem *eie = NULL; | ||
848 | 862 | ||
849 | INIT_LIST_HEAD(&prefs); | 863 | INIT_LIST_HEAD(&prefs); |
850 | INIT_LIST_HEAD(&prefs_delayed); | 864 | INIT_LIST_HEAD(&prefs_delayed); |
@@ -958,7 +972,6 @@ again: | |||
958 | goto out; | 972 | goto out; |
959 | } | 973 | } |
960 | if (ref->count && ref->parent) { | 974 | if (ref->count && ref->parent) { |
961 | struct extent_inode_elem *eie = NULL; | ||
962 | if (extent_item_pos && !ref->inode_list) { | 975 | if (extent_item_pos && !ref->inode_list) { |
963 | u32 bsz; | 976 | u32 bsz; |
964 | struct extent_buffer *eb; | 977 | struct extent_buffer *eb; |
@@ -993,6 +1006,7 @@ again: | |||
993 | eie = eie->next; | 1006 | eie = eie->next; |
994 | eie->next = ref->inode_list; | 1007 | eie->next = ref->inode_list; |
995 | } | 1008 | } |
1009 | eie = NULL; | ||
996 | } | 1010 | } |
997 | list_del(&ref->list); | 1011 | list_del(&ref->list); |
998 | kmem_cache_free(btrfs_prelim_ref_cache, ref); | 1012 | kmem_cache_free(btrfs_prelim_ref_cache, ref); |
@@ -1011,7 +1025,8 @@ out: | |||
1011 | list_del(&ref->list); | 1025 | list_del(&ref->list); |
1012 | kmem_cache_free(btrfs_prelim_ref_cache, ref); | 1026 | kmem_cache_free(btrfs_prelim_ref_cache, ref); |
1013 | } | 1027 | } |
1014 | 1028 | if (ret < 0) | |
1029 | free_inode_elem_list(eie); | ||
1015 | return ret; | 1030 | return ret; |
1016 | } | 1031 | } |
1017 | 1032 | ||
@@ -1019,7 +1034,6 @@ static void free_leaf_list(struct ulist *blocks) | |||
1019 | { | 1034 | { |
1020 | struct ulist_node *node = NULL; | 1035 | struct ulist_node *node = NULL; |
1021 | struct extent_inode_elem *eie; | 1036 | struct extent_inode_elem *eie; |
1022 | struct extent_inode_elem *eie_next; | ||
1023 | struct ulist_iterator uiter; | 1037 | struct ulist_iterator uiter; |
1024 | 1038 | ||
1025 | ULIST_ITER_INIT(&uiter); | 1039 | ULIST_ITER_INIT(&uiter); |
@@ -1027,10 +1041,7 @@ static void free_leaf_list(struct ulist *blocks) | |||
1027 | if (!node->aux) | 1041 | if (!node->aux) |
1028 | continue; | 1042 | continue; |
1029 | eie = (struct extent_inode_elem *)(uintptr_t)node->aux; | 1043 | eie = (struct extent_inode_elem *)(uintptr_t)node->aux; |
1030 | for (; eie; eie = eie_next) { | 1044 | free_inode_elem_list(eie); |
1031 | eie_next = eie->next; | ||
1032 | kfree(eie); | ||
1033 | } | ||
1034 | node->aux = 0; | 1045 | node->aux = 0; |
1035 | } | 1046 | } |
1036 | 1047 | ||