diff options
Diffstat (limited to 'virt')
-rw-r--r-- | virt/kvm/Kconfig | 3 | ||||
-rw-r--r-- | virt/kvm/eventfd.c | 18 | ||||
-rw-r--r-- | virt/kvm/kvm_main.c | 32 | ||||
-rw-r--r-- | virt/lib/irqbypass.c | 12 |
4 files changed, 47 insertions, 18 deletions
diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig index 7a79b6853583..e5d6108f5e85 100644 --- a/virt/kvm/Kconfig +++ b/virt/kvm/Kconfig @@ -41,6 +41,9 @@ config KVM_VFIO config HAVE_KVM_ARCH_TLB_FLUSH_ALL bool +config HAVE_KVM_INVALID_WAKEUPS + bool + config KVM_GENERIC_DIRTYLOG_READ_PROTECT bool diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c index 46dbc0a7dfc1..e469b6012471 100644 --- a/virt/kvm/eventfd.c +++ b/virt/kvm/eventfd.c @@ -408,15 +408,17 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args) */ fdput(f); #ifdef CONFIG_HAVE_KVM_IRQ_BYPASS - irqfd->consumer.token = (void *)irqfd->eventfd; - irqfd->consumer.add_producer = kvm_arch_irq_bypass_add_producer; - irqfd->consumer.del_producer = kvm_arch_irq_bypass_del_producer; - irqfd->consumer.stop = kvm_arch_irq_bypass_stop; - irqfd->consumer.start = kvm_arch_irq_bypass_start; - ret = irq_bypass_register_consumer(&irqfd->consumer); - if (ret) - pr_info("irq bypass consumer (token %p) registration fails: %d\n", + if (kvm_arch_has_irq_bypass()) { + irqfd->consumer.token = (void *)irqfd->eventfd; + irqfd->consumer.add_producer = kvm_arch_irq_bypass_add_producer; + irqfd->consumer.del_producer = kvm_arch_irq_bypass_del_producer; + irqfd->consumer.stop = kvm_arch_irq_bypass_stop; + irqfd->consumer.start = kvm_arch_irq_bypass_start; + ret = irq_bypass_register_consumer(&irqfd->consumer); + if (ret) + pr_info("irq bypass consumer (token %p) registration fails: %d\n", irqfd->consumer.token, ret); + } #endif return 0; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 4fd482fb9260..dd4ac9d9e8f5 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2028,6 +2028,8 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu) */ if (kvm_vcpu_check_block(vcpu) < 0) { ++vcpu->stat.halt_successful_poll; + if (!vcpu_valid_wakeup(vcpu)) + ++vcpu->stat.halt_poll_invalid; goto out; } cur = ktime_get(); @@ -2053,7 +2055,9 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu) out: block_ns = ktime_to_ns(cur) - ktime_to_ns(start); - if (halt_poll_ns) { + if (!vcpu_valid_wakeup(vcpu)) + shrink_halt_poll_ns(vcpu); + else if (halt_poll_ns) { if (block_ns <= vcpu->halt_poll_ns) ; /* we had a long block, shrink polling */ @@ -2066,18 +2070,14 @@ out: } else vcpu->halt_poll_ns = 0; - trace_kvm_vcpu_wakeup(block_ns, waited); + trace_kvm_vcpu_wakeup(block_ns, waited, vcpu_valid_wakeup(vcpu)); + kvm_arch_vcpu_block_finish(vcpu); } EXPORT_SYMBOL_GPL(kvm_vcpu_block); #ifndef CONFIG_S390 -/* - * Kick a sleeping VCPU, or a guest VCPU in guest mode, into host kernel mode. - */ -void kvm_vcpu_kick(struct kvm_vcpu *vcpu) +void kvm_vcpu_wake_up(struct kvm_vcpu *vcpu) { - int me; - int cpu = vcpu->cpu; struct swait_queue_head *wqp; wqp = kvm_arch_vcpu_wq(vcpu); @@ -2086,6 +2086,18 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu) ++vcpu->stat.halt_wakeup; } +} +EXPORT_SYMBOL_GPL(kvm_vcpu_wake_up); + +/* + * Kick a sleeping VCPU, or a guest VCPU in guest mode, into host kernel mode. + */ +void kvm_vcpu_kick(struct kvm_vcpu *vcpu) +{ + int me; + int cpu = vcpu->cpu; + + kvm_vcpu_wake_up(vcpu); me = get_cpu(); if (cpu != me && (unsigned)cpu < nr_cpu_ids && cpu_online(cpu)) if (kvm_arch_vcpu_should_kick(vcpu)) @@ -2272,7 +2284,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id) int r; struct kvm_vcpu *vcpu; - if (id >= KVM_MAX_VCPUS) + if (id >= KVM_MAX_VCPU_ID) return -EINVAL; vcpu = kvm_arch_vcpu_create(kvm, id); @@ -2746,6 +2758,8 @@ static long kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg) case KVM_CAP_MULTI_ADDRESS_SPACE: return KVM_ADDRESS_SPACE_NUM; #endif + case KVM_CAP_MAX_VCPU_ID: + return KVM_MAX_VCPU_ID; default: break; } diff --git a/virt/lib/irqbypass.c b/virt/lib/irqbypass.c index 09a03b5a21ff..52abac4bb6a2 100644 --- a/virt/lib/irqbypass.c +++ b/virt/lib/irqbypass.c @@ -89,6 +89,9 @@ int irq_bypass_register_producer(struct irq_bypass_producer *producer) struct irq_bypass_producer *tmp; struct irq_bypass_consumer *consumer; + if (!producer->token) + return -EINVAL; + might_sleep(); if (!try_module_get(THIS_MODULE)) @@ -136,6 +139,9 @@ void irq_bypass_unregister_producer(struct irq_bypass_producer *producer) struct irq_bypass_producer *tmp; struct irq_bypass_consumer *consumer; + if (!producer->token) + return; + might_sleep(); if (!try_module_get(THIS_MODULE)) @@ -177,7 +183,8 @@ int irq_bypass_register_consumer(struct irq_bypass_consumer *consumer) struct irq_bypass_consumer *tmp; struct irq_bypass_producer *producer; - if (!consumer->add_producer || !consumer->del_producer) + if (!consumer->token || + !consumer->add_producer || !consumer->del_producer) return -EINVAL; might_sleep(); @@ -227,6 +234,9 @@ void irq_bypass_unregister_consumer(struct irq_bypass_consumer *consumer) struct irq_bypass_consumer *tmp; struct irq_bypass_producer *producer; + if (!consumer->token) + return; + might_sleep(); if (!try_module_get(THIS_MODULE)) |