Skip to content

Commit

Permalink
lib/rbtree.c: avoid the use of non-static __always_inline
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Michel Lespinasse authored and Linus Torvalds committed Jan 11, 2013
1 parent a8906b0 commit 3cb7a56
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 6 deletions.
14 changes: 11 additions & 3 deletions include/linux/rbtree_augmented.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ __rb_change_child(struct rb_node *old, struct rb_node *new,
extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root,
void (*augment_rotate)(struct rb_node *old, struct rb_node *new));

static __always_inline void
rb_erase_augmented(struct rb_node *node, struct rb_root *root,
const struct rb_augment_callbacks *augment)
static __always_inline struct rb_node *
__rb_erase_augmented(struct rb_node *node, struct rb_root *root,
const struct rb_augment_callbacks *augment)
{
struct rb_node *child = node->rb_right, *tmp = node->rb_left;
struct rb_node *parent, *rebalance;
Expand Down Expand Up @@ -217,6 +217,14 @@ rb_erase_augmented(struct rb_node *node, struct rb_root *root,
}

augment->propagate(tmp, NULL);
return rebalance;
}

static __always_inline void
rb_erase_augmented(struct rb_node *node, struct rb_root *root,
const struct rb_augment_callbacks *augment)
{
struct rb_node *rebalance = __rb_erase_augmented(node, root, augment);
if (rebalance)
__rb_erase_color(rebalance, root, augment->rotate);
}
Expand Down
20 changes: 17 additions & 3 deletions lib/rbtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,12 @@ __rb_insert(struct rb_node *node, struct rb_root *root,
}
}

__always_inline void
__rb_erase_color(struct rb_node *parent, struct rb_root *root,
/*
* Inline version for rb_erase() use - we want to be able to inline
* and eliminate the dummy_rotate callback there
*/
static __always_inline void
____rb_erase_color(struct rb_node *parent, struct rb_root *root,
void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
{
struct rb_node *node = NULL, *sibling, *tmp1, *tmp2;
Expand Down Expand Up @@ -355,6 +359,13 @@ __rb_erase_color(struct rb_node *parent, struct rb_root *root,
}
}
}

/* Non-inline version for rb_erase_augmented() use */
void __rb_erase_color(struct rb_node *parent, struct rb_root *root,
void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
{
____rb_erase_color(parent, root, augment_rotate);
}
EXPORT_SYMBOL(__rb_erase_color);

/*
Expand All @@ -380,7 +391,10 @@ EXPORT_SYMBOL(rb_insert_color);

void rb_erase(struct rb_node *node, struct rb_root *root)
{
rb_erase_augmented(node, root, &dummy_callbacks);
struct rb_node *rebalance;
rebalance = __rb_erase_augmented(node, root, &dummy_callbacks);
if (rebalance)
____rb_erase_color(rebalance, root, dummy_rotate);
}
EXPORT_SYMBOL(rb_erase);

Expand Down

0 comments on commit 3cb7a56

Please sign in to comment.