Skip to content

Commit c57c804

Browse files
Junaid ShahidKAGA-KOKO
authored andcommitted
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 <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]>
1 parent b8e8c83 commit c57c804

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

include/linux/kvm_host.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,4 +1382,10 @@ static inline int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
13821382
}
13831383
#endif /* CONFIG_HAVE_KVM_VCPU_RUN_PID_CHANGE */
13841384

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+
13851391
#endif

virt/kvm/kvm_main.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include <linux/bsearch.h>
5151
#include <linux/io.h>
5252
#include <linux/lockdep.h>
53+
#include <linux/kthread.h>
5354

5455
#include <asm/processor.h>
5556
#include <asm/ioctl.h>
@@ -4371,3 +4372,86 @@ void kvm_exit(void)
43714372
kvm_vfio_ops_exit();
43724373
}
43734374
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+
}

0 commit comments

Comments
 (0)