Prior to this commit, if you submitted the same callback_head twice, it would be enqueued twice, but only if it was the last callback on the list. The first time it was submitted, rq->balance_callback was NULL, so head->next is NULL. That defeated the check in queue_balance_callback().
This commit changes the callback list such that whenever an item is on the list, its head->next is not NULL. The last element (first inserted) will point to itself. This allows us to detect and ignore any attempt to reenqueue a callback_head. Signed-off-by: Barret Rhoden <b...@google.com> --- sorry about the old version. i updated to linus's branch, plus a minor fix from v1. this should work with the balance_push_callback stuff you added a few months ago. in this commit, head->next can equal null *or* head and it will be treated as null. (balance_push_callback's next == NULL). thanks, barret kernel/sched/core.c | 3 ++- kernel/sched/sched.h | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 98191218d891..c5a1a225d0b4 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -3986,7 +3986,8 @@ static void do_balance_callbacks(struct rq *rq, struct callback_head *head) while (head) { func = (void (*)(struct rq *))head->func; - next = head->next; + /* The last element pointed to itself */ + next = head->next == head ? NULL : head->next; head->next = NULL; head = next; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 10a1522b1e30..66e1a9e5a1af 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1418,11 +1418,15 @@ queue_balance_callback(struct rq *rq, { lockdep_assert_held(&rq->lock); + /* + * The last element on the list points to itself, so we can always + * detect if head is already enqueued. + */ if (unlikely(head->next || rq->balance_callback == &balance_push_callback)) return; head->func = (void (*)(struct callback_head *))func; - head->next = rq->balance_callback; + head->next = rq->balance_callback ?: head; rq->balance_callback = head; } -- 2.31.0.rc2.261.g7f71774620-goog