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);