aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/backref.c
diff options
context:
space:
mode:
authorJan Schmidt <list.btrfs@jan-o-sch.net>2012-05-22 08:56:50 -0400
committerJan Schmidt <list.btrfs@jan-o-sch.net>2012-05-26 06:17:49 -0400
commitcd1b413c5c863a96bfdeab8e91b1fb3a52665e42 (patch)
treea433c13c530c487f2d7e209402ef72ec67e48647 /fs/btrfs/backref.c
parentb9fab919b748c7b39c19ff236ed6c5682c266dde (diff)
Btrfs: ulist realloc bugfix
ulist_next gets the pointer to the previously returned element to find the next element from there. However, when we call ulist_add while iteration with ulist_next is in progress (ulist explicitly supports this), we can realloc the ulist internal memory, which makes the pointer to the previous element useless. Instead, we now use an iterator parameter that's independent from the internal pointers. Reported-by: Alexander Block <ablock84@googlemail.com> Signed-off-by: Jan Schmidt <list.btrfs@jan-o-sch.net>
Diffstat (limited to 'fs/btrfs/backref.c')
-rw-r--r--fs/btrfs/backref.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index bcec06750232..b41d94a6471b 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -201,6 +201,7 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
201 struct __prelim_ref *new_ref; 201 struct __prelim_ref *new_ref;
202 struct ulist *parents; 202 struct ulist *parents;
203 struct ulist_node *node; 203 struct ulist_node *node;
204 struct ulist_iterator uiter;
204 205
205 parents = ulist_alloc(GFP_NOFS); 206 parents = ulist_alloc(GFP_NOFS);
206 if (!parents) 207 if (!parents)
@@ -225,11 +226,12 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
225 } 226 }
226 227
227 /* we put the first parent into the ref at hand */ 228 /* we put the first parent into the ref at hand */
228 node = ulist_next(parents, NULL); 229 ULIST_ITER_INIT(&uiter);
230 node = ulist_next(parents, &uiter);
229 ref->parent = node ? node->val : 0; 231 ref->parent = node ? node->val : 0;
230 232
231 /* additional parents require new refs being added here */ 233 /* additional parents require new refs being added here */
232 while ((node = ulist_next(parents, node))) { 234 while ((node = ulist_next(parents, &uiter))) {
233 new_ref = kmalloc(sizeof(*new_ref), GFP_NOFS); 235 new_ref = kmalloc(sizeof(*new_ref), GFP_NOFS);
234 if (!new_ref) { 236 if (!new_ref) {
235 ret = -ENOMEM; 237 ret = -ENOMEM;
@@ -788,6 +790,7 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
788{ 790{
789 struct ulist *tmp; 791 struct ulist *tmp;
790 struct ulist_node *node = NULL; 792 struct ulist_node *node = NULL;
793 struct ulist_iterator uiter;
791 int ret; 794 int ret;
792 795
793 tmp = ulist_alloc(GFP_NOFS); 796 tmp = ulist_alloc(GFP_NOFS);
@@ -799,6 +802,7 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
799 return -ENOMEM; 802 return -ENOMEM;
800 } 803 }
801 804
805 ULIST_ITER_INIT(&uiter);
802 while (1) { 806 while (1) {
803 ret = find_parent_nodes(trans, fs_info, bytenr, seq, 807 ret = find_parent_nodes(trans, fs_info, bytenr, seq,
804 tmp, *roots); 808 tmp, *roots);
@@ -807,7 +811,7 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
807 ulist_free(*roots); 811 ulist_free(*roots);
808 return ret; 812 return ret;
809 } 813 }
810 node = ulist_next(tmp, node); 814 node = ulist_next(tmp, &uiter);
811 if (!node) 815 if (!node)
812 break; 816 break;
813 bytenr = node->val; 817 bytenr = node->val;
@@ -1176,6 +1180,8 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
1176 struct ulist_node *ref_node = NULL; 1180 struct ulist_node *ref_node = NULL;
1177 struct ulist_node *root_node = NULL; 1181 struct ulist_node *root_node = NULL;
1178 struct seq_list seq_elem; 1182 struct seq_list seq_elem;
1183 struct ulist_iterator ref_uiter;
1184 struct ulist_iterator root_uiter;
1179 struct btrfs_delayed_ref_root *delayed_refs = NULL; 1185 struct btrfs_delayed_ref_root *delayed_refs = NULL;
1180 1186
1181 pr_debug("resolving all inodes for extent %llu\n", 1187 pr_debug("resolving all inodes for extent %llu\n",
@@ -1201,12 +1207,14 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
1201 if (ret) 1207 if (ret)
1202 goto out; 1208 goto out;
1203 1209
1204 while (!ret && (ref_node = ulist_next(refs, ref_node))) { 1210 ULIST_ITER_INIT(&ref_uiter);
1211 while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) {
1205 ret = btrfs_find_all_roots(trans, fs_info, ref_node->val, -1, 1212 ret = btrfs_find_all_roots(trans, fs_info, ref_node->val, -1,
1206 seq_elem.seq, &roots); 1213 seq_elem.seq, &roots);
1207 if (ret) 1214 if (ret)
1208 break; 1215 break;
1209 while (!ret && (root_node = ulist_next(roots, root_node))) { 1216 ULIST_ITER_INIT(&root_uiter);
1217 while (!ret && (root_node = ulist_next(roots, &root_uiter))) {
1210 pr_debug("root %llu references leaf %llu\n", 1218 pr_debug("root %llu references leaf %llu\n",
1211 root_node->val, ref_node->val); 1219 root_node->val, ref_node->val);
1212 ret = iterate_leaf_refs(fs_info, ref_node->val, 1220 ret = iterate_leaf_refs(fs_info, ref_node->val,