Skip to content

Commit

Permalink
kernel/async.c: revert "async: simplify lowest_in_progress()"
Browse files Browse the repository at this point in the history
This reverts commit 92266d6 ("async: simplify lowest_in_progress()")
which was simply wrong: In the case where domain is NULL, we now use the
wrong offsetof() in the list_first_entry macro, so we don't actually
fetch the ->cookie value, but rather the eight bytes located
sizeof(struct list_head) further into the struct async_entry.

On 64 bit, that's the data member, while on 32 bit, that's a u64 built
from func and data in some order.

I think the bug happens to be harmless in practice: It obviously only
affects callers which pass a NULL domain, and AFAICT the only such
caller is

  async_synchronize_full() ->
  async_synchronize_full_domain(NULL) ->
  async_synchronize_cookie_domain(ASYNC_COOKIE_MAX, NULL)

and the ASYNC_COOKIE_MAX means that in practice we end up waiting for
the async_global_pending list to be empty - but it would break if
somebody happened to pass (void*)-1 as the data element to
async_schedule, and of course also if somebody ever does a
async_synchronize_cookie_domain(, NULL) with a "finite" cookie value.

Maybe the "harmless in practice" means this isn't -stable material.  But
I'm not completely confident my quick git grep'ing is enough, and there
might be affected code in one of the earlier kernels that has since been
removed, so I'll leave the decision to the stable guys.

Link: http://lkml.kernel.org/r/[email protected]
Fixes: 92266d6 "async: simplify lowest_in_progress()"
Signed-off-by: Rasmus Villemoes <[email protected]>
Acked-by: Tejun Heo <[email protected]>
Cc: Arjan van de Ven <[email protected]>
Cc: Adam Wallis <[email protected]>
Cc: Lai Jiangshan <[email protected]>
Cc: <[email protected]>	[3.10+]
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Villemoes authored and torvalds committed Feb 7, 2018
1 parent ad343a9 commit 4f7e988
Showing 1 changed file with 12 additions and 8 deletions.
20 changes: 12 additions & 8 deletions kernel/async.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,24 @@ static atomic_t entry_count;

static async_cookie_t lowest_in_progress(struct async_domain *domain)
{
struct list_head *pending;
struct async_entry *first = NULL;
async_cookie_t ret = ASYNC_COOKIE_MAX;
unsigned long flags;

spin_lock_irqsave(&async_lock, flags);

if (domain)
pending = &domain->pending;
else
pending = &async_global_pending;
if (domain) {
if (!list_empty(&domain->pending))
first = list_first_entry(&domain->pending,
struct async_entry, domain_list);
} else {
if (!list_empty(&async_global_pending))
first = list_first_entry(&async_global_pending,
struct async_entry, global_list);
}

if (!list_empty(pending))
ret = list_first_entry(pending, struct async_entry,
domain_list)->cookie;
if (first)
ret = first->cookie;

spin_unlock_irqrestore(&async_lock, flags);
return ret;
Expand Down

0 comments on commit 4f7e988

Please sign in to comment.