aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorMatthew Wilcox <willy@linux.intel.com>2016-05-20 20:02:11 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-05-20 20:58:30 -0400
commit49ea6ebcd3080ebf2c589b5f1437dd8bb2f90395 (patch)
treea6a7659f076d68efeeafa8fcd5c8f4d1ae731474 /lib
parent1456a439fc2dcc0c3d1a2d7af1fd83962813aaee (diff)
radix-tree: fix extending the tree for multi-order entries at offset 0
The current code will insert entries at each level, as if we're going to add a new entry at the bottom level, so we then get an -EEXIST when we try to insert the entry into the tree. The best way to fix this is to not check 'order' when inserting into an empty tree. We still need to 'extend' the tree to the height necessary for the maximum index corresponding to this entry, so pass that value to radix_tree_extend() rather than the index we're asked to create, or we won't create a tree that's deep enough. 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.c28
1 files changed, 17 insertions, 11 deletions
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 272ce810d29b..f13ddbba8ace 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -432,7 +432,7 @@ static unsigned radix_tree_load_root(struct radix_tree_root *root,
432 * Extend a radix tree so it can store key @index. 432 * Extend a radix tree so it can store key @index.
433 */ 433 */
434static int radix_tree_extend(struct radix_tree_root *root, 434static int radix_tree_extend(struct radix_tree_root *root,
435 unsigned long index, unsigned order) 435 unsigned long index)
436{ 436{
437 struct radix_tree_node *node; 437 struct radix_tree_node *node;
438 struct radix_tree_node *slot; 438 struct radix_tree_node *slot;
@@ -444,7 +444,7 @@ static int radix_tree_extend(struct radix_tree_root *root,
444 while (index > radix_tree_maxindex(height)) 444 while (index > radix_tree_maxindex(height))
445 height++; 445 height++;
446 446
447 if ((root->rnode == NULL) && (order == 0)) { 447 if (root->rnode == NULL) {
448 root->height = height; 448 root->height = height;
449 goto out; 449 goto out;
450 } 450 }
@@ -467,7 +467,7 @@ static int radix_tree_extend(struct radix_tree_root *root,
467 node->count = 1; 467 node->count = 1;
468 node->parent = NULL; 468 node->parent = NULL;
469 slot = root->rnode; 469 slot = root->rnode;
470 if (radix_tree_is_indirect_ptr(slot) && newheight > 1) { 470 if (radix_tree_is_indirect_ptr(slot)) {
471 slot = indirect_to_ptr(slot); 471 slot = indirect_to_ptr(slot);
472 slot->parent = node; 472 slot->parent = node;
473 slot = ptr_to_indirect(slot); 473 slot = ptr_to_indirect(slot);
@@ -478,7 +478,7 @@ static int radix_tree_extend(struct radix_tree_root *root,
478 root->height = newheight; 478 root->height = newheight;
479 } while (height > root->height); 479 } while (height > root->height);
480out: 480out:
481 return 0; 481 return height * RADIX_TREE_MAP_SHIFT;
482} 482}
483 483
484/** 484/**
@@ -503,20 +503,26 @@ int __radix_tree_create(struct radix_tree_root *root, unsigned long index,
503 void ***slotp) 503 void ***slotp)
504{ 504{
505 struct radix_tree_node *node = NULL, *slot; 505 struct radix_tree_node *node = NULL, *slot;
506 unsigned long maxindex;
506 unsigned int height, shift, offset; 507 unsigned int height, shift, offset;
507 int error; 508 unsigned long max = index | ((1UL << order) - 1);
509
510 shift = radix_tree_load_root(root, &slot, &maxindex);
508 511
509 /* Make sure the tree is high enough. */ 512 /* Make sure the tree is high enough. */
510 if (index > radix_tree_maxindex(root->height)) { 513 if (max > maxindex) {
511 error = radix_tree_extend(root, index, order); 514 int error = radix_tree_extend(root, max);
512 if (error) 515 if (error < 0)
513 return error; 516 return error;
517 shift = error;
518 slot = root->rnode;
519 if (order == shift) {
520 shift += RADIX_TREE_MAP_SHIFT;
521 root->height++;
522 }
514 } 523 }
515 524
516 slot = root->rnode;
517
518 height = root->height; 525 height = root->height;
519 shift = height * RADIX_TREE_MAP_SHIFT;
520 526
521 offset = 0; /* uninitialised var warning */ 527 offset = 0; /* uninitialised var warning */
522 while (shift > order) { 528 while (shift > order) {