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 | |
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>
-rw-r--r-- | include/linux/rbtree.h | 4 | ||||
-rw-r--r-- | lib/rbtree.c | 40 |
2 files changed, 44 insertions, 0 deletions
diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h index 0022c1bb1e26..c467151e9950 100644 --- a/include/linux/rbtree.h +++ b/include/linux/rbtree.h | |||
@@ -68,6 +68,10 @@ extern struct rb_node *rb_prev(const struct rb_node *); | |||
68 | extern struct rb_node *rb_first(const struct rb_root *); | 68 | extern struct rb_node *rb_first(const struct rb_root *); |
69 | extern struct rb_node *rb_last(const struct rb_root *); | 69 | extern struct rb_node *rb_last(const struct rb_root *); |
70 | 70 | ||
71 | /* Postorder iteration - always visit the parent after its children */ | ||
72 | extern struct rb_node *rb_first_postorder(const struct rb_root *); | ||
73 | extern struct rb_node *rb_next_postorder(const struct rb_node *); | ||
74 | |||
71 | /* Fast replacement of a single node without remove/rebalance/add/rebalance */ | 75 | /* Fast replacement of a single node without remove/rebalance/add/rebalance */ |
72 | extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, | 76 | extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, |
73 | struct rb_root *root); | 77 | struct rb_root *root); |
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); | ||