Merge tag 'kvm-x86-generic-6.11' of https://github.com/kvm-x86/linux into HEAD
KVM generic changes for 6.11 - Enable halt poll shrinking by default, as Intel found it to be a clear win. - Setup empty IRQ routing when creating a VM to avoid having to synchronize SRCU when creating a split IRQCHIP on x86. - Rework the sched_in/out() paths to replace kvm_arch_sched_in() with a flag that arch code can use for hooking both sched_in() and sched_out(). - Take the vCPU @id as an "unsigned long" instead of "u32" to avoid truncating a bogus value from userspace, e.g. to help userspace detect bugs. - Mark a vCPU as preempted if and only if it's scheduled out while in the KVM_RUN loop, e.g. to avoid marking it preempted and thus writing guest memory when retrieving guest state during live migration blackout. - A few minor cleanups
This commit is contained in:
+1
-12
@@ -80,7 +80,6 @@ static void async_pf_execute(struct work_struct *work)
|
||||
spin_lock(&vcpu->async_pf.lock);
|
||||
first = list_empty(&vcpu->async_pf.done);
|
||||
list_add_tail(&apf->link, &vcpu->async_pf.done);
|
||||
apf->vcpu = NULL;
|
||||
spin_unlock(&vcpu->async_pf.lock);
|
||||
|
||||
/*
|
||||
@@ -120,8 +119,6 @@ static void kvm_flush_and_free_async_pf_work(struct kvm_async_pf *work)
|
||||
|
||||
void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
spin_lock(&vcpu->async_pf.lock);
|
||||
|
||||
/* cancel outstanding work queue item */
|
||||
while (!list_empty(&vcpu->async_pf.queue)) {
|
||||
struct kvm_async_pf *work =
|
||||
@@ -129,23 +126,15 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu)
|
||||
typeof(*work), queue);
|
||||
list_del(&work->queue);
|
||||
|
||||
/*
|
||||
* We know it's present in vcpu->async_pf.done, do
|
||||
* nothing here.
|
||||
*/
|
||||
if (!work->vcpu)
|
||||
continue;
|
||||
|
||||
spin_unlock(&vcpu->async_pf.lock);
|
||||
#ifdef CONFIG_KVM_ASYNC_PF_SYNC
|
||||
flush_work(&work->work);
|
||||
#else
|
||||
if (cancel_work_sync(&work->work))
|
||||
kmem_cache_free(async_pf_cache, work);
|
||||
#endif
|
||||
spin_lock(&vcpu->async_pf.lock);
|
||||
}
|
||||
|
||||
spin_lock(&vcpu->async_pf.lock);
|
||||
while (!list_empty(&vcpu->async_pf.done)) {
|
||||
struct kvm_async_pf *work =
|
||||
list_first_entry(&vcpu->async_pf.done,
|
||||
|
||||
@@ -237,3 +237,27 @@ out:
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate empty IRQ routing by default so that additional setup isn't needed
|
||||
* when userspace-driven IRQ routing is activated, and so that kvm->irq_routing
|
||||
* is guaranteed to be non-NULL.
|
||||
*/
|
||||
int kvm_init_irq_routing(struct kvm *kvm)
|
||||
{
|
||||
struct kvm_irq_routing_table *new;
|
||||
int chip_size;
|
||||
|
||||
new = kzalloc(struct_size(new, map, 1), GFP_KERNEL_ACCOUNT);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
new->nr_rt_entries = 1;
|
||||
|
||||
chip_size = sizeof(int) * KVM_NR_IRQCHIPS * KVM_IRQCHIP_NUM_PINS;
|
||||
memset(new->chip, -1, chip_size);
|
||||
|
||||
RCU_INIT_POINTER(kvm->irq_routing, new);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+33
-13
@@ -1,9 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Kernel-based Virtual Machine driver for Linux
|
||||
*
|
||||
* This module enables machines with Intel VT-x extensions to run virtual
|
||||
* machines without emulation or binary translation.
|
||||
* Kernel-based Virtual Machine (KVM) Hypervisor
|
||||
*
|
||||
* Copyright (C) 2006 Qumranet, Inc.
|
||||
* Copyright 2010 Red Hat, Inc. and/or its affiliates.
|
||||
@@ -74,6 +71,7 @@
|
||||
#define ITOA_MAX_LEN 12
|
||||
|
||||
MODULE_AUTHOR("Qumranet");
|
||||
MODULE_DESCRIPTION("Kernel-based Virtual Machine (KVM) Hypervisor");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* Architectures should define their poll value according to the halt latency */
|
||||
@@ -91,8 +89,8 @@ unsigned int halt_poll_ns_grow_start = 10000; /* 10us */
|
||||
module_param(halt_poll_ns_grow_start, uint, 0644);
|
||||
EXPORT_SYMBOL_GPL(halt_poll_ns_grow_start);
|
||||
|
||||
/* Default resets per-vcpu halt_poll_ns . */
|
||||
unsigned int halt_poll_ns_shrink;
|
||||
/* Default halves per-vcpu halt_poll_ns. */
|
||||
unsigned int halt_poll_ns_shrink = 2;
|
||||
module_param(halt_poll_ns_shrink, uint, 0644);
|
||||
EXPORT_SYMBOL_GPL(halt_poll_ns_shrink);
|
||||
|
||||
@@ -110,8 +108,7 @@ static struct kmem_cache *kvm_vcpu_cache;
|
||||
static __read_mostly struct preempt_ops kvm_preempt_ops;
|
||||
static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_running_vcpu);
|
||||
|
||||
struct dentry *kvm_debugfs_dir;
|
||||
EXPORT_SYMBOL_GPL(kvm_debugfs_dir);
|
||||
static struct dentry *kvm_debugfs_dir;
|
||||
|
||||
static const struct file_operations stat_fops_per_vm;
|
||||
|
||||
@@ -1145,8 +1142,7 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
|
||||
{
|
||||
struct kvm *kvm = kvm_arch_alloc_vm();
|
||||
struct kvm_memslots *slots;
|
||||
int r = -ENOMEM;
|
||||
int i, j;
|
||||
int r, i, j;
|
||||
|
||||
if (!kvm)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
@@ -1183,12 +1179,18 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
|
||||
snprintf(kvm->stats_id, sizeof(kvm->stats_id), "kvm-%d",
|
||||
task_pid_nr(current));
|
||||
|
||||
r = -ENOMEM;
|
||||
if (init_srcu_struct(&kvm->srcu))
|
||||
goto out_err_no_srcu;
|
||||
if (init_srcu_struct(&kvm->irq_srcu))
|
||||
goto out_err_no_irq_srcu;
|
||||
|
||||
r = kvm_init_irq_routing(kvm);
|
||||
if (r)
|
||||
goto out_err_no_irq_routing;
|
||||
|
||||
refcount_set(&kvm->users_count, 1);
|
||||
|
||||
for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
|
||||
for (j = 0; j < 2; j++) {
|
||||
slots = &kvm->__memslots[i][j];
|
||||
@@ -1206,6 +1208,7 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
|
||||
rcu_assign_pointer(kvm->memslots[i], &kvm->__memslots[i][0]);
|
||||
}
|
||||
|
||||
r = -ENOMEM;
|
||||
for (i = 0; i < KVM_NR_BUSES; i++) {
|
||||
rcu_assign_pointer(kvm->buses[i],
|
||||
kzalloc(sizeof(struct kvm_io_bus), GFP_KERNEL_ACCOUNT));
|
||||
@@ -1267,6 +1270,8 @@ out_err_no_arch_destroy_vm:
|
||||
WARN_ON_ONCE(!refcount_dec_and_test(&kvm->users_count));
|
||||
for (i = 0; i < KVM_NR_BUSES; i++)
|
||||
kfree(kvm_get_bus(kvm, i));
|
||||
kvm_free_irq_routing(kvm);
|
||||
out_err_no_irq_routing:
|
||||
cleanup_srcu_struct(&kvm->irq_srcu);
|
||||
out_err_no_irq_srcu:
|
||||
cleanup_srcu_struct(&kvm->srcu);
|
||||
@@ -4202,12 +4207,21 @@ static void kvm_create_vcpu_debugfs(struct kvm_vcpu *vcpu)
|
||||
/*
|
||||
* Creates some virtual cpus. Good luck creating more than one.
|
||||
*/
|
||||
static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
|
||||
static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
|
||||
{
|
||||
int r;
|
||||
struct kvm_vcpu *vcpu;
|
||||
struct page *page;
|
||||
|
||||
/*
|
||||
* KVM tracks vCPU IDs as 'int', be kind to userspace and reject
|
||||
* too-large values instead of silently truncating.
|
||||
*
|
||||
* Ensure KVM_MAX_VCPU_IDS isn't pushed above INT_MAX without first
|
||||
* changing the storage type (at the very least, IDs should be tracked
|
||||
* as unsigned ints).
|
||||
*/
|
||||
BUILD_BUG_ON(KVM_MAX_VCPU_IDS > INT_MAX);
|
||||
if (id >= KVM_MAX_VCPU_IDS)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -4467,7 +4481,10 @@ static long kvm_vcpu_ioctl(struct file *filp,
|
||||
synchronize_rcu();
|
||||
put_pid(oldpid);
|
||||
}
|
||||
vcpu->wants_to_run = !READ_ONCE(vcpu->run->immediate_exit__unsafe);
|
||||
r = kvm_arch_vcpu_ioctl_run(vcpu);
|
||||
vcpu->wants_to_run = false;
|
||||
|
||||
trace_kvm_userspace_exit(vcpu->run->exit_reason, r);
|
||||
break;
|
||||
}
|
||||
@@ -6347,8 +6364,9 @@ static void kvm_sched_in(struct preempt_notifier *pn, int cpu)
|
||||
WRITE_ONCE(vcpu->ready, false);
|
||||
|
||||
__this_cpu_write(kvm_running_vcpu, vcpu);
|
||||
kvm_arch_sched_in(vcpu, cpu);
|
||||
kvm_arch_vcpu_load(vcpu, cpu);
|
||||
|
||||
WRITE_ONCE(vcpu->scheduled_out, false);
|
||||
}
|
||||
|
||||
static void kvm_sched_out(struct preempt_notifier *pn,
|
||||
@@ -6356,7 +6374,9 @@ static void kvm_sched_out(struct preempt_notifier *pn,
|
||||
{
|
||||
struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
|
||||
|
||||
if (current->on_rq) {
|
||||
WRITE_ONCE(vcpu->scheduled_out, true);
|
||||
|
||||
if (current->on_rq && vcpu->wants_to_run) {
|
||||
WRITE_ONCE(vcpu->preempted, true);
|
||||
WRITE_ONCE(vcpu->ready, true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user