diff --git a/[refs] b/[refs] index 8f4043b982dd..edd1050f4d57 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: c8446b75be6f85b3d40066922876cb7adc948afb +refs/heads/master: e0bbe2d80c415bd4063d894ec2ccb336788af814 diff --git a/trunk/kernel/irq_work.c b/trunk/kernel/irq_work.c index 57be1a6cd8da..64eddd59ed83 100644 --- a/trunk/kernel/irq_work.c +++ b/trunk/kernel/irq_work.c @@ -34,15 +34,21 @@ static DEFINE_PER_CPU(struct llist_head, irq_work_list); */ static bool irq_work_claim(struct irq_work *work) { - unsigned long flags, nflags; + unsigned long flags, oflags, nflags; + /* + * Start with our best wish as a premise but only trust any + * flag value after cmpxchg() result. + */ + flags = work->flags & ~IRQ_WORK_PENDING; for (;;) { - flags = work->flags; - if (flags & IRQ_WORK_PENDING) - return false; nflags = flags | IRQ_WORK_FLAGS; - if (cmpxchg(&work->flags, flags, nflags) == flags) + oflags = cmpxchg(&work->flags, flags, nflags); + if (oflags == flags) break; + if (oflags & IRQ_WORK_PENDING) + return false; + flags = oflags; cpu_relax(); }