1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2021 Oracle Corporation
5 #include <linux/slab.h>
6 #include <linux/completion.h>
7 #include <linux/sched/task.h>
8 #include <linux/sched/vhost_task.h>
9 #include <linux/sched/signal.h>
11 enum vhost_task_flags {
12 VHOST_TASK_FLAGS_STOP,
16 bool (*fn)(void *data);
18 struct completion exited;
20 struct task_struct *task;
23 static int vhost_task_fn(void *data)
25 struct vhost_task *vtsk = data;
31 /* mb paired w/ vhost_task_stop */
32 if (test_bit(VHOST_TASK_FLAGS_STOP, &vtsk->flags))
35 if (!dead && signal_pending(current)) {
38 * Calling get_signal will block in SIGSTOP,
39 * or clear fatal_signal_pending, but remember
42 * This thread won't actually exit until all
43 * of the file descriptors are closed, and
44 * the release function is called.
46 dead = get_signal(&ksig);
48 clear_thread_flag(TIF_SIGPENDING);
51 did_work = vtsk->fn(vtsk->data);
53 set_current_state(TASK_INTERRUPTIBLE);
58 complete(&vtsk->exited);
63 * vhost_task_wake - wakeup the vhost_task
64 * @vtsk: vhost_task to wake
66 * wake up the vhost_task worker thread
68 void vhost_task_wake(struct vhost_task *vtsk)
70 wake_up_process(vtsk->task);
72 EXPORT_SYMBOL_GPL(vhost_task_wake);
75 * vhost_task_stop - stop a vhost_task
76 * @vtsk: vhost_task to stop
78 * vhost_task_fn ensures the worker thread exits after
79 * VHOST_TASK_FLAGS_SOP becomes true.
81 void vhost_task_stop(struct vhost_task *vtsk)
83 set_bit(VHOST_TASK_FLAGS_STOP, &vtsk->flags);
84 vhost_task_wake(vtsk);
86 * Make sure vhost_task_fn is no longer accessing the vhost_task before
89 wait_for_completion(&vtsk->exited);
92 EXPORT_SYMBOL_GPL(vhost_task_stop);
95 * vhost_task_create - create a copy of a task to be used by the kernel
96 * @fn: vhost worker function
97 * @arg: data to be passed to fn
98 * @name: the thread's name
100 * This returns a specialized task for use by the vhost layer or NULL on
101 * failure. The returned task is inactive, and the caller must fire it up
102 * through vhost_task_start().
104 struct vhost_task *vhost_task_create(bool (*fn)(void *), void *arg,
107 struct kernel_clone_args args = {
108 .flags = CLONE_FS | CLONE_UNTRACED | CLONE_VM |
109 CLONE_THREAD | CLONE_SIGHAND,
116 struct vhost_task *vtsk;
117 struct task_struct *tsk;
119 vtsk = kzalloc(sizeof(*vtsk), GFP_KERNEL);
122 init_completion(&vtsk->exited);
128 tsk = copy_process(NULL, 0, NUMA_NO_NODE, &args);
137 EXPORT_SYMBOL_GPL(vhost_task_create);
140 * vhost_task_start - start a vhost_task created with vhost_task_create
141 * @vtsk: vhost_task to wake up
143 void vhost_task_start(struct vhost_task *vtsk)
145 wake_up_new_task(vtsk->task);
147 EXPORT_SYMBOL_GPL(vhost_task_start);