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

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>

authored by

Cody P Schafer and committed by
Linus Torvalds
9dee5c51 b4bc4a18

+44
+4
include/linux/rbtree.h
··· 68 68 extern struct rb_node *rb_first(const struct rb_root *); 69 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 75 /* Fast replacement of a single node without remove/rebalance/add/rebalance */ 72 76 extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, 73 77 struct rb_root *root);
+40
lib/rbtree.c
··· 518 518 *new = *victim; 519 519 } 520 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);