cancel_delayed_work() can't be called from IRQ handlers due to its use of del_timer_sync() and can't cancel work items which are already transferred from timer to worklist. Also, unlike other flush and cancel functions, a canceled delayed_work would still point to the last associated cpu_workqueue. If the workqueue is destroyed afterwards and the work item is re-used on a different workqueue, the queueing code can oops trying to dereference already freed cpu_workqueue. This patch reimplements cancel_delayed_work() using try_to_grab_pending() and set_work_cpu_and_clear_pending(). This allows the function to be called from IRQ handlers and makes its behavior consistent with other flush / cancel functions.
Showing the changes to kernel/workqueue.c (1 of 2 files). Show all
Unified · Split
| @@ -2948,6 +2948,36 @@ bool flush_delayed_work(struct delayed_work *dwork) · 2947 unmodified lines | |||
| 2948 | } | 2948 | } |
| 2949 | EXPORT_SYMBOL(flush_delayed_work); | 2949 | EXPORT_SYMBOL(flush_delayed_work); |
| 2950 | 2950 | ||
| 2951 | /** | ||
| 2952 | * cancel_delayed_work - cancel a delayed work | ||
| 2953 | * @dwork: delayed_work to cancel | ||
| 2954 | * | ||
| 2955 | * Kill off a pending delayed_work. Returns %true if @dwork was pending | ||
| 2956 | * and canceled; %false if wasn't pending. Note that the work callback | ||
| 2957 | * function may still be running on return, unless it returns %true and the | ||
| 2958 | * work doesn't re-arm itself. Explicitly flush or use | ||
| 2959 | * cancel_delayed_work_sync() to wait on it. | ||
| 2960 | * | ||
| 2961 | * This function is safe to call from any context including IRQ handler. | ||
| 2962 | */ | ||
| 2963 | bool cancel_delayed_work(struct delayed_work *dwork) | ||
| 2964 | { | ||
| 2965 | unsigned long flags; | ||
| 2966 | int ret; | ||
| 2967 | |||
| 2968 | do { | ||
| 2969 | ret = try_to_grab_pending(&dwork->work, true, &flags); | ||
| 2970 | } while (unlikely(ret == -EAGAIN)); | ||
| 2971 | |||
| 2972 | if (unlikely(ret < 0)) | ||
| 2973 | return false; | ||
| 2974 | |||
| 2975 | set_work_cpu_and_clear_pending(&dwork->work, work_cpu(&dwork->work)); | ||
| 2976 | local_irq_restore(flags); | ||
| 2977 | return true; | ||
| 2978 | } | ||
| 2979 | EXPORT_SYMBOL(cancel_delayed_work); | ||
| 2980 | |||
| 2951 | /** | 2981 | /** |
| 2952 | * cancel_delayed_work_sync - cancel a delayed work and wait for it to finish | 2982 | * cancel_delayed_work_sync - cancel a delayed work and wait for it to finish |
| 2953 | * @dwork: the delayed work cancel | 2983 | * @dwork: the delayed work cancel |