diff options
author | Matthew Wilcox <willy@linux.intel.com> | 2016-05-20 20:02:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-20 20:58:30 -0400 |
commit | 0a2efc6c809b01872321d9c7e7d82d59ac6fde10 (patch) | |
tree | 18b67497a5df2dfe015ed03fe665fae59f0311ca /lib | |
parent | 8a14f4d8328cc8615f8a5487c4173f36a8314796 (diff) |
radix-tree: rewrite radix_tree_locate_item
Use the new multi-order support functions to rewrite
radix_tree_locate_item(). Modify the locate tests to test multiorder
entries too.
[hughd@google.com: radix_tree_locate_item() is often returning the wrong index]
Link: http://lkml.kernel.org/r/alpine.LSU.2.11.1605012108490.1166@eggly.anvils
Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
Reviewed-by: Ross Zwisler <ross.zwisler@linux.intel.com>
Cc: Konstantin Khlebnikov <koct9i@gmail.com>
Cc: Kirill Shutemov <kirill.shutemov@linux.intel.com>
Cc: Jan Kara <jack@suse.com>
Cc: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/radix-tree.c | 87 |
1 files changed, 43 insertions, 44 deletions
diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 9b5d8a963897..8329a2e950eb 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c | |||
@@ -1303,58 +1303,54 @@ EXPORT_SYMBOL(radix_tree_gang_lookup_tag_slot); | |||
1303 | #if defined(CONFIG_SHMEM) && defined(CONFIG_SWAP) | 1303 | #if defined(CONFIG_SHMEM) && defined(CONFIG_SWAP) |
1304 | #include <linux/sched.h> /* for cond_resched() */ | 1304 | #include <linux/sched.h> /* for cond_resched() */ |
1305 | 1305 | ||
1306 | struct locate_info { | ||
1307 | unsigned long found_index; | ||
1308 | bool stop; | ||
1309 | }; | ||
1310 | |||
1306 | /* | 1311 | /* |
1307 | * This linear search is at present only useful to shmem_unuse_inode(). | 1312 | * This linear search is at present only useful to shmem_unuse_inode(). |
1308 | */ | 1313 | */ |
1309 | static unsigned long __locate(struct radix_tree_node *slot, void *item, | 1314 | static unsigned long __locate(struct radix_tree_node *slot, void *item, |
1310 | unsigned long index, unsigned long *found_index) | 1315 | unsigned long index, struct locate_info *info) |
1311 | { | 1316 | { |
1312 | unsigned int shift, height; | 1317 | unsigned int shift, height; |
1313 | unsigned long i; | 1318 | unsigned long i; |
1314 | 1319 | ||
1315 | height = slot->path & RADIX_TREE_HEIGHT_MASK; | 1320 | height = slot->path & RADIX_TREE_HEIGHT_MASK; |
1316 | shift = (height-1) * RADIX_TREE_MAP_SHIFT; | 1321 | shift = height * RADIX_TREE_MAP_SHIFT; |
1317 | 1322 | ||
1318 | for ( ; height > 1; height--) { | 1323 | do { |
1319 | i = (index >> shift) & RADIX_TREE_MAP_MASK; | 1324 | shift -= RADIX_TREE_MAP_SHIFT; |
1320 | for (;;) { | ||
1321 | if (slot->slots[i] != NULL) | ||
1322 | break; | ||
1323 | index &= ~((1UL << shift) - 1); | ||
1324 | index += 1UL << shift; | ||
1325 | if (index == 0) | ||
1326 | goto out; /* 32-bit wraparound */ | ||
1327 | i++; | ||
1328 | if (i == RADIX_TREE_MAP_SIZE) | ||
1329 | goto out; | ||
1330 | } | ||
1331 | 1325 | ||
1332 | slot = rcu_dereference_raw(slot->slots[i]); | 1326 | for (i = (index >> shift) & RADIX_TREE_MAP_MASK; |
1333 | if (slot == NULL) | 1327 | i < RADIX_TREE_MAP_SIZE; |
1334 | goto out; | 1328 | i++, index += (1UL << shift)) { |
1335 | if (!radix_tree_is_indirect_ptr(slot)) { | 1329 | struct radix_tree_node *node = |
1336 | if (slot == item) { | 1330 | rcu_dereference_raw(slot->slots[i]); |
1337 | *found_index = index + i; | 1331 | if (node == RADIX_TREE_RETRY) |
1338 | index = 0; | 1332 | goto out; |
1339 | } else { | 1333 | if (!radix_tree_is_indirect_ptr(node)) { |
1340 | index += shift; | 1334 | if (node == item) { |
1335 | info->found_index = index; | ||
1336 | info->stop = true; | ||
1337 | goto out; | ||
1338 | } | ||
1339 | continue; | ||
1341 | } | 1340 | } |
1342 | goto out; | 1341 | node = indirect_to_ptr(node); |
1342 | if (is_sibling_entry(slot, node)) | ||
1343 | continue; | ||
1344 | slot = node; | ||
1345 | break; | ||
1343 | } | 1346 | } |
1344 | slot = indirect_to_ptr(slot); | 1347 | if (i == RADIX_TREE_MAP_SIZE) |
1345 | shift -= RADIX_TREE_MAP_SHIFT; | 1348 | break; |
1346 | } | 1349 | } while (shift); |
1347 | 1350 | ||
1348 | /* Bottom level: check items */ | ||
1349 | for (i = 0; i < RADIX_TREE_MAP_SIZE; i++) { | ||
1350 | if (slot->slots[i] == item) { | ||
1351 | *found_index = index + i; | ||
1352 | index = 0; | ||
1353 | goto out; | ||
1354 | } | ||
1355 | } | ||
1356 | index += RADIX_TREE_MAP_SIZE; | ||
1357 | out: | 1351 | out: |
1352 | if ((index == 0) && (i == RADIX_TREE_MAP_SIZE)) | ||
1353 | info->stop = true; | ||
1358 | return index; | 1354 | return index; |
1359 | } | 1355 | } |
1360 | 1356 | ||
@@ -1372,7 +1368,10 @@ unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item) | |||
1372 | struct radix_tree_node *node; | 1368 | struct radix_tree_node *node; |
1373 | unsigned long max_index; | 1369 | unsigned long max_index; |
1374 | unsigned long cur_index = 0; | 1370 | unsigned long cur_index = 0; |
1375 | unsigned long found_index = -1; | 1371 | struct locate_info info = { |
1372 | .found_index = -1, | ||
1373 | .stop = false, | ||
1374 | }; | ||
1376 | 1375 | ||
1377 | do { | 1376 | do { |
1378 | rcu_read_lock(); | 1377 | rcu_read_lock(); |
@@ -1380,24 +1379,24 @@ unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item) | |||
1380 | if (!radix_tree_is_indirect_ptr(node)) { | 1379 | if (!radix_tree_is_indirect_ptr(node)) { |
1381 | rcu_read_unlock(); | 1380 | rcu_read_unlock(); |
1382 | if (node == item) | 1381 | if (node == item) |
1383 | found_index = 0; | 1382 | info.found_index = 0; |
1384 | break; | 1383 | break; |
1385 | } | 1384 | } |
1386 | 1385 | ||
1387 | node = indirect_to_ptr(node); | 1386 | node = indirect_to_ptr(node); |
1388 | max_index = radix_tree_maxindex(node->path & | 1387 | |
1389 | RADIX_TREE_HEIGHT_MASK); | 1388 | max_index = node_maxindex(node); |
1390 | if (cur_index > max_index) { | 1389 | if (cur_index > max_index) { |
1391 | rcu_read_unlock(); | 1390 | rcu_read_unlock(); |
1392 | break; | 1391 | break; |
1393 | } | 1392 | } |
1394 | 1393 | ||
1395 | cur_index = __locate(node, item, cur_index, &found_index); | 1394 | cur_index = __locate(node, item, cur_index, &info); |
1396 | rcu_read_unlock(); | 1395 | rcu_read_unlock(); |
1397 | cond_resched(); | 1396 | cond_resched(); |
1398 | } while (cur_index != 0 && cur_index <= max_index); | 1397 | } while (!info.stop && cur_index <= max_index); |
1399 | 1398 | ||
1400 | return found_index; | 1399 | return info.found_index; |
1401 | } | 1400 | } |
1402 | #else | 1401 | #else |
1403 | unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item) | 1402 | unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item) |