aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorMatthew Wilcox <willy@linux.intel.com>2016-05-20 20:02:46 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-05-20 20:58:30 -0400
commit0a2efc6c809b01872321d9c7e7d82d59ac6fde10 (patch)
tree18b67497a5df2dfe015ed03fe665fae59f0311ca /lib
parent8a14f4d8328cc8615f8a5487c4173f36a8314796 (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.c87
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
1306struct 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 */
1309static unsigned long __locate(struct radix_tree_node *slot, void *item, 1314static 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;
1357out: 1351out:
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
1403unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item) 1402unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item)