rbtree: Add support for augmented rbtrees

Add support for augmented rbtrees in core rbtree code.

This will be used in subsequent patches, in x86 PAT code, which needs
interval trees to efficiently keep track of PAT ranges.

Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
LKML-Reference: <20100210232343.GA11465@linux-os.sc.intel.com>
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>

authored by Pallipadi, Venkatesh and committed by H. Peter Anvin 17d9ddc7 724e6d3f

+106 -5
+58
Documentation/rbtree.txt
··· 190 190 for (node = rb_first(&mytree); node; node = rb_next(node)) 191 191 printk("key=%s\n", rb_entry(node, struct mytype, node)->keystring); 192 192 193 + Support for Augmented rbtrees 194 + ----------------------------- 195 + 196 + Augmented rbtree is an rbtree with "some" additional data stored in each node. 197 + This data can be used to augment some new functionality to rbtree. 198 + Augmented rbtree is an optional feature built on top of basic rbtree 199 + infrastructure. rbtree user who wants this feature will have an augment 200 + callback function in rb_root initialized. 201 + 202 + This callback function will be called from rbtree core routines whenever 203 + a node has a change in one or both of its children. It is the responsibility 204 + of the callback function to recalculate the additional data that is in the 205 + rb node using new children information. Note that if this new additional 206 + data affects the parent node's additional data, then callback function has 207 + to handle it and do the recursive updates. 208 + 209 + 210 + Interval tree is an example of augmented rb tree. Reference - 211 + "Introduction to Algorithms" by Cormen, Leiserson, Rivest and Stein. 212 + More details about interval trees: 213 + 214 + Classical rbtree has a single key and it cannot be directly used to store 215 + interval ranges like [lo:hi] and do a quick lookup for any overlap with a new 216 + lo:hi or to find whether there is an exact match for a new lo:hi. 217 + 218 + However, rbtree can be augmented to store such interval ranges in a structured 219 + way making it possible to do efficient lookup and exact match. 220 + 221 + This "extra information" stored in each node is the maximum hi 222 + (max_hi) value among all the nodes that are its descendents. This 223 + information can be maintained at each node just be looking at the node 224 + and its immediate children. And this will be used in O(log n) lookup 225 + for lowest match (lowest start address among all possible matches) 226 + with something like: 227 + 228 + find_lowest_match(lo, hi, node) 229 + { 230 + lowest_match = NULL; 231 + while (node) { 232 + if (max_hi(node->left) > lo) { 233 + // Lowest overlap if any must be on left side 234 + node = node->left; 235 + } else if (overlap(lo, hi, node)) { 236 + lowest_match = node; 237 + break; 238 + } else if (lo > node->lo) { 239 + // Lowest overlap if any must be on right side 240 + node = node->right; 241 + } else { 242 + break; 243 + } 244 + } 245 + return lowest_match; 246 + } 247 + 248 + Finding exact match will be to first find lowest match and then to follow 249 + successor nodes looking for exact match, until the start of a node is beyond 250 + the hi value we are looking for.
+4 -1
include/linux/rbtree.h
··· 110 110 struct rb_root 111 111 { 112 112 struct rb_node *rb_node; 113 + void (*augment_cb)(struct rb_node *node); 113 114 }; 114 115 115 116 ··· 130 129 rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; 131 130 } 132 131 133 - #define RB_ROOT (struct rb_root) { NULL, } 132 + #define RB_ROOT (struct rb_root) { NULL, NULL, } 133 + #define RB_AUGMENT_ROOT(x) (struct rb_root) { NULL, x} 134 + 134 135 #define rb_entry(ptr, type, member) container_of(ptr, type, member) 135 136 136 137 #define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
+44 -4
lib/rbtree.c
··· 44 44 else 45 45 root->rb_node = right; 46 46 rb_set_parent(node, right); 47 + 48 + if (root->augment_cb) { 49 + root->augment_cb(node); 50 + root->augment_cb(right); 51 + } 47 52 } 48 53 49 54 static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) ··· 72 67 else 73 68 root->rb_node = left; 74 69 rb_set_parent(node, left); 70 + 71 + if (root->augment_cb) { 72 + root->augment_cb(node); 73 + root->augment_cb(left); 74 + } 75 75 } 76 76 77 77 void rb_insert_color(struct rb_node *node, struct rb_root *root) 78 78 { 79 79 struct rb_node *parent, *gparent; 80 + 81 + if (root->augment_cb) 82 + root->augment_cb(node); 80 83 81 84 while ((parent = rb_parent(node)) && rb_is_red(parent)) 82 85 { ··· 240 227 else 241 228 { 242 229 struct rb_node *old = node, *left; 230 + int old_parent_cb = 0; 231 + int successor_parent_cb = 0; 243 232 244 233 node = node->rb_right; 245 234 while ((left = node->rb_left) != NULL) 246 235 node = left; 247 236 248 237 if (rb_parent(old)) { 238 + old_parent_cb = 1; 249 239 if (rb_parent(old)->rb_left == old) 250 240 rb_parent(old)->rb_left = node; 251 241 else ··· 263 247 if (parent == old) { 264 248 parent = node; 265 249 } else { 250 + successor_parent_cb = 1; 266 251 if (child) 267 252 rb_set_parent(child, parent); 253 + 268 254 parent->rb_left = child; 269 255 270 256 node->rb_right = old->rb_right; ··· 277 259 node->rb_left = old->rb_left; 278 260 rb_set_parent(old->rb_left, node); 279 261 262 + if (root->augment_cb) { 263 + /* 264 + * Here, three different nodes can have new children. 265 + * The parent of the successor node that was selected 266 + * to replace the node to be erased. 267 + * The node that is getting erased and is now replaced 268 + * by its successor. 269 + * The parent of the node getting erased-replaced. 270 + */ 271 + if (successor_parent_cb) 272 + root->augment_cb(parent); 273 + 274 + root->augment_cb(node); 275 + 276 + if (old_parent_cb) 277 + root->augment_cb(rb_parent(old)); 278 + } 279 + 280 280 goto color; 281 281 } 282 282 ··· 303 267 304 268 if (child) 305 269 rb_set_parent(child, parent); 306 - if (parent) 307 - { 270 + 271 + if (parent) { 308 272 if (parent->rb_left == node) 309 273 parent->rb_left = child; 310 274 else 311 275 parent->rb_right = child; 312 - } 313 - else 276 + 277 + if (root->augment_cb) 278 + root->augment_cb(parent); 279 + 280 + } else { 314 281 root->rb_node = child; 282 + } 315 283 316 284 color: 317 285 if (color == RB_BLACK)