diff options
Diffstat (limited to 'kernel/irq_work.c')
-rw-r--r-- | kernel/irq_work.c | 21 |
1 files changed, 15 insertions, 6 deletions
diff --git a/kernel/irq_work.c b/kernel/irq_work.c index 1588e3b2871b..64eddd59ed83 100644 --- a/kernel/irq_work.c +++ b/kernel/irq_work.c | |||
@@ -34,15 +34,21 @@ static DEFINE_PER_CPU(struct llist_head, irq_work_list); | |||
34 | */ | 34 | */ |
35 | static bool irq_work_claim(struct irq_work *work) | 35 | static bool irq_work_claim(struct irq_work *work) |
36 | { | 36 | { |
37 | unsigned long flags, nflags; | 37 | unsigned long flags, oflags, nflags; |
38 | 38 | ||
39 | /* | ||
40 | * Start with our best wish as a premise but only trust any | ||
41 | * flag value after cmpxchg() result. | ||
42 | */ | ||
43 | flags = work->flags & ~IRQ_WORK_PENDING; | ||
39 | for (;;) { | 44 | for (;;) { |
40 | flags = work->flags; | ||
41 | if (flags & IRQ_WORK_PENDING) | ||
42 | return false; | ||
43 | nflags = flags | IRQ_WORK_FLAGS; | 45 | nflags = flags | IRQ_WORK_FLAGS; |
44 | if (cmpxchg(&work->flags, flags, nflags) == flags) | 46 | oflags = cmpxchg(&work->flags, flags, nflags); |
47 | if (oflags == flags) | ||
45 | break; | 48 | break; |
49 | if (oflags & IRQ_WORK_PENDING) | ||
50 | return false; | ||
51 | flags = oflags; | ||
46 | cpu_relax(); | 52 | cpu_relax(); |
47 | } | 53 | } |
48 | 54 | ||
@@ -119,8 +125,11 @@ void irq_work_run(void) | |||
119 | /* | 125 | /* |
120 | * Clear the PENDING bit, after this point the @work | 126 | * Clear the PENDING bit, after this point the @work |
121 | * can be re-used. | 127 | * can be re-used. |
128 | * Make it immediately visible so that other CPUs trying | ||
129 | * to claim that work don't rely on us to handle their data | ||
130 | * while we are in the middle of the func. | ||
122 | */ | 131 | */ |
123 | work->flags = IRQ_WORK_BUSY; | 132 | xchg(&work->flags, IRQ_WORK_BUSY); |
124 | work->func(work); | 133 | work->func(work); |
125 | /* | 134 | /* |
126 | * Clear the BUSY bit and return to the free state if | 135 | * Clear the BUSY bit and return to the free state if |