diff options
Diffstat (limited to 'virt/kvm/kvm_main.c')
-rw-r--r-- | virt/kvm/kvm_main.c | 44 |
1 files changed, 31 insertions, 13 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index a17d78759727..88257b311cb5 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -727,8 +727,11 @@ static void kvm_destroy_vm(struct kvm *kvm) | |||
727 | list_del(&kvm->vm_list); | 727 | list_del(&kvm->vm_list); |
728 | spin_unlock(&kvm_lock); | 728 | spin_unlock(&kvm_lock); |
729 | kvm_free_irq_routing(kvm); | 729 | kvm_free_irq_routing(kvm); |
730 | for (i = 0; i < KVM_NR_BUSES; i++) | 730 | for (i = 0; i < KVM_NR_BUSES; i++) { |
731 | kvm_io_bus_destroy(kvm->buses[i]); | 731 | if (kvm->buses[i]) |
732 | kvm_io_bus_destroy(kvm->buses[i]); | ||
733 | kvm->buses[i] = NULL; | ||
734 | } | ||
732 | kvm_coalesced_mmio_free(kvm); | 735 | kvm_coalesced_mmio_free(kvm); |
733 | #if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER) | 736 | #if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER) |
734 | mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm); | 737 | mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm); |
@@ -1062,7 +1065,7 @@ int __kvm_set_memory_region(struct kvm *kvm, | |||
1062 | * changes) is disallowed above, so any other attribute changes getting | 1065 | * changes) is disallowed above, so any other attribute changes getting |
1063 | * here can be skipped. | 1066 | * here can be skipped. |
1064 | */ | 1067 | */ |
1065 | if ((change == KVM_MR_CREATE) || (change == KVM_MR_MOVE)) { | 1068 | if (as_id == 0 && (change == KVM_MR_CREATE || change == KVM_MR_MOVE)) { |
1066 | r = kvm_iommu_map_pages(kvm, &new); | 1069 | r = kvm_iommu_map_pages(kvm, &new); |
1067 | return r; | 1070 | return r; |
1068 | } | 1071 | } |
@@ -3474,6 +3477,8 @@ int kvm_io_bus_write(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr, | |||
3474 | }; | 3477 | }; |
3475 | 3478 | ||
3476 | bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu); | 3479 | bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu); |
3480 | if (!bus) | ||
3481 | return -ENOMEM; | ||
3477 | r = __kvm_io_bus_write(vcpu, bus, &range, val); | 3482 | r = __kvm_io_bus_write(vcpu, bus, &range, val); |
3478 | return r < 0 ? r : 0; | 3483 | return r < 0 ? r : 0; |
3479 | } | 3484 | } |
@@ -3491,6 +3496,8 @@ int kvm_io_bus_write_cookie(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, | |||
3491 | }; | 3496 | }; |
3492 | 3497 | ||
3493 | bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu); | 3498 | bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu); |
3499 | if (!bus) | ||
3500 | return -ENOMEM; | ||
3494 | 3501 | ||
3495 | /* First try the device referenced by cookie. */ | 3502 | /* First try the device referenced by cookie. */ |
3496 | if ((cookie >= 0) && (cookie < bus->dev_count) && | 3503 | if ((cookie >= 0) && (cookie < bus->dev_count) && |
@@ -3541,6 +3548,8 @@ int kvm_io_bus_read(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr, | |||
3541 | }; | 3548 | }; |
3542 | 3549 | ||
3543 | bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu); | 3550 | bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu); |
3551 | if (!bus) | ||
3552 | return -ENOMEM; | ||
3544 | r = __kvm_io_bus_read(vcpu, bus, &range, val); | 3553 | r = __kvm_io_bus_read(vcpu, bus, &range, val); |
3545 | return r < 0 ? r : 0; | 3554 | return r < 0 ? r : 0; |
3546 | } | 3555 | } |
@@ -3553,6 +3562,9 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, | |||
3553 | struct kvm_io_bus *new_bus, *bus; | 3562 | struct kvm_io_bus *new_bus, *bus; |
3554 | 3563 | ||
3555 | bus = kvm->buses[bus_idx]; | 3564 | bus = kvm->buses[bus_idx]; |
3565 | if (!bus) | ||
3566 | return -ENOMEM; | ||
3567 | |||
3556 | /* exclude ioeventfd which is limited by maximum fd */ | 3568 | /* exclude ioeventfd which is limited by maximum fd */ |
3557 | if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1) | 3569 | if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1) |
3558 | return -ENOSPC; | 3570 | return -ENOSPC; |
@@ -3572,37 +3584,41 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, | |||
3572 | } | 3584 | } |
3573 | 3585 | ||
3574 | /* Caller must hold slots_lock. */ | 3586 | /* Caller must hold slots_lock. */ |
3575 | int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx, | 3587 | void kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx, |
3576 | struct kvm_io_device *dev) | 3588 | struct kvm_io_device *dev) |
3577 | { | 3589 | { |
3578 | int i, r; | 3590 | int i; |
3579 | struct kvm_io_bus *new_bus, *bus; | 3591 | struct kvm_io_bus *new_bus, *bus; |
3580 | 3592 | ||
3581 | bus = kvm->buses[bus_idx]; | 3593 | bus = kvm->buses[bus_idx]; |
3582 | r = -ENOENT; | 3594 | if (!bus) |
3595 | return; | ||
3596 | |||
3583 | for (i = 0; i < bus->dev_count; i++) | 3597 | for (i = 0; i < bus->dev_count; i++) |
3584 | if (bus->range[i].dev == dev) { | 3598 | if (bus->range[i].dev == dev) { |
3585 | r = 0; | ||
3586 | break; | 3599 | break; |
3587 | } | 3600 | } |
3588 | 3601 | ||
3589 | if (r) | 3602 | if (i == bus->dev_count) |
3590 | return r; | 3603 | return; |
3591 | 3604 | ||
3592 | new_bus = kmalloc(sizeof(*bus) + ((bus->dev_count - 1) * | 3605 | new_bus = kmalloc(sizeof(*bus) + ((bus->dev_count - 1) * |
3593 | sizeof(struct kvm_io_range)), GFP_KERNEL); | 3606 | sizeof(struct kvm_io_range)), GFP_KERNEL); |
3594 | if (!new_bus) | 3607 | if (!new_bus) { |
3595 | return -ENOMEM; | 3608 | pr_err("kvm: failed to shrink bus, removing it completely\n"); |
3609 | goto broken; | ||
3610 | } | ||
3596 | 3611 | ||
3597 | memcpy(new_bus, bus, sizeof(*bus) + i * sizeof(struct kvm_io_range)); | 3612 | memcpy(new_bus, bus, sizeof(*bus) + i * sizeof(struct kvm_io_range)); |
3598 | new_bus->dev_count--; | 3613 | new_bus->dev_count--; |
3599 | memcpy(new_bus->range + i, bus->range + i + 1, | 3614 | memcpy(new_bus->range + i, bus->range + i + 1, |
3600 | (new_bus->dev_count - i) * sizeof(struct kvm_io_range)); | 3615 | (new_bus->dev_count - i) * sizeof(struct kvm_io_range)); |
3601 | 3616 | ||
3617 | broken: | ||
3602 | rcu_assign_pointer(kvm->buses[bus_idx], new_bus); | 3618 | rcu_assign_pointer(kvm->buses[bus_idx], new_bus); |
3603 | synchronize_srcu_expedited(&kvm->srcu); | 3619 | synchronize_srcu_expedited(&kvm->srcu); |
3604 | kfree(bus); | 3620 | kfree(bus); |
3605 | return r; | 3621 | return; |
3606 | } | 3622 | } |
3607 | 3623 | ||
3608 | struct kvm_io_device *kvm_io_bus_get_dev(struct kvm *kvm, enum kvm_bus bus_idx, | 3624 | struct kvm_io_device *kvm_io_bus_get_dev(struct kvm *kvm, enum kvm_bus bus_idx, |
@@ -3615,6 +3631,8 @@ struct kvm_io_device *kvm_io_bus_get_dev(struct kvm *kvm, enum kvm_bus bus_idx, | |||
3615 | srcu_idx = srcu_read_lock(&kvm->srcu); | 3631 | srcu_idx = srcu_read_lock(&kvm->srcu); |
3616 | 3632 | ||
3617 | bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu); | 3633 | bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu); |
3634 | if (!bus) | ||
3635 | goto out_unlock; | ||
3618 | 3636 | ||
3619 | dev_idx = kvm_io_bus_get_first_dev(bus, addr, 1); | 3637 | dev_idx = kvm_io_bus_get_first_dev(bus, addr, 1); |
3620 | if (dev_idx < 0) | 3638 | if (dev_idx < 0) |