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,
15 static int vhost_task_fn(void *data)
17 struct vhost_task *vtsk = data;
20 ret = vtsk->fn(vtsk->data);
21 complete(&vtsk->exited);
26 * vhost_task_stop - stop a vhost_task
27 * @vtsk: vhost_task to stop
29 * Callers must call vhost_task_should_stop and return from their worker
30 * function when it returns true;
32 void vhost_task_stop(struct vhost_task *vtsk)
34 pid_t pid = vtsk->task->pid;
36 set_bit(VHOST_TASK_FLAGS_STOP, &vtsk->flags);
37 wake_up_process(vtsk->task);
39 * Make sure vhost_task_fn is no longer accessing the vhost_task before
40 * freeing it below. If userspace crashed or exited without closing,
41 * then the vhost_task->task could already be marked dead so
42 * kernel_wait will return early.
44 wait_for_completion(&vtsk->exited);
46 * If we are just closing/removing a device and the parent process is
47 * not exiting then reap the task.
49 kernel_wait4(pid, NULL, __WCLONE, NULL);
52 EXPORT_SYMBOL_GPL(vhost_task_stop);
55 * vhost_task_should_stop - should the vhost task return from the work function
56 * @vtsk: vhost_task to stop
58 bool vhost_task_should_stop(struct vhost_task *vtsk)
60 return test_bit(VHOST_TASK_FLAGS_STOP, &vtsk->flags);
62 EXPORT_SYMBOL_GPL(vhost_task_should_stop);
65 * vhost_task_create - create a copy of a process to be used by the kernel
67 * @arg: data to be passed to fn
68 * @name: the thread's name
70 * This returns a specialized task for use by the vhost layer or NULL on
71 * failure. The returned task is inactive, and the caller must fire it up
72 * through vhost_task_start().
74 struct vhost_task *vhost_task_create(int (*fn)(void *), void *arg,
77 struct kernel_clone_args args = {
78 .flags = CLONE_FS | CLONE_UNTRACED | CLONE_VM,
86 struct vhost_task *vtsk;
87 struct task_struct *tsk;
89 vtsk = kzalloc(sizeof(*vtsk), GFP_KERNEL);
92 init_completion(&vtsk->exited);
98 tsk = copy_process(NULL, 0, NUMA_NO_NODE, &args);
107 EXPORT_SYMBOL_GPL(vhost_task_create);
110 * vhost_task_start - start a vhost_task created with vhost_task_create
111 * @vtsk: vhost_task to wake up
113 void vhost_task_start(struct vhost_task *vtsk)
115 wake_up_new_task(vtsk->task);
117 EXPORT_SYMBOL_GPL(vhost_task_start);