Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 57128468 authored by Andres Lagar-Cavilla's avatar Andres Lagar-Cavilla Committed by Paolo Bonzini
Browse files

kvm: Fix page ageing bugs



1. We were calling clear_flush_young_notify in unmap_one, but we are
within an mmu notifier invalidate range scope. The spte exists no more
(due to range_start) and the accessed bit info has already been
propagated (due to kvm_pfn_set_accessed). Simply call
clear_flush_young.

2. We clear_flush_young on a primary MMU PMD, but this may be mapped
as a collection of PTEs by the secondary MMU (e.g. during log-dirty).
This required expanding the interface of the clear_flush_young mmu
notifier, so a lot of code has been trivially touched.

3. In the absence of shadow_accessed_mask (e.g. EPT A bit), we emulate
the access bit by blowing the spte. This requires proper synchronizing
with MMU notifier consumers, like every other removal of spte's does.

Signed-off-by: default avatarAndres Lagar-Cavilla <andreslc@google.com>
Acked-by: default avatarRik van Riel <riel@redhat.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 8a9522d2
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -170,7 +170,8 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);

/* We do not have shadow page tables, hence the empty hooks */
static inline int kvm_age_hva(struct kvm *kvm, unsigned long hva)
static inline int kvm_age_hva(struct kvm *kvm, unsigned long start,
			      unsigned long end)
{
	return 0;
}
+2 −1
Original line number Diff line number Diff line
@@ -180,7 +180,8 @@ int kvm_unmap_hva_range(struct kvm *kvm,
void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);

/* We do not have shadow page tables, hence the empty hooks */
static inline int kvm_age_hva(struct kvm *kvm, unsigned long hva)
static inline int kvm_age_hva(struct kvm *kvm, unsigned long start,
			      unsigned long end)
{
	return 0;
}
+1 −1
Original line number Diff line number Diff line
@@ -56,7 +56,7 @@
extern int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
extern int kvm_unmap_hva_range(struct kvm *kvm,
			       unsigned long start, unsigned long end);
extern int kvm_age_hva(struct kvm *kvm, unsigned long hva);
extern int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
extern int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
extern void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);

+1 −1
Original line number Diff line number Diff line
@@ -243,7 +243,7 @@ struct kvmppc_ops {
	int (*unmap_hva)(struct kvm *kvm, unsigned long hva);
	int (*unmap_hva_range)(struct kvm *kvm, unsigned long start,
			   unsigned long end);
	int (*age_hva)(struct kvm *kvm, unsigned long hva);
	int (*age_hva)(struct kvm *kvm, unsigned long start, unsigned long end);
	int (*test_age_hva)(struct kvm *kvm, unsigned long hva);
	void (*set_spte_hva)(struct kvm *kvm, unsigned long hva, pte_t pte);
	void (*mmu_destroy)(struct kvm_vcpu *vcpu);
+2 −2
Original line number Diff line number Diff line
@@ -851,9 +851,9 @@ int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
	return kvm->arch.kvm_ops->unmap_hva_range(kvm, start, end);
}

int kvm_age_hva(struct kvm *kvm, unsigned long hva)
int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end)
{
	return kvm->arch.kvm_ops->age_hva(kvm, hva);
	return kvm->arch.kvm_ops->age_hva(kvm, start, end);
}

int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
Loading