aboutsummaryrefslogtreecommitdiffstats
path: root/lib/radix-tree.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /lib/radix-tree.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'lib/radix-tree.c')
-rw-r--r--lib/radix-tree.c92
1 files changed, 63 insertions, 29 deletions
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index efd16fa80b1c..7ea2e033d715 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -49,7 +49,7 @@ struct radix_tree_node {
49 unsigned int height; /* Height from the bottom */ 49 unsigned int height; /* Height from the bottom */
50 unsigned int count; 50 unsigned int count;
51 struct rcu_head rcu_head; 51 struct rcu_head rcu_head;
52 void *slots[RADIX_TREE_MAP_SIZE]; 52 void __rcu *slots[RADIX_TREE_MAP_SIZE];
53 unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS]; 53 unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];
54}; 54};
55 55
@@ -82,6 +82,16 @@ struct radix_tree_preload {
82}; 82};
83static DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, }; 83static DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, };
84 84
85static inline void *ptr_to_indirect(void *ptr)
86{
87 return (void *)((unsigned long)ptr | RADIX_TREE_INDIRECT_PTR);
88}
89
90static inline void *indirect_to_ptr(void *ptr)
91{
92 return (void *)((unsigned long)ptr & ~RADIX_TREE_INDIRECT_PTR);
93}
94
85static inline gfp_t root_gfp_mask(struct radix_tree_root *root) 95static inline gfp_t root_gfp_mask(struct radix_tree_root *root)
86{ 96{
87 return root->gfp_mask & __GFP_BITS_MASK; 97 return root->gfp_mask & __GFP_BITS_MASK;
@@ -265,7 +275,7 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
265 return -ENOMEM; 275 return -ENOMEM;
266 276
267 /* Increase the height. */ 277 /* Increase the height. */
268 node->slots[0] = radix_tree_indirect_to_ptr(root->rnode); 278 node->slots[0] = indirect_to_ptr(root->rnode);
269 279
270 /* Propagate the aggregated tag info into the new root */ 280 /* Propagate the aggregated tag info into the new root */
271 for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { 281 for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
@@ -276,7 +286,7 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
276 newheight = root->height+1; 286 newheight = root->height+1;
277 node->height = newheight; 287 node->height = newheight;
278 node->count = 1; 288 node->count = 1;
279 node = radix_tree_ptr_to_indirect(node); 289 node = ptr_to_indirect(node);
280 rcu_assign_pointer(root->rnode, node); 290 rcu_assign_pointer(root->rnode, node);
281 root->height = newheight; 291 root->height = newheight;
282 } while (height > root->height); 292 } while (height > root->height);
@@ -309,7 +319,7 @@ int radix_tree_insert(struct radix_tree_root *root,
309 return error; 319 return error;
310 } 320 }
311 321
312 slot = radix_tree_indirect_to_ptr(root->rnode); 322 slot = indirect_to_ptr(root->rnode);
313 323
314 height = root->height; 324 height = root->height;
315 shift = (height-1) * RADIX_TREE_MAP_SHIFT; 325 shift = (height-1) * RADIX_TREE_MAP_SHIFT;
@@ -325,8 +335,7 @@ int radix_tree_insert(struct radix_tree_root *root,
325 rcu_assign_pointer(node->slots[offset], slot); 335 rcu_assign_pointer(node->slots[offset], slot);
326 node->count++; 336 node->count++;
327 } else 337 } else
328 rcu_assign_pointer(root->rnode, 338 rcu_assign_pointer(root->rnode, ptr_to_indirect(slot));
329 radix_tree_ptr_to_indirect(slot));
330 } 339 }
331 340
332 /* Go a level down */ 341 /* Go a level down */
@@ -374,7 +383,7 @@ static void *radix_tree_lookup_element(struct radix_tree_root *root,
374 return NULL; 383 return NULL;
375 return is_slot ? (void *)&root->rnode : node; 384 return is_slot ? (void *)&root->rnode : node;
376 } 385 }
377 node = radix_tree_indirect_to_ptr(node); 386 node = indirect_to_ptr(node);
378 387
379 height = node->height; 388 height = node->height;
380 if (index > radix_tree_maxindex(height)) 389 if (index > radix_tree_maxindex(height))
@@ -393,7 +402,7 @@ static void *radix_tree_lookup_element(struct radix_tree_root *root,
393 height--; 402 height--;
394 } while (height > 0); 403 } while (height > 0);
395 404
396 return is_slot ? (void *)slot:node; 405 return is_slot ? (void *)slot : indirect_to_ptr(node);
397} 406}
398 407
399/** 408/**
@@ -455,7 +464,7 @@ void *radix_tree_tag_set(struct radix_tree_root *root,
455 height = root->height; 464 height = root->height;
456 BUG_ON(index > radix_tree_maxindex(height)); 465 BUG_ON(index > radix_tree_maxindex(height));
457 466
458 slot = radix_tree_indirect_to_ptr(root->rnode); 467 slot = indirect_to_ptr(root->rnode);
459 shift = (height - 1) * RADIX_TREE_MAP_SHIFT; 468 shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
460 469
461 while (height > 0) { 470 while (height > 0) {
@@ -509,7 +518,7 @@ void *radix_tree_tag_clear(struct radix_tree_root *root,
509 518
510 shift = (height - 1) * RADIX_TREE_MAP_SHIFT; 519 shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
511 pathp->node = NULL; 520 pathp->node = NULL;
512 slot = radix_tree_indirect_to_ptr(root->rnode); 521 slot = indirect_to_ptr(root->rnode);
513 522
514 while (height > 0) { 523 while (height > 0) {
515 int offset; 524 int offset;
@@ -579,7 +588,7 @@ int radix_tree_tag_get(struct radix_tree_root *root,
579 588
580 if (!radix_tree_is_indirect_ptr(node)) 589 if (!radix_tree_is_indirect_ptr(node))
581 return (index == 0); 590 return (index == 0);
582 node = radix_tree_indirect_to_ptr(node); 591 node = indirect_to_ptr(node);
583 592
584 height = node->height; 593 height = node->height;
585 if (index > radix_tree_maxindex(height)) 594 if (index > radix_tree_maxindex(height))
@@ -666,7 +675,7 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
666 } 675 }
667 676
668 shift = (height - 1) * RADIX_TREE_MAP_SHIFT; 677 shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
669 slot = radix_tree_indirect_to_ptr(root->rnode); 678 slot = indirect_to_ptr(root->rnode);
670 679
671 /* 680 /*
672 * we fill the path from (root->height - 2) to 0, leaving the index at 681 * we fill the path from (root->height - 2) to 0, leaving the index at
@@ -727,10 +736,11 @@ next:
727 } 736 }
728 } 737 }
729 /* 738 /*
730 * The iftag must have been set somewhere because otherwise 739 * We need not to tag the root tag if there is no tag which is set with
731 * we would return immediated at the beginning of the function 740 * settag within the range from *first_indexp to last_index.
732 */ 741 */
733 root_tag_set(root, settag); 742 if (tagged > 0)
743 root_tag_set(root, settag);
734 *first_indexp = index; 744 *first_indexp = index;
735 745
736 return tagged; 746 return tagged;
@@ -897,7 +907,7 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
897 results[0] = node; 907 results[0] = node;
898 return 1; 908 return 1;
899 } 909 }
900 node = radix_tree_indirect_to_ptr(node); 910 node = indirect_to_ptr(node);
901 911
902 max_index = radix_tree_maxindex(node->height); 912 max_index = radix_tree_maxindex(node->height);
903 913
@@ -916,7 +926,8 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
916 slot = *(((void ***)results)[ret + i]); 926 slot = *(((void ***)results)[ret + i]);
917 if (!slot) 927 if (!slot)
918 continue; 928 continue;
919 results[ret + nr_found] = rcu_dereference_raw(slot); 929 results[ret + nr_found] =
930 indirect_to_ptr(rcu_dereference_raw(slot));
920 nr_found++; 931 nr_found++;
921 } 932 }
922 ret += nr_found; 933 ret += nr_found;
@@ -965,7 +976,7 @@ radix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results,
965 results[0] = (void **)&root->rnode; 976 results[0] = (void **)&root->rnode;
966 return 1; 977 return 1;
967 } 978 }
968 node = radix_tree_indirect_to_ptr(node); 979 node = indirect_to_ptr(node);
969 980
970 max_index = radix_tree_maxindex(node->height); 981 max_index = radix_tree_maxindex(node->height);
971 982
@@ -1090,7 +1101,7 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
1090 results[0] = node; 1101 results[0] = node;
1091 return 1; 1102 return 1;
1092 } 1103 }
1093 node = radix_tree_indirect_to_ptr(node); 1104 node = indirect_to_ptr(node);
1094 1105
1095 max_index = radix_tree_maxindex(node->height); 1106 max_index = radix_tree_maxindex(node->height);
1096 1107
@@ -1109,7 +1120,8 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
1109 slot = *(((void ***)results)[ret + i]); 1120 slot = *(((void ***)results)[ret + i]);
1110 if (!slot) 1121 if (!slot)
1111 continue; 1122 continue;
1112 results[ret + nr_found] = rcu_dereference_raw(slot); 1123 results[ret + nr_found] =
1124 indirect_to_ptr(rcu_dereference_raw(slot));
1113 nr_found++; 1125 nr_found++;
1114 } 1126 }
1115 ret += nr_found; 1127 ret += nr_found;
@@ -1159,7 +1171,7 @@ radix_tree_gang_lookup_tag_slot(struct radix_tree_root *root, void ***results,
1159 results[0] = (void **)&root->rnode; 1171 results[0] = (void **)&root->rnode;
1160 return 1; 1172 return 1;
1161 } 1173 }
1162 node = radix_tree_indirect_to_ptr(node); 1174 node = indirect_to_ptr(node);
1163 1175
1164 max_index = radix_tree_maxindex(node->height); 1176 max_index = radix_tree_maxindex(node->height);
1165 1177
@@ -1195,7 +1207,7 @@ static inline void radix_tree_shrink(struct radix_tree_root *root)
1195 void *newptr; 1207 void *newptr;
1196 1208
1197 BUG_ON(!radix_tree_is_indirect_ptr(to_free)); 1209 BUG_ON(!radix_tree_is_indirect_ptr(to_free));
1198 to_free = radix_tree_indirect_to_ptr(to_free); 1210 to_free = indirect_to_ptr(to_free);
1199 1211
1200 /* 1212 /*
1201 * The candidate node has more than one child, or its child 1213 * The candidate node has more than one child, or its child
@@ -1208,16 +1220,39 @@ static inline void radix_tree_shrink(struct radix_tree_root *root)
1208 1220
1209 /* 1221 /*
1210 * We don't need rcu_assign_pointer(), since we are simply 1222 * We don't need rcu_assign_pointer(), since we are simply
1211 * moving the node from one part of the tree to another. If 1223 * moving the node from one part of the tree to another: if it
1212 * it was safe to dereference the old pointer to it 1224 * was safe to dereference the old pointer to it
1213 * (to_free->slots[0]), it will be safe to dereference the new 1225 * (to_free->slots[0]), it will be safe to dereference the new
1214 * one (root->rnode). 1226 * one (root->rnode) as far as dependent read barriers go.
1215 */ 1227 */
1216 newptr = to_free->slots[0]; 1228 newptr = to_free->slots[0];
1217 if (root->height > 1) 1229 if (root->height > 1)
1218 newptr = radix_tree_ptr_to_indirect(newptr); 1230 newptr = ptr_to_indirect(newptr);
1219 root->rnode = newptr; 1231 root->rnode = newptr;
1220 root->height--; 1232 root->height--;
1233
1234 /*
1235 * We have a dilemma here. The node's slot[0] must not be
1236 * NULLed in case there are concurrent lookups expecting to
1237 * find the item. However if this was a bottom-level node,
1238 * then it may be subject to the slot pointer being visible
1239 * to callers dereferencing it. If item corresponding to
1240 * slot[0] is subsequently deleted, these callers would expect
1241 * their slot to become empty sooner or later.
1242 *
1243 * For example, lockless pagecache will look up a slot, deref
1244 * the page pointer, and if the page is 0 refcount it means it
1245 * was concurrently deleted from pagecache so try the deref
1246 * again. Fortunately there is already a requirement for logic
1247 * to retry the entire slot lookup -- the indirect pointer
1248 * problem (replacing direct root node with an indirect pointer
1249 * also results in a stale slot). So tag the slot as indirect
1250 * to force callers to retry.
1251 */
1252 if (root->height == 0)
1253 *((unsigned long *)&to_free->slots[0]) |=
1254 RADIX_TREE_INDIRECT_PTR;
1255
1221 radix_tree_node_free(to_free); 1256 radix_tree_node_free(to_free);
1222 } 1257 }
1223} 1258}
@@ -1254,7 +1289,7 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
1254 root->rnode = NULL; 1289 root->rnode = NULL;
1255 goto out; 1290 goto out;
1256 } 1291 }
1257 slot = radix_tree_indirect_to_ptr(slot); 1292 slot = indirect_to_ptr(slot);
1258 1293
1259 shift = (height - 1) * RADIX_TREE_MAP_SHIFT; 1294 shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
1260 pathp->node = NULL; 1295 pathp->node = NULL;
@@ -1296,8 +1331,7 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
1296 radix_tree_node_free(to_free); 1331 radix_tree_node_free(to_free);
1297 1332
1298 if (pathp->node->count) { 1333 if (pathp->node->count) {
1299 if (pathp->node == 1334 if (pathp->node == indirect_to_ptr(root->rnode))
1300 radix_tree_indirect_to_ptr(root->rnode))
1301 radix_tree_shrink(root); 1335 radix_tree_shrink(root);
1302 goto out; 1336 goto out;
1303 } 1337 }