diff options
author | Junaid Shahid <junaids@google.com> | 2019-11-04 06:22:02 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2019-11-04 06:22:02 -0500 |
commit | c57c80467f90e5504c8df9ad3555d2c78800bf94 (patch) | |
tree | 966043228f49ced836e69295f80305bc1ec29bc3 | |
parent | b8e8c8303ff28c61046a4d0f6ea99aea609a7dc0 (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.h | 6 | ||||
-rw-r--r-- | virt/kvm/kvm_main.c | 84 |
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 | ||
1385 | typedef int (*kvm_vm_thread_fn_t)(struct kvm *kvm, uintptr_t data); | ||
1386 | |||
1387 | int 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 | } |
4373 | EXPORT_SYMBOL_GPL(kvm_exit); | 4374 | EXPORT_SYMBOL_GPL(kvm_exit); |
4375 | |||
4376 | struct 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 | |||
4385 | static 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 | |||
4412 | init_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 | |||
4429 | int 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 | } | ||