aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
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
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')
-rw-r--r--fs/btrfs/backref.c18
-rw-r--r--fs/btrfs/ulist.c23
-rw-r--r--fs/btrfs/ulist.h9
3 files changed, 29 insertions, 21 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,
diff --git a/fs/btrfs/ulist.c b/fs/btrfs/ulist.c
index 12f5147bd2b1..17e68bdc307c 100644
--- a/fs/btrfs/ulist.c
+++ b/fs/btrfs/ulist.c
@@ -23,9 +23,9 @@
23 * 23 *
24 * ulist = ulist_alloc(); 24 * ulist = ulist_alloc();
25 * ulist_add(ulist, root); 25 * ulist_add(ulist, root);
26 * elem = NULL; 26 * ULIST_ITER_INIT(&uiter);
27 * 27 *
28 * while ((elem = ulist_next(ulist, elem)) { 28 * while ((elem = ulist_next(ulist, &uiter)) {
29 * for (all child nodes n in elem) 29 * for (all child nodes n in elem)
30 * ulist_add(ulist, n); 30 * ulist_add(ulist, n);
31 * do something useful with the node; 31 * do something useful with the node;
@@ -188,33 +188,26 @@ EXPORT_SYMBOL(ulist_add);
188/** 188/**
189 * ulist_next - iterate ulist 189 * ulist_next - iterate ulist
190 * @ulist: ulist to iterate 190 * @ulist: ulist to iterate
191 * @prev: previously returned element or %NULL to start iteration 191 * @uiter: iterator variable, initialized with ULIST_ITER_INIT(&iterator)
192 * 192 *
193 * Note: locking must be provided by the caller. In case of rwlocks only read 193 * Note: locking must be provided by the caller. In case of rwlocks only read
194 * locking is needed 194 * locking is needed
195 * 195 *
196 * This function is used to iterate an ulist. The iteration is started with 196 * This function is used to iterate an ulist.
197 * @prev = %NULL. It returns the next element from the ulist or %NULL when the 197 * It returns the next element from the ulist or %NULL when the
198 * end is reached. No guarantee is made with respect to the order in which 198 * end is reached. No guarantee is made with respect to the order in which
199 * the elements are returned. They might neither be returned in order of 199 * the elements are returned. They might neither be returned in order of
200 * addition nor in ascending order. 200 * addition nor in ascending order.
201 * It is allowed to call ulist_add during an enumeration. Newly added items 201 * It is allowed to call ulist_add during an enumeration. Newly added items
202 * are guaranteed to show up in the running enumeration. 202 * are guaranteed to show up in the running enumeration.
203 */ 203 */
204struct ulist_node *ulist_next(struct ulist *ulist, struct ulist_node *prev) 204struct ulist_node *ulist_next(struct ulist *ulist, struct ulist_iterator *uiter)
205{ 205{
206 int next;
207
208 if (ulist->nnodes == 0) 206 if (ulist->nnodes == 0)
209 return NULL; 207 return NULL;
210 208 if (uiter->i < 0 || uiter->i >= ulist->nnodes)
211 if (!prev)
212 return &ulist->nodes[0];
213
214 next = (prev - ulist->nodes) + 1;
215 if (next < 0 || next >= ulist->nnodes)
216 return NULL; 209 return NULL;
217 210
218 return &ulist->nodes[next]; 211 return &ulist->nodes[uiter->i++];
219} 212}
220EXPORT_SYMBOL(ulist_next); 213EXPORT_SYMBOL(ulist_next);
diff --git a/fs/btrfs/ulist.h b/fs/btrfs/ulist.h
index 2e25dec58ec0..62d2574f775a 100644
--- a/fs/btrfs/ulist.h
+++ b/fs/btrfs/ulist.h
@@ -24,6 +24,10 @@
24 */ 24 */
25#define ULIST_SIZE 16 25#define ULIST_SIZE 16
26 26
27struct ulist_iterator {
28 int i;
29};
30
27/* 31/*
28 * element of the list 32 * element of the list
29 */ 33 */
@@ -63,6 +67,9 @@ struct ulist *ulist_alloc(unsigned long gfp_mask);
63void ulist_free(struct ulist *ulist); 67void ulist_free(struct ulist *ulist);
64int ulist_add(struct ulist *ulist, u64 val, unsigned long aux, 68int ulist_add(struct ulist *ulist, u64 val, unsigned long aux,
65 unsigned long gfp_mask); 69 unsigned long gfp_mask);
66struct ulist_node *ulist_next(struct ulist *ulist, struct ulist_node *prev); 70struct ulist_node *ulist_next(struct ulist *ulist,
71 struct ulist_iterator *uiter);
72
73#define ULIST_ITER_INIT(uiter) ((uiter)->i = 0)
67 74
68#endif 75#endif