Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Matthew Wilcox and committed by
Linus Torvalds
0a2efc6c 8a14f4d8

+62 -57
+44 -45
lib/radix-tree.c
··· 1303 1303 #if defined(CONFIG_SHMEM) && defined(CONFIG_SWAP) 1304 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 1312 * This linear search is at present only useful to shmem_unuse_inode(). 1308 1313 */ 1309 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 1317 unsigned int shift, height; 1313 1318 unsigned long i; 1314 1319 1315 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--) { 1319 - i = (index >> shift) & RADIX_TREE_MAP_MASK; 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 - 1332 - slot = rcu_dereference_raw(slot->slots[i]); 1333 - if (slot == NULL) 1334 - goto out; 1335 - if (!radix_tree_is_indirect_ptr(slot)) { 1336 - if (slot == item) { 1337 - *found_index = index + i; 1338 - index = 0; 1339 - } else { 1340 - index += shift; 1341 - } 1342 - goto out; 1343 - } 1344 - slot = indirect_to_ptr(slot); 1323 + do { 1345 1324 shift -= RADIX_TREE_MAP_SHIFT; 1346 - } 1347 1325 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; 1326 + for (i = (index >> shift) & RADIX_TREE_MAP_MASK; 1327 + i < RADIX_TREE_MAP_SIZE; 1328 + i++, index += (1UL << shift)) { 1329 + struct radix_tree_node *node = 1330 + rcu_dereference_raw(slot->slots[i]); 1331 + if (node == RADIX_TREE_RETRY) 1332 + goto out; 1333 + if (!radix_tree_is_indirect_ptr(node)) { 1334 + if (node == item) { 1335 + info->found_index = index; 1336 + info->stop = true; 1337 + goto out; 1338 + } 1339 + continue; 1340 + } 1341 + node = indirect_to_ptr(node); 1342 + if (is_sibling_entry(slot, node)) 1343 + continue; 1344 + slot = node; 1345 + break; 1354 1346 } 1355 - } 1356 - index += RADIX_TREE_MAP_SIZE; 1347 + if (i == RADIX_TREE_MAP_SIZE) 1348 + break; 1349 + } while (shift); 1350 + 1357 1351 out: 1352 + if ((index == 0) && (i == RADIX_TREE_MAP_SIZE)) 1353 + info->stop = true; 1358 1354 return index; 1359 1355 } 1360 1356 ··· 1368 1372 struct radix_tree_node *node; 1369 1373 unsigned long max_index; 1370 1374 unsigned long cur_index = 0; 1371 - unsigned long found_index = -1; 1375 + struct locate_info info = { 1376 + .found_index = -1, 1377 + .stop = false, 1378 + }; 1372 1379 1373 1380 do { 1374 1381 rcu_read_lock(); ··· 1379 1380 if (!radix_tree_is_indirect_ptr(node)) { 1380 1381 rcu_read_unlock(); 1381 1382 if (node == item) 1382 - found_index = 0; 1383 + info.found_index = 0; 1383 1384 break; 1384 1385 } 1385 1386 1386 1387 node = indirect_to_ptr(node); 1387 - max_index = radix_tree_maxindex(node->path & 1388 - RADIX_TREE_HEIGHT_MASK); 1388 + 1389 + max_index = node_maxindex(node); 1389 1390 if (cur_index > max_index) { 1390 1391 rcu_read_unlock(); 1391 1392 break; 1392 1393 } 1393 1394 1394 - cur_index = __locate(node, item, cur_index, &found_index); 1395 + cur_index = __locate(node, item, cur_index, &info); 1395 1396 rcu_read_unlock(); 1396 1397 cond_resched(); 1397 - } while (cur_index != 0 && cur_index <= max_index); 1398 + } while (!info.stop && cur_index <= max_index); 1398 1399 1399 - return found_index; 1400 + return info.found_index; 1400 1401 } 1401 1402 #else 1402 1403 unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item)
+18 -12
tools/testing/radix-tree/main.c
··· 232 232 item_kill_tree(&tree); 233 233 } 234 234 235 - void __locate_check(struct radix_tree_root *tree, unsigned long index) 235 + void __locate_check(struct radix_tree_root *tree, unsigned long index, 236 + unsigned order) 236 237 { 237 238 struct item *item; 238 239 unsigned long index2; 239 240 240 - item_insert(tree, index); 241 + item_insert_order(tree, index, order); 241 242 item = item_lookup(tree, index); 242 243 index2 = radix_tree_locate_item(tree, item); 243 244 if (index != index2) { 244 - printf("index %ld inserted; found %ld\n", 245 - index, index2); 245 + printf("index %ld order %d inserted; found %ld\n", 246 + index, order, index2); 246 247 abort(); 247 248 } 248 249 } ··· 251 250 static void locate_check(void) 252 251 { 253 252 RADIX_TREE(tree, GFP_KERNEL); 253 + unsigned order; 254 254 unsigned long offset, index; 255 255 256 - for (offset = 0; offset < (1 << 3); offset++) { 257 - for (index = 0; index < (1UL << 5); index++) { 258 - __locate_check(&tree, index + offset); 259 - } 260 - if (radix_tree_locate_item(&tree, &tree) != -1) 261 - abort(); 256 + for (order = 0; order < 20; order++) { 257 + for (offset = 0; offset < (1 << (order + 3)); 258 + offset += (1UL << order)) { 259 + for (index = 0; index < (1UL << (order + 5)); 260 + index += (1UL << order)) { 261 + __locate_check(&tree, index + offset, order); 262 + } 263 + if (radix_tree_locate_item(&tree, &tree) != -1) 264 + abort(); 262 265 263 - item_kill_tree(&tree); 266 + item_kill_tree(&tree); 267 + } 264 268 } 265 269 266 270 if (radix_tree_locate_item(&tree, &tree) != -1) 267 271 abort(); 268 - __locate_check(&tree, -1); 272 + __locate_check(&tree, -1, 0); 269 273 if (radix_tree_locate_item(&tree, &tree) != -1) 270 274 abort(); 271 275 item_kill_tree(&tree);