From b519e868c4b450dd47e75674d60bcb2abd489d8e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 13 Oct 2021 11:23:33 +0200 Subject: [PATCH] Revert "lib/timerqueue: Rely on rbtree semantics for next timer" This reverts commit b9a1ac8e7c03fd09992352c7fb1a61cbbb9ad52b which is commit 511885d7061eda3eb1faf3f57dcc936ff75863f1 upstream. It breaks the abi and does not resolve an issue that is relevant to Android devices, so it can be reverted. Signed-off-by: Greg Kroah-Hartman Change-Id: I7b35b10c18f91bd132bf33de3572e272591976ae --- include/linux/timerqueue.h | 13 +++++++------ lib/timerqueue.c | 30 ++++++++++++++++++------------ 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/include/linux/timerqueue.h b/include/linux/timerqueue.h index aff122f1062a..78b8cc73f12f 100644 --- a/include/linux/timerqueue.h +++ b/include/linux/timerqueue.h @@ -12,7 +12,8 @@ struct timerqueue_node { }; struct timerqueue_head { - struct rb_root_cached rb_root; + struct rb_root head; + struct timerqueue_node *next; }; @@ -28,14 +29,13 @@ extern struct timerqueue_node *timerqueue_iterate_next( * * @head: head of timerqueue * - * Returns a pointer to the timer node that has the earliest expiration time. + * Returns a pointer to the timer node that has the + * earliest expiration time. */ static inline struct timerqueue_node *timerqueue_getnext(struct timerqueue_head *head) { - struct rb_node *leftmost = rb_first_cached(&head->rb_root); - - return rb_entry(leftmost, struct timerqueue_node, node); + return head->next; } static inline void timerqueue_init(struct timerqueue_node *node) @@ -45,6 +45,7 @@ static inline void timerqueue_init(struct timerqueue_node *node) static inline void timerqueue_init_head(struct timerqueue_head *head) { - head->rb_root = RB_ROOT_CACHED; + head->head = RB_ROOT; + head->next = NULL; } #endif /* _LINUX_TIMERQUEUE_H */ diff --git a/lib/timerqueue.c b/lib/timerqueue.c index 7a8ae3d5fd40..0d54bcbc8170 100644 --- a/lib/timerqueue.c +++ b/lib/timerqueue.c @@ -39,10 +39,9 @@ */ bool timerqueue_add(struct timerqueue_head *head, struct timerqueue_node *node) { - struct rb_node **p = &head->rb_root.rb_root.rb_node; + struct rb_node **p = &head->head.rb_node; struct rb_node *parent = NULL; - struct timerqueue_node *ptr; - bool leftmost = true; + struct timerqueue_node *ptr; /* Make sure we don't add nodes that are already added */ WARN_ON_ONCE(!RB_EMPTY_NODE(&node->node)); @@ -50,17 +49,19 @@ bool timerqueue_add(struct timerqueue_head *head, struct timerqueue_node *node) while (*p) { parent = *p; ptr = rb_entry(parent, struct timerqueue_node, node); - if (node->expires < ptr->expires) { + if (node->expires < ptr->expires) p = &(*p)->rb_left; - } else { + else p = &(*p)->rb_right; - leftmost = false; - } } rb_link_node(&node->node, parent, p); - rb_insert_color_cached(&node->node, &head->rb_root, leftmost); + rb_insert_color(&node->node, &head->head); - return leftmost; + if (!head->next || node->expires < head->next->expires) { + head->next = node; + return true; + } + return false; } EXPORT_SYMBOL_GPL(timerqueue_add); @@ -77,10 +78,15 @@ bool timerqueue_del(struct timerqueue_head *head, struct timerqueue_node *node) { WARN_ON_ONCE(RB_EMPTY_NODE(&node->node)); - rb_erase_cached(&node->node, &head->rb_root); - RB_CLEAR_NODE(&node->node); + /* update next pointer */ + if (head->next == node) { + struct rb_node *rbn = rb_next(&node->node); - return !RB_EMPTY_ROOT(&head->rb_root.rb_root); + head->next = rb_entry_safe(rbn, struct timerqueue_node, node); + } + rb_erase(&node->node, &head->head); + RB_CLEAR_NODE(&node->node); + return head->next != NULL; } EXPORT_SYMBOL_GPL(timerqueue_del);