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

lib/rbtree.c: avoid the use of non-static __always_inline

lib/rbtree.c declared __rb_erase_color() as __always_inline void, and
then exported it with EXPORT_SYMBOL.

This was because __rb_erase_color() must be exported for augmented
rbtree users, but it must also be inlined into rb_erase() so that the
dummy callback can get optimized out of that call site.

(Actually with a modern compiler, none of the dummy callback functions
should even be generated as separate text functions).

The above usage is legal C, but it was unusual enough for some compilers
to warn about it. This change makes things more explicit, with a static
__always_inline ____rb_erase_color function for use in rb_erase(), and a
separate non-inline __rb_erase_color function for use in
rb_erase_augmented call sites.

Signed-off-by: Michel Lespinasse <walken@google.com>
Reported-by: Wu Fengguang <fengguang.wu@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Michel Lespinasse and committed by
Linus Torvalds
3cb7a563 a8906b0b

+28 -6
+11 -3
include/linux/rbtree_augmented.h
··· 123 123 extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root, 124 124 void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); 125 125 126 - static __always_inline void 127 - rb_erase_augmented(struct rb_node *node, struct rb_root *root, 128 - const struct rb_augment_callbacks *augment) 126 + static __always_inline struct rb_node * 127 + __rb_erase_augmented(struct rb_node *node, struct rb_root *root, 128 + const struct rb_augment_callbacks *augment) 129 129 { 130 130 struct rb_node *child = node->rb_right, *tmp = node->rb_left; 131 131 struct rb_node *parent, *rebalance; ··· 217 217 } 218 218 219 219 augment->propagate(tmp, NULL); 220 + return rebalance; 221 + } 222 + 223 + static __always_inline void 224 + rb_erase_augmented(struct rb_node *node, struct rb_root *root, 225 + const struct rb_augment_callbacks *augment) 226 + { 227 + struct rb_node *rebalance = __rb_erase_augmented(node, root, augment); 220 228 if (rebalance) 221 229 __rb_erase_color(rebalance, root, augment->rotate); 222 230 }
+17 -3
lib/rbtree.c
··· 194 194 } 195 195 } 196 196 197 - __always_inline void 198 - __rb_erase_color(struct rb_node *parent, struct rb_root *root, 197 + /* 198 + * Inline version for rb_erase() use - we want to be able to inline 199 + * and eliminate the dummy_rotate callback there 200 + */ 201 + static __always_inline void 202 + ____rb_erase_color(struct rb_node *parent, struct rb_root *root, 199 203 void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) 200 204 { 201 205 struct rb_node *node = NULL, *sibling, *tmp1, *tmp2; ··· 359 355 } 360 356 } 361 357 } 358 + 359 + /* Non-inline version for rb_erase_augmented() use */ 360 + void __rb_erase_color(struct rb_node *parent, struct rb_root *root, 361 + void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) 362 + { 363 + ____rb_erase_color(parent, root, augment_rotate); 364 + } 362 365 EXPORT_SYMBOL(__rb_erase_color); 363 366 364 367 /* ··· 391 380 392 381 void rb_erase(struct rb_node *node, struct rb_root *root) 393 382 { 394 - rb_erase_augmented(node, root, &dummy_callbacks); 383 + struct rb_node *rebalance; 384 + rebalance = __rb_erase_augmented(node, root, &dummy_callbacks); 385 + if (rebalance) 386 + ____rb_erase_color(rebalance, root, dummy_rotate); 395 387 } 396 388 EXPORT_SYMBOL(rb_erase); 397 389