1. in btrfs_find_all_roots This method uses a ulist to solve the recursion. The local variable node is used in combination with ulist_next to iterate through the list. Calls to find_parent_nodes fill up this list. The problem is, adding new nodes to the ulist may cause the ulist->nodes pointer to change in case the ulist needs to realloc the buffer. The call to ulist_next may use a wrong prev pointer in that case, resulting in undefined behaviour. It is changed now to not use ulist_next. 2. in __iterate_extent_inodes the first while loop calls btrfs_find_all_roots, which then allocates a new ulist for the roots. In case the first while loops loops more then once, we leak the previous ulist as it is not freed.
Point 1 was also causing missed backrefs because the iteration stopped too early. Signed-off-by: Alexander Block <abloc...@googlemail.com> --- fs/btrfs/backref.c | 20 ++++++++++++++------ 1 files changed, 14 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index f28ecba..b08cf93 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -791,6 +791,7 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans, struct ulist *tmp; struct ulist_node *node = NULL; int ret; + int cur; tmp = ulist_alloc(GFP_NOFS); if (!tmp) @@ -801,7 +802,14 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans, return -ENOMEM; } - while (1) { + cur = 0; + ulist_add(tmp, bytenr, 0, GFP_NOFS); + + while (cur < tmp->nnodes) { + node = &tmp->nodes[cur++]; + bytenr = node->val; + + /* this will add new nodes to the tmp ulist */ ret = find_parent_nodes(trans, fs_info, bytenr, seq, tmp, *roots); if (ret < 0 && ret != -ENOENT) { @@ -809,10 +817,6 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans, ulist_free(*roots); return ret; } - node = ulist_next(tmp, node); - if (!node) - break; - bytenr = node->val; } ulist_free(tmp); @@ -1231,10 +1235,14 @@ static int __iterate_extent_inodes(struct btrfs_fs_info *fs_info, match_with_offset, iterate, ctx); } + if (roots) + ulist_free(roots); + roots = NULL; } ulist_free(refs); - ulist_free(roots); + if (roots) + ulist_free(roots); out: if (!search_commit_root) { btrfs_put_delayed_seq(delayed_refs, &seq_elem); -- 1.7.3.4 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html