|
@@ -95,8 +95,6 @@ static int hardware_enable_all(void);
|
|
static void hardware_disable_all(void);
|
|
static void hardware_disable_all(void);
|
|
|
|
|
|
static void kvm_io_bus_destroy(struct kvm_io_bus *bus);
|
|
static void kvm_io_bus_destroy(struct kvm_io_bus *bus);
|
|
-static void update_memslots(struct kvm_memslots *slots,
|
|
|
|
- struct kvm_memory_slot *new, u64 last_generation);
|
|
|
|
|
|
|
|
static void kvm_release_pfn_dirty(pfn_t pfn);
|
|
static void kvm_release_pfn_dirty(pfn_t pfn);
|
|
static void mark_page_dirty_in_slot(struct kvm *kvm,
|
|
static void mark_page_dirty_in_slot(struct kvm *kvm,
|
|
@@ -695,8 +693,7 @@ static void sort_memslots(struct kvm_memslots *slots)
|
|
}
|
|
}
|
|
|
|
|
|
static void update_memslots(struct kvm_memslots *slots,
|
|
static void update_memslots(struct kvm_memslots *slots,
|
|
- struct kvm_memory_slot *new,
|
|
|
|
- u64 last_generation)
|
|
|
|
|
|
+ struct kvm_memory_slot *new)
|
|
{
|
|
{
|
|
if (new) {
|
|
if (new) {
|
|
int id = new->id;
|
|
int id = new->id;
|
|
@@ -707,8 +704,6 @@ static void update_memslots(struct kvm_memslots *slots,
|
|
if (new->npages != npages)
|
|
if (new->npages != npages)
|
|
sort_memslots(slots);
|
|
sort_memslots(slots);
|
|
}
|
|
}
|
|
-
|
|
|
|
- slots->generation = last_generation + 1;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
static int check_memory_region_flags(struct kvm_userspace_memory_region *mem)
|
|
static int check_memory_region_flags(struct kvm_userspace_memory_region *mem)
|
|
@@ -730,10 +725,24 @@ static struct kvm_memslots *install_new_memslots(struct kvm *kvm,
|
|
{
|
|
{
|
|
struct kvm_memslots *old_memslots = kvm->memslots;
|
|
struct kvm_memslots *old_memslots = kvm->memslots;
|
|
|
|
|
|
- update_memslots(slots, new, kvm->memslots->generation);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Set the low bit in the generation, which disables SPTE caching
|
|
|
|
+ * until the end of synchronize_srcu_expedited.
|
|
|
|
+ */
|
|
|
|
+ WARN_ON(old_memslots->generation & 1);
|
|
|
|
+ slots->generation = old_memslots->generation + 1;
|
|
|
|
+
|
|
|
|
+ update_memslots(slots, new);
|
|
rcu_assign_pointer(kvm->memslots, slots);
|
|
rcu_assign_pointer(kvm->memslots, slots);
|
|
synchronize_srcu_expedited(&kvm->srcu);
|
|
synchronize_srcu_expedited(&kvm->srcu);
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Increment the new memslot generation a second time. This prevents
|
|
|
|
+ * vm exits that race with memslot updates from caching a memslot
|
|
|
|
+ * generation that will (potentially) be valid forever.
|
|
|
|
+ */
|
|
|
|
+ slots->generation++;
|
|
|
|
+
|
|
kvm_arch_memslots_updated(kvm);
|
|
kvm_arch_memslots_updated(kvm);
|
|
|
|
|
|
return old_memslots;
|
|
return old_memslots;
|