summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunaid Shahid <junaids@google.com>2019-11-04 06:22:02 -0500
committerThomas Gleixner <tglx@linutronix.de>2019-11-04 06:22:02 -0500
commitc57c80467f90e5504c8df9ad3555d2c78800bf94 (patch)
tree966043228f49ced836e69295f80305bc1ec29bc3
parentb8e8c8303ff28c61046a4d0f6ea99aea609a7dc0 (diff)
kvm: Add helper function for creating VM worker threads
Add a function to create a kernel thread associated with a given VM. In particular, it ensures that the worker thread inherits the priority and cgroups of the calling thread. Signed-off-by: Junaid Shahid <junaids@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--include/linux/kvm_host.h6
-rw-r--r--virt/kvm/kvm_main.c84
2 files changed, 90 insertions, 0 deletions
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 719fc3e15ea4..52ed5f66e8f9 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1382,4 +1382,10 @@ static inline int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
1382} 1382}
1383#endif /* CONFIG_HAVE_KVM_VCPU_RUN_PID_CHANGE */ 1383#endif /* CONFIG_HAVE_KVM_VCPU_RUN_PID_CHANGE */
1384 1384
1385typedef int (*kvm_vm_thread_fn_t)(struct kvm *kvm, uintptr_t data);
1386
1387int kvm_vm_create_worker_thread(struct kvm *kvm, kvm_vm_thread_fn_t thread_fn,
1388 uintptr_t data, const char *name,
1389 struct task_struct **thread_ptr);
1390
1385#endif 1391#endif
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index d6f0696d98ef..8aed32b604d9 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -50,6 +50,7 @@
50#include <linux/bsearch.h> 50#include <linux/bsearch.h>
51#include <linux/io.h> 51#include <linux/io.h>
52#include <linux/lockdep.h> 52#include <linux/lockdep.h>
53#include <linux/kthread.h>
53 54
54#include <asm/processor.h> 55#include <asm/processor.h>
55#include <asm/ioctl.h> 56#include <asm/ioctl.h>
@@ -4371,3 +4372,86 @@ void kvm_exit(void)
4371 kvm_vfio_ops_exit(); 4372 kvm_vfio_ops_exit();
4372} 4373}
4373EXPORT_SYMBOL_GPL(kvm_exit); 4374EXPORT_SYMBOL_GPL(kvm_exit);
4375
4376struct kvm_vm_worker_thread_context {
4377 struct kvm *kvm;
4378 struct task_struct *parent;
4379 struct completion init_done;
4380 kvm_vm_thread_fn_t thread_fn;
4381 uintptr_t data;
4382 int err;
4383};
4384
4385static int kvm_vm_worker_thread(void *context)
4386{
4387 /*
4388 * The init_context is allocated on the stack of the parent thread, so
4389 * we have to locally copy anything that is needed beyond initialization
4390 */
4391 struct kvm_vm_worker_thread_context *init_context = context;
4392 struct kvm *kvm = init_context->kvm;
4393 kvm_vm_thread_fn_t thread_fn = init_context->thread_fn;
4394 uintptr_t data = init_context->data;
4395 int err;
4396
4397 err = kthread_park(current);
4398 /* kthread_park(current) is never supposed to return an error */
4399 WARN_ON(err != 0);
4400 if (err)
4401 goto init_complete;
4402
4403 err = cgroup_attach_task_all(init_context->parent, current);
4404 if (err) {
4405 kvm_err("%s: cgroup_attach_task_all failed with err %d\n",
4406 __func__, err);
4407 goto init_complete;
4408 }
4409
4410 set_user_nice(current, task_nice(init_context->parent));
4411
4412init_complete:
4413 init_context->err = err;
4414 complete(&init_context->init_done);
4415 init_context = NULL;
4416
4417 if (err)
4418 return err;
4419
4420 /* Wait to be woken up by the spawner before proceeding. */
4421 kthread_parkme();
4422
4423 if (!kthread_should_stop())
4424 err = thread_fn(kvm, data);
4425
4426 return err;
4427}
4428
4429int kvm_vm_create_worker_thread(struct kvm *kvm, kvm_vm_thread_fn_t thread_fn,
4430 uintptr_t data, const char *name,
4431 struct task_struct **thread_ptr)
4432{
4433 struct kvm_vm_worker_thread_context init_context = {};
4434 struct task_struct *thread;
4435
4436 *thread_ptr = NULL;
4437 init_context.kvm = kvm;
4438 init_context.parent = current;
4439 init_context.thread_fn = thread_fn;
4440 init_context.data = data;
4441 init_completion(&init_context.init_done);
4442
4443 thread = kthread_run(kvm_vm_worker_thread, &init_context,
4444 "%s-%d", name, task_pid_nr(current));
4445 if (IS_ERR(thread))
4446 return PTR_ERR(thread);
4447
4448 /* kthread_run is never supposed to return NULL */
4449 WARN_ON(thread == NULL);
4450
4451 wait_for_completion(&init_context.init_done);
4452
4453 if (!init_context.err)
4454 *thread_ptr = thread;
4455
4456 return init_context.err;
4457}