KVM: Reinstall old memslots if arch preparation fails

Reinstall the old memslots if preparing the new memory region fails
after invalidating a to-be-{re}moved memslot.

Remove the superfluous 'old_memslots' variable so that it's somewhat
clear that the error handling path needs to free the unused memslots,
not simply the 'old' memslots.

Fixes: bc6678a33d ("KVM: introduce kvm->srcu and convert kvm_set_memory_region to SRCU update")
Reviewed-by: Christoffer Dall <christoffer.dall@arm.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Sean Christopherson 2020-02-18 13:07:16 -08:00 коммит произвёл Paolo Bonzini
Родитель edd4fa37ba
Коммит 13ea525517
1 изменённых файлов: 12 добавлений и 11 удалений

Просмотреть файл

@ -999,7 +999,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
unsigned long npages; unsigned long npages;
struct kvm_memory_slot *slot; struct kvm_memory_slot *slot;
struct kvm_memory_slot old, new; struct kvm_memory_slot old, new;
struct kvm_memslots *slots = NULL, *old_memslots; struct kvm_memslots *slots;
int as_id, id; int as_id, id;
enum kvm_mr_change change; enum kvm_mr_change change;
@ -1107,7 +1107,13 @@ int __kvm_set_memory_region(struct kvm *kvm,
slot = id_to_memslot(slots, id); slot = id_to_memslot(slots, id);
slot->flags |= KVM_MEMSLOT_INVALID; slot->flags |= KVM_MEMSLOT_INVALID;
old_memslots = install_new_memslots(kvm, as_id, slots); /*
* We can re-use the old memslots, the only difference from the
* newly installed memslots is the invalid flag, which will get
* dropped by update_memslots anyway. We'll also revert to the
* old memslots if preparing the new memory region fails.
*/
slots = install_new_memslots(kvm, as_id, slots);
/* From this point no new shadow pages pointing to a deleted, /* From this point no new shadow pages pointing to a deleted,
* or moved, memslot will be created. * or moved, memslot will be created.
@ -1117,13 +1123,6 @@ int __kvm_set_memory_region(struct kvm *kvm,
* - kvm_is_visible_gfn (mmu_check_root) * - kvm_is_visible_gfn (mmu_check_root)
*/ */
kvm_arch_flush_shadow_memslot(kvm, slot); kvm_arch_flush_shadow_memslot(kvm, slot);
/*
* We can re-use the old_memslots from above, the only difference
* from the currently installed memslots is the invalid flag. This
* will get overwritten by update_memslots anyway.
*/
slots = old_memslots;
} }
r = kvm_arch_prepare_memory_region(kvm, &new, mem, change); r = kvm_arch_prepare_memory_region(kvm, &new, mem, change);
@ -1137,15 +1136,17 @@ int __kvm_set_memory_region(struct kvm *kvm,
} }
update_memslots(slots, &new, change); update_memslots(slots, &new, change);
old_memslots = install_new_memslots(kvm, as_id, slots); slots = install_new_memslots(kvm, as_id, slots);
kvm_arch_commit_memory_region(kvm, mem, &old, &new, change); kvm_arch_commit_memory_region(kvm, mem, &old, &new, change);
kvm_free_memslot(kvm, &old, &new); kvm_free_memslot(kvm, &old, &new);
kvfree(old_memslots); kvfree(slots);
return 0; return 0;
out_slots: out_slots:
if (change == KVM_MR_DELETE || change == KVM_MR_MOVE)
slots = install_new_memslots(kvm, as_id, slots);
kvfree(slots); kvfree(slots);
out_free: out_free:
kvm_free_memslot(kvm, &new, &old); kvm_free_memslot(kvm, &new, &old);