aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Christopherson <sean.j.christopherson@intel.com>2019-02-05 16:01:35 -0500
committerPaolo Bonzini <pbonzini@redhat.com>2019-02-20 16:48:48 -0500
commit83cdb56864bcb1466b454f17fff47348ca7925a2 (patch)
tree5aaec20dae0e3c69a9b00123718e8834da76ac59
parentea145aacf4ae8485cf179a4d0dc502e9f75044f4 (diff)
KVM: x86/mmu: Differentiate between nr zapped and list unstable
The return value of kvm_mmu_prepare_zap_page() has evolved to become overloaded to convey two separate pieces of information. 1) was at least one page zapped and 2) has the list of MMU pages become unstable. In it's original incarnation (as kvm_mmu_zap_page()), there was no return value at all. Commit 0738541396be ("KVM: MMU: awareness of new kvm_mmu_zap_page behaviour") added a return value in preparation for commit 4731d4c7a077 ("KVM: MMU: out of sync shadow core"). Although the return value was of type 'int', it was actually used as a boolean to indicate whether or not active_mmu_pages may have become unstable due to zapping children. Walking a list with list_for_each_entry_safe() only protects against deleting/moving the current entry, i.e. zapping a child page would break iteration due to modifying any number of entries. Later, commit 60c8aec6e2c9 ("KVM: MMU: use page array in unsync walk") modified mmu_zap_unsync_children() to return an approximation of the number of children zapped. This was not intentional, it was simply a side effect of how the code was written. The unintented side affect was then morphed into an actual feature by commit 77662e0028c7 ("KVM: MMU: fix kvm_mmu_zap_page() and its calling path"), which modified kvm_mmu_change_mmu_pages() to use the number of zapped pages when determining the number of MMU pages in use by the VM. Finally, commit 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed") added the initial page to the return value to make its behavior more consistent with what most users would expect. Incorporating the initial parent page in the return value of kvm_mmu_zap_page() breaks the original usage of restarting a list walk on a non-zero return value to handle a potentially unstable list, i.e. walks will unnecessarily restart when any page is zapped. Fix this by restoring the original behavior of kvm_mmu_zap_page(), i.e. return a boolean to indicate that the list may be unstable and move the number of zapped children to a dedicated parameter. Since the majority of callers to kvm_mmu_prepare_zap_page() don't care about either return value, preserve the current definition of kvm_mmu_prepare_zap_page() by making it a wrapper of a new helper, __kvm_mmu_prepare_zap_page(). This avoids having to update every call site and also provides cleaner code for functions that only care about the number of pages zapped. Fixes: 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed") Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--arch/x86/kvm/mmu.c36
1 files changed, 26 insertions, 10 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 6d602d4c3ca4..4b93fcdf0839 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -2200,8 +2200,8 @@ static void kvm_unlink_unsync_page(struct kvm *kvm, struct kvm_mmu_page *sp)
2200 --kvm->stat.mmu_unsync; 2200 --kvm->stat.mmu_unsync;
2201} 2201}
2202 2202
2203static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp, 2203static bool kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp,
2204 struct list_head *invalid_list); 2204 struct list_head *invalid_list);
2205static void kvm_mmu_commit_zap_page(struct kvm *kvm, 2205static void kvm_mmu_commit_zap_page(struct kvm *kvm,
2206 struct list_head *invalid_list); 2206 struct list_head *invalid_list);
2207 2207
@@ -2669,17 +2669,22 @@ static int mmu_zap_unsync_children(struct kvm *kvm,
2669 return zapped; 2669 return zapped;
2670} 2670}
2671 2671
2672static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp, 2672static bool __kvm_mmu_prepare_zap_page(struct kvm *kvm,
2673 struct list_head *invalid_list) 2673 struct kvm_mmu_page *sp,
2674 struct list_head *invalid_list,
2675 int *nr_zapped)
2674{ 2676{
2675 int ret; 2677 bool list_unstable;
2676 2678
2677 trace_kvm_mmu_prepare_zap_page(sp); 2679 trace_kvm_mmu_prepare_zap_page(sp);
2678 ++kvm->stat.mmu_shadow_zapped; 2680 ++kvm->stat.mmu_shadow_zapped;
2679 ret = mmu_zap_unsync_children(kvm, sp, invalid_list); 2681 *nr_zapped = mmu_zap_unsync_children(kvm, sp, invalid_list);
2680 kvm_mmu_page_unlink_children(kvm, sp); 2682 kvm_mmu_page_unlink_children(kvm, sp);
2681 kvm_mmu_unlink_parents(kvm, sp); 2683 kvm_mmu_unlink_parents(kvm, sp);
2682 2684
2685 /* Zapping children means active_mmu_pages has become unstable. */
2686 list_unstable = *nr_zapped;
2687
2683 if (!sp->role.invalid && !sp->role.direct) 2688 if (!sp->role.invalid && !sp->role.direct)
2684 unaccount_shadowed(kvm, sp); 2689 unaccount_shadowed(kvm, sp);
2685 2690
@@ -2687,7 +2692,7 @@ static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp,
2687 kvm_unlink_unsync_page(kvm, sp); 2692 kvm_unlink_unsync_page(kvm, sp);
2688 if (!sp->root_count) { 2693 if (!sp->root_count) {
2689 /* Count self */ 2694 /* Count self */
2690 ret++; 2695 (*nr_zapped)++;
2691 list_move(&sp->link, invalid_list); 2696 list_move(&sp->link, invalid_list);
2692 kvm_mod_used_mmu_pages(kvm, -1); 2697 kvm_mod_used_mmu_pages(kvm, -1);
2693 } else { 2698 } else {
@@ -2698,7 +2703,16 @@ static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp,
2698 } 2703 }
2699 2704
2700 sp->role.invalid = 1; 2705 sp->role.invalid = 1;
2701 return ret; 2706 return list_unstable;
2707}
2708
2709static bool kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp,
2710 struct list_head *invalid_list)
2711{
2712 int nr_zapped;
2713
2714 __kvm_mmu_prepare_zap_page(kvm, sp, invalid_list, &nr_zapped);
2715 return nr_zapped;
2702} 2716}
2703 2717
2704static void kvm_mmu_commit_zap_page(struct kvm *kvm, 2718static void kvm_mmu_commit_zap_page(struct kvm *kvm,
@@ -5830,13 +5844,14 @@ void kvm_mmu_zap_all(struct kvm *kvm)
5830{ 5844{
5831 struct kvm_mmu_page *sp, *node; 5845 struct kvm_mmu_page *sp, *node;
5832 LIST_HEAD(invalid_list); 5846 LIST_HEAD(invalid_list);
5847 int ign;
5833 5848
5834 spin_lock(&kvm->mmu_lock); 5849 spin_lock(&kvm->mmu_lock);
5835restart: 5850restart:
5836 list_for_each_entry_safe(sp, node, &kvm->arch.active_mmu_pages, link) { 5851 list_for_each_entry_safe(sp, node, &kvm->arch.active_mmu_pages, link) {
5837 if (sp->role.invalid && sp->root_count) 5852 if (sp->role.invalid && sp->root_count)
5838 continue; 5853 continue;
5839 if (kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list) || 5854 if (__kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list, &ign) ||
5840 cond_resched_lock(&kvm->mmu_lock)) 5855 cond_resched_lock(&kvm->mmu_lock))
5841 goto restart; 5856 goto restart;
5842 } 5857 }
@@ -5849,13 +5864,14 @@ static void kvm_mmu_zap_mmio_sptes(struct kvm *kvm)
5849{ 5864{
5850 struct kvm_mmu_page *sp, *node; 5865 struct kvm_mmu_page *sp, *node;
5851 LIST_HEAD(invalid_list); 5866 LIST_HEAD(invalid_list);
5867 int ign;
5852 5868
5853 spin_lock(&kvm->mmu_lock); 5869 spin_lock(&kvm->mmu_lock);
5854restart: 5870restart:
5855 list_for_each_entry_safe(sp, node, &kvm->arch.active_mmu_pages, link) { 5871 list_for_each_entry_safe(sp, node, &kvm->arch.active_mmu_pages, link) {
5856 if (!sp->mmio_cached) 5872 if (!sp->mmio_cached)
5857 continue; 5873 continue;
5858 if (kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list) || 5874 if (__kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list, &ign) ||
5859 cond_resched_lock(&kvm->mmu_lock)) 5875 cond_resched_lock(&kvm->mmu_lock))
5860 goto restart; 5876 goto restart;
5861 } 5877 }