diff options
| author | Cody P Schafer <cody@linux.vnet.ibm.com> | 2013-09-11 17:25:10 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-11 18:59:19 -0400 |
| commit | 9dee5c51516d2c3fff22633c1272c5652e68075a (patch) | |
| tree | b8d1811b0357a74c720008911e06559f772ce731 /lib | |
| parent | b4bc4a18a226f46fec4ef47f2df28ea209db8b5d (diff) | |
rbtree: add postorder iteration functions
Postorder iteration yields all of a node's children prior to yielding the
node itself, and this particular implementation also avoids examining the
leaf links in a node after that node has been yielded.
In what I expect will be its most common usage, postorder iteration allows
the deletion of every node in an rbtree without modifying the rbtree nodes
(no _requirement_ that they be nulled) while avoiding referencing child
nodes after they have been "deleted" (most commonly, freed).
I have only updated zswap to use this functionality at this point, but
numerous bits of code (most notably in the filesystem drivers) use a hand
rolled postorder iteration that NULLs child links as it traverses the
tree. Each of those instances could be replaced with this common
implementation.
1 & 2 add rbtree postorder iteration functions.
3 adds testing of the iteration to the rbtree runtime tests
4 allows building the rbtree runtime tests as builtins
5 updates zswap.
This patch:
Add postorder iteration functions for rbtree. These are useful for safely
freeing an entire rbtree without modifying the tree at all.
Signed-off-by: Cody P Schafer <cody@linux.vnet.ibm.com>
Reviewed-by: Seth Jennings <sjenning@linux.vnet.ibm.com>
Cc: David Woodhouse <David.Woodhouse@intel.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Michel Lespinasse <walken@google.com>
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/rbtree.c | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/lib/rbtree.c b/lib/rbtree.c index c0e31fe2fabf..65f4effd117f 100644 --- a/lib/rbtree.c +++ b/lib/rbtree.c | |||
| @@ -518,3 +518,43 @@ void rb_replace_node(struct rb_node *victim, struct rb_node *new, | |||
| 518 | *new = *victim; | 518 | *new = *victim; |
| 519 | } | 519 | } |
| 520 | EXPORT_SYMBOL(rb_replace_node); | 520 | EXPORT_SYMBOL(rb_replace_node); |
| 521 | |||
| 522 | static struct rb_node *rb_left_deepest_node(const struct rb_node *node) | ||
| 523 | { | ||
| 524 | for (;;) { | ||
| 525 | if (node->rb_left) | ||
| 526 | node = node->rb_left; | ||
| 527 | else if (node->rb_right) | ||
| 528 | node = node->rb_right; | ||
| 529 | else | ||
| 530 | return (struct rb_node *)node; | ||
| 531 | } | ||
| 532 | } | ||
| 533 | |||
| 534 | struct rb_node *rb_next_postorder(const struct rb_node *node) | ||
| 535 | { | ||
| 536 | const struct rb_node *parent; | ||
| 537 | if (!node) | ||
| 538 | return NULL; | ||
| 539 | parent = rb_parent(node); | ||
| 540 | |||
| 541 | /* If we're sitting on node, we've already seen our children */ | ||
| 542 | if (parent && node == parent->rb_left && parent->rb_right) { | ||
| 543 | /* If we are the parent's left node, go to the parent's right | ||
| 544 | * node then all the way down to the left */ | ||
| 545 | return rb_left_deepest_node(parent->rb_right); | ||
| 546 | } else | ||
| 547 | /* Otherwise we are the parent's right node, and the parent | ||
| 548 | * should be next */ | ||
| 549 | return (struct rb_node *)parent; | ||
| 550 | } | ||
| 551 | EXPORT_SYMBOL(rb_next_postorder); | ||
| 552 | |||
| 553 | struct rb_node *rb_first_postorder(const struct rb_root *root) | ||
| 554 | { | ||
| 555 | if (!root->rb_node) | ||
| 556 | return NULL; | ||
| 557 | |||
| 558 | return rb_left_deepest_node(root->rb_node); | ||
| 559 | } | ||
| 560 | EXPORT_SYMBOL(rb_first_postorder); | ||
