diff --git a/include/linux/kthread.h b/include/linux/kthread.h index daeb2befbabffb844087d9ced1ef9ef23ce37bf0..afc8939da8613db1a3c59b1de287c2a8127a2408 100644 --- a/include/linux/kthread.h +++ b/include/linux/kthread.h @@ -136,4 +136,6 @@ bool kthread_queue_work(struct kthread_worker *worker, void kthread_flush_work(struct kthread_work *work); void kthread_flush_worker(struct kthread_worker *worker); +void kthread_destroy_worker(struct kthread_worker *worker); + #endif /* _LINUX_KTHREAD_H */ diff --git a/kernel/kthread.c b/kernel/kthread.c index 12695e68ed00d43345ef3595bb1d9ecb3084e5c0..f874300dfce5e1c946e36df1827aea97a1107e31 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -823,3 +823,26 @@ void kthread_flush_worker(struct kthread_worker *worker) wait_for_completion(&fwork.done); } EXPORT_SYMBOL_GPL(kthread_flush_worker); + +/** + * kthread_destroy_worker - destroy a kthread worker + * @worker: worker to be destroyed + * + * Flush and destroy @worker. The simple flush is enough because the kthread + * worker API is used only in trivial scenarios. There are no multi-step state + * machines needed. + */ +void kthread_destroy_worker(struct kthread_worker *worker) +{ + struct task_struct *task; + + task = worker->task; + if (WARN_ON(!task)) + return; + + kthread_flush_worker(worker); + kthread_stop(task); + WARN_ON(!list_empty(&worker->work_list)); + kfree(worker); +} +EXPORT_SYMBOL(kthread_destroy_worker);