We need to convert flags to atomic_t in order to later fix an ordering issue on atomic_cmpxchg() failure. This will allow us to use atomic_fetch_or(). Also clarify the nature of those flags. [ mingo: Converted two more usage site the original patch missed. ]
Unified · Split
| @@ -22,7 +22,7 @@ · 21 unmodified lines | ||
| 22 | 22 | #define IRQ_WORK_CLAIMED (IRQ_WORK_PENDING | IRQ_WORK_BUSY) |
| 23 | 23 | |
| 24 | 24 | struct irq_work { |
| 25 | − unsigned long flags; | |
| 25 | + atomic_t flags; | |
| 26 | 26 | struct llist_node llnode; |
| 27 | 27 | void (*func)(struct irq_work *); |
| 28 | 28 | }; |
| @@ -30,11 +30,15 @@ struct irq_work { · 1 unmodified line | ||
| 30 | 30 | static inline |
| 31 | 31 | void init_irq_work(struct irq_work *work, void (*func)(struct irq_work *)) |
| 32 | 32 | { |
| 33 | − work->flags = 0; | |
| 33 | + atomic_set(&work->flags, 0); | |
| 34 | 34 | work->func = func; |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | −#define DEFINE_IRQ_WORK(name, _f) struct irq_work name = { .func = (_f), } | |
| 37 | +#define DEFINE_IRQ_WORK(name, _f) struct irq_work name = { \ | |
| 38 | + .flags = ATOMIC_INIT(0), \ | |
| 39 | + .func = (_f) \ | |
| 40 | +} | |
| 41 | + | |
| 38 | 42 | |
| 39 | 43 | bool irq_work_queue(struct irq_work *work); |
| 40 | 44 | bool irq_work_queue_on(struct irq_work *work, int cpu); |
| @@ -289,7 +289,7 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs, · 288 unmodified lines | ||
| 289 | 289 | |
| 290 | 290 | if (in_nmi()) { |
| 291 | 291 | work = this_cpu_ptr(&up_read_work); |
| 292 | − if (work->irq_work.flags & IRQ_WORK_BUSY) | |
| 292 | + if (atomic_read(&work->irq_work.flags) & IRQ_WORK_BUSY) | |
| 293 | 293 | /* cannot queue more up_read, fallback */ |
| 294 | 294 | irq_work_busy = true; |
| 295 | 295 | } |
| @@ -29,16 +29,16 @@ static DEFINE_PER_CPU(struct llist_head, lazy_list); · 28 unmodified lines | ||
| 29 | 29 | */ |
| 30 | 30 | static bool irq_work_claim(struct irq_work *work) |
| 31 | 31 | { |
| 32 | − unsigned long flags, oflags, nflags; | |
| 32 | + int flags, oflags, nflags; | |
| 33 | 33 | |
| 34 | 34 | /* |
| 35 | 35 | * Start with our best wish as a premise but only trust any |
| 36 | 36 | * flag value after cmpxchg() result. |
| 37 | 37 | */ |
| 38 | − flags = work->flags & ~IRQ_WORK_PENDING; | |
| 38 | + flags = atomic_read(&work->flags) & ~IRQ_WORK_PENDING; | |
| 39 | 39 | for (;;) { |
| 40 | 40 | nflags = flags | IRQ_WORK_CLAIMED; |
| 41 | − oflags = cmpxchg(&work->flags, flags, nflags); | |
| 41 | + oflags = atomic_cmpxchg(&work->flags, flags, nflags); | |
| 42 | 42 | if (oflags == flags) |
| 43 | 43 | break; |
| 44 | 44 | if (oflags & IRQ_WORK_PENDING) |
| @@ -61,7 +61,7 @@ void __weak arch_irq_work_raise(void) · 16 unmodified lines | ||
| 61 | 61 | static void __irq_work_queue_local(struct irq_work *work) |
| 62 | 62 | { |
| 63 | 63 | /* If the work is "lazy", handle it from next tick if any */ |
| 64 | − if (work->flags & IRQ_WORK_LAZY) { | |
| 64 | + if (atomic_read(&work->flags) & IRQ_WORK_LAZY) { | |
| 65 | 65 | if (llist_add(&work->llnode, this_cpu_ptr(&lazy_list)) && |
| 66 | 66 | tick_nohz_tick_stopped()) |
| 67 | 67 | arch_irq_work_raise(); |
| @@ -143,7 +143,7 @@ static void irq_work_run_list(struct llist_head *list) · 75 unmodified lines | ||
| 143 | 143 | { |
| 144 | 144 | struct irq_work *work, *tmp; |
| 145 | 145 | struct llist_node *llnode; |
| 146 | − unsigned long flags; | |
| 146 | + int flags; | |
| 147 | 147 | |
| 148 | 148 | BUG_ON(!irqs_disabled()); |
| 149 | 149 | |
| @@ -159,15 +159,15 @@ static void irq_work_run_list(struct llist_head *list) · 9 unmodified lines | ||
| 159 | 159 | * to claim that work don't rely on us to handle their data |
| 160 | 160 | * while we are in the middle of the func. |
| 161 | 161 | */ |
| 162 | − flags = work->flags & ~IRQ_WORK_PENDING; | |
| 163 | − xchg(&work->flags, flags); | |
| 162 | + flags = atomic_read(&work->flags) & ~IRQ_WORK_PENDING; | |
| 163 | + atomic_xchg(&work->flags, flags); | |
| 164 | 164 | |
| 165 | 165 | work->func(work); |
| 166 | 166 | /* |
| 167 | 167 | * Clear the BUSY bit and return to the free state if |
| 168 | 168 | * no-one else claimed it meanwhile. |
| 169 | 169 | */ |
| 170 | − (void)cmpxchg(&work->flags, flags, flags & ~IRQ_WORK_BUSY); | |
| 170 | + (void)atomic_cmpxchg(&work->flags, flags, flags & ~IRQ_WORK_BUSY); | |
| 171 | 171 | } |
| 172 | 172 | } |
| 173 | 173 | |
| @@ -199,7 +199,7 @@ void irq_work_sync(struct irq_work *work) · 25 unmodified lines | ||
| 199 | 199 | { |
| 200 | 200 | lockdep_assert_irqs_enabled(); |
| 201 | 201 | |
| 202 | − while (work->flags & IRQ_WORK_BUSY) | |
| 202 | + while (atomic_read(&work->flags) & IRQ_WORK_BUSY) | |
| 203 | 203 | cpu_relax(); |
| 204 | 204 | } |
| 205 | 205 | EXPORT_SYMBOL_GPL(irq_work_sync); |
| @@ -2961,7 +2961,7 @@ static void wake_up_klogd_work_func(struct irq_work *irq_work) · 2960 unmodified lines | ||
| 2961 | 2961 | |
| 2962 | 2962 | static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = { |
| 2963 | 2963 | .func = wake_up_klogd_work_func, |
| 2964 | − .flags = IRQ_WORK_LAZY, | |
| 2964 | + .flags = ATOMIC_INIT(IRQ_WORK_LAZY), | |
| 2965 | 2965 | }; |
| 2966 | 2966 | |
| 2967 | 2967 | void wake_up_klogd(void) |
| @@ -660,7 +660,7 @@ BPF_CALL_1(bpf_send_signal, u32, sig) · 659 unmodified lines | ||
| 660 | 660 | return -EINVAL; |
| 661 | 661 | |
| 662 | 662 | work = this_cpu_ptr(&send_signal_work); |
| 663 | − if (work->irq_work.flags & IRQ_WORK_BUSY) | |
| 663 | + if (atomic_read(&work->irq_work.flags) & IRQ_WORK_BUSY) | |
| 664 | 664 | return -EBUSY; |
| 665 | 665 | |
| 666 | 666 | /* Add the current task, which is the target of sending signal, |