diff --git a/include/linux/kthread.h b/include/linux/kthread.h index 5c2ec2c4eb22..4f5235cb13bb 100644 --- a/include/linux/kthread.h +++ b/include/linux/kthread.h @@ -65,7 +65,12 @@ struct kthread_work; typedef void (*kthread_work_func_t)(struct kthread_work *work); void kthread_delayed_work_timer_fn(unsigned long __data); +enum { + KTW_FREEZABLE = 1 << 0, /* freeze during suspend */ +}; + struct kthread_worker { + unsigned int flags; spinlock_t lock; struct list_head work_list; struct list_head delayed_work_list; @@ -154,12 +159,13 @@ extern void __kthread_init_worker(struct kthread_worker *worker, int kthread_worker_fn(void *worker_ptr); -__printf(1, 2) +__printf(2, 3) struct kthread_worker * -kthread_create_worker(const char namefmt[], ...); +kthread_create_worker(unsigned int flags, const char namefmt[], ...); struct kthread_worker * -kthread_create_worker_on_cpu(int cpu, const char namefmt[], ...); +kthread_create_worker_on_cpu(int cpu, unsigned int flags, + const char namefmt[], ...); bool kthread_queue_work(struct kthread_worker *worker, struct kthread_work *work); diff --git a/kernel/kthread.c b/kernel/kthread.c index c1fcc63fa605..be2cc1f9dd57 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -560,11 +560,11 @@ void __kthread_init_worker(struct kthread_worker *worker, const char *name, struct lock_class_key *key) { + memset(worker, 0, sizeof(struct kthread_worker)); spin_lock_init(&worker->lock); lockdep_set_class_and_name(&worker->lock, key, name); INIT_LIST_HEAD(&worker->work_list); INIT_LIST_HEAD(&worker->delayed_work_list); - worker->task = NULL; } EXPORT_SYMBOL_GPL(__kthread_init_worker); @@ -594,6 +594,10 @@ int kthread_worker_fn(void *worker_ptr) */ WARN_ON(worker->task && worker->task != current); worker->task = current; + + if (worker->flags & KTW_FREEZABLE) + set_freezable(); + repeat: set_current_state(TASK_INTERRUPTIBLE); /* mb paired w/ kthread_stop */ @@ -627,7 +631,8 @@ repeat: EXPORT_SYMBOL_GPL(kthread_worker_fn); static struct kthread_worker * -__kthread_create_worker(int cpu, const char namefmt[], va_list args) +__kthread_create_worker(int cpu, unsigned int flags, + const char namefmt[], va_list args) { struct kthread_worker *worker; struct task_struct *task; @@ -657,6 +662,7 @@ __kthread_create_worker(int cpu, const char namefmt[], va_list args) if (IS_ERR(task)) goto fail_task; + worker->flags = flags; worker->task = task; wake_up_process(task); return worker; @@ -668,6 +674,7 @@ fail_task: /** * kthread_create_worker - create a kthread worker + * @flags: flags modifying the default behavior of the worker * @namefmt: printf-style name for the kthread worker (task). * * Returns a pointer to the allocated worker on success, ERR_PTR(-ENOMEM) @@ -675,13 +682,13 @@ fail_task: * when the worker was SIGKILLed. */ struct kthread_worker * -kthread_create_worker(const char namefmt[], ...) +kthread_create_worker(unsigned int flags, const char namefmt[], ...) { struct kthread_worker *worker; va_list args; va_start(args, namefmt); - worker = __kthread_create_worker(-1, namefmt, args); + worker = __kthread_create_worker(-1, flags, namefmt, args); va_end(args); return worker; @@ -692,6 +699,7 @@ EXPORT_SYMBOL(kthread_create_worker); * kthread_create_worker_on_cpu - create a kthread worker and bind it * it to a given CPU and the associated NUMA node. * @cpu: CPU number + * @flags: flags modifying the default behavior of the worker * @namefmt: printf-style name for the kthread worker (task). * * Use a valid CPU number if you want to bind the kthread worker @@ -705,13 +713,14 @@ EXPORT_SYMBOL(kthread_create_worker); * when the worker was SIGKILLed. */ struct kthread_worker * -kthread_create_worker_on_cpu(int cpu, const char namefmt[], ...) +kthread_create_worker_on_cpu(int cpu, unsigned int flags, + const char namefmt[], ...) { struct kthread_worker *worker; va_list args; va_start(args, namefmt); - worker = __kthread_create_worker(cpu, namefmt, args); + worker = __kthread_create_worker(cpu, flags, namefmt, args); va_end(args); return worker;