~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/kernel/vhost_task.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright (C) 2021 Oracle Corporation
  4  */
  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>
 10 
 11 enum vhost_task_flags {
 12         VHOST_TASK_FLAGS_STOP,
 13         VHOST_TASK_FLAGS_KILLED,
 14 };
 15 
 16 struct vhost_task {
 17         bool (*fn)(void *data);
 18         void (*handle_sigkill)(void *data);
 19         void *data;
 20         struct completion exited;
 21         unsigned long flags;
 22         struct task_struct *task;
 23         /* serialize SIGKILL and vhost_task_stop calls */
 24         struct mutex exit_mutex;
 25 };
 26 
 27 static int vhost_task_fn(void *data)
 28 {
 29         struct vhost_task *vtsk = data;
 30 
 31         for (;;) {
 32                 bool did_work;
 33 
 34                 if (signal_pending(current)) {
 35                         struct ksignal ksig;
 36 
 37                         if (get_signal(&ksig))
 38                                 break;
 39                 }
 40 
 41                 /* mb paired w/ vhost_task_stop */
 42                 set_current_state(TASK_INTERRUPTIBLE);
 43 
 44                 if (test_bit(VHOST_TASK_FLAGS_STOP, &vtsk->flags)) {
 45                         __set_current_state(TASK_RUNNING);
 46                         break;
 47                 }
 48 
 49                 did_work = vtsk->fn(vtsk->data);
 50                 if (!did_work)
 51                         schedule();
 52         }
 53 
 54         mutex_lock(&vtsk->exit_mutex);
 55         /*
 56          * If a vhost_task_stop and SIGKILL race, we can ignore the SIGKILL.
 57          * When the vhost layer has called vhost_task_stop it's already stopped
 58          * new work and flushed.
 59          */
 60         if (!test_bit(VHOST_TASK_FLAGS_STOP, &vtsk->flags)) {
 61                 set_bit(VHOST_TASK_FLAGS_KILLED, &vtsk->flags);
 62                 vtsk->handle_sigkill(vtsk->data);
 63         }
 64         mutex_unlock(&vtsk->exit_mutex);
 65         complete(&vtsk->exited);
 66 
 67         do_exit(0);
 68 }
 69 
 70 /**
 71  * vhost_task_wake - wakeup the vhost_task
 72  * @vtsk: vhost_task to wake
 73  *
 74  * wake up the vhost_task worker thread
 75  */
 76 void vhost_task_wake(struct vhost_task *vtsk)
 77 {
 78         wake_up_process(vtsk->task);
 79 }
 80 EXPORT_SYMBOL_GPL(vhost_task_wake);
 81 
 82 /**
 83  * vhost_task_stop - stop a vhost_task
 84  * @vtsk: vhost_task to stop
 85  *
 86  * vhost_task_fn ensures the worker thread exits after
 87  * VHOST_TASK_FLAGS_STOP becomes true.
 88  */
 89 void vhost_task_stop(struct vhost_task *vtsk)
 90 {
 91         mutex_lock(&vtsk->exit_mutex);
 92         if (!test_bit(VHOST_TASK_FLAGS_KILLED, &vtsk->flags)) {
 93                 set_bit(VHOST_TASK_FLAGS_STOP, &vtsk->flags);
 94                 vhost_task_wake(vtsk);
 95         }
 96         mutex_unlock(&vtsk->exit_mutex);
 97 
 98         /*
 99          * Make sure vhost_task_fn is no longer accessing the vhost_task before
100          * freeing it below.
101          */
102         wait_for_completion(&vtsk->exited);
103         kfree(vtsk);
104 }
105 EXPORT_SYMBOL_GPL(vhost_task_stop);
106 
107 /**
108  * vhost_task_create - create a copy of a task to be used by the kernel
109  * @fn: vhost worker function
110  * @handle_sigkill: vhost function to handle when we are killed
111  * @arg: data to be passed to fn and handled_kill
112  * @name: the thread's name
113  *
114  * This returns a specialized task for use by the vhost layer or NULL on
115  * failure. The returned task is inactive, and the caller must fire it up
116  * through vhost_task_start().
117  */
118 struct vhost_task *vhost_task_create(bool (*fn)(void *),
119                                      void (*handle_sigkill)(void *), void *arg,
120                                      const char *name)
121 {
122         struct kernel_clone_args args = {
123                 .flags          = CLONE_FS | CLONE_UNTRACED | CLONE_VM |
124                                   CLONE_THREAD | CLONE_SIGHAND,
125                 .exit_signal    = 0,
126                 .fn             = vhost_task_fn,
127                 .name           = name,
128                 .user_worker    = 1,
129                 .no_files       = 1,
130         };
131         struct vhost_task *vtsk;
132         struct task_struct *tsk;
133 
134         vtsk = kzalloc(sizeof(*vtsk), GFP_KERNEL);
135         if (!vtsk)
136                 return NULL;
137         init_completion(&vtsk->exited);
138         mutex_init(&vtsk->exit_mutex);
139         vtsk->data = arg;
140         vtsk->fn = fn;
141         vtsk->handle_sigkill = handle_sigkill;
142 
143         args.fn_arg = vtsk;
144 
145         tsk = copy_process(NULL, 0, NUMA_NO_NODE, &args);
146         if (IS_ERR(tsk)) {
147                 kfree(vtsk);
148                 return NULL;
149         }
150 
151         vtsk->task = tsk;
152         return vtsk;
153 }
154 EXPORT_SYMBOL_GPL(vhost_task_create);
155 
156 /**
157  * vhost_task_start - start a vhost_task created with vhost_task_create
158  * @vtsk: vhost_task to wake up
159  */
160 void vhost_task_start(struct vhost_task *vtsk)
161 {
162         wake_up_new_task(vtsk->task);
163 }
164 EXPORT_SYMBOL_GPL(vhost_task_start);
165 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php