[RHEL7,COMMIT] kvm: fix race between mmu_shrink_scan() and VM destroy

Submitted by Konstantin Khorenko on June 7, 2019, 4:22 p.m.

Details

Message ID 201906071622.x57GMEAC017614@finist-ce7.sw.ru
State New
Series "Series without cover letter"
Headers show

Commit Message

Konstantin Khorenko June 7, 2019, 4:22 p.m.
The commit is pushed to "branch-rh7-3.10.0-957.12.2.vz7.96.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-957.12.2.vz7.96.14
------>
commit 1fa5a8788c5c93c37558f216ec0185f09310c3b6
Author: Konstantin Khorenko <khorenko@virtuozzo.com>
Date:   Fri Jun 7 14:28:44 2019 +0300

    kvm: fix race between mmu_shrink_scan() and VM destroy
    
    Honor the race between VM memory shrink and VM destroy,
    just skip dying VMs, shrink alive ones.
    
    Fixes: 05a623470d4b ("kvm: move actual VM memory shrink out of kvm_lock")
    https://jira.sw.ru/browse/PSBM-95077
    
    Reported-by: Kirill Tkhai <ktkhai@virtuozzo.com>
    Signed-off-by: Konstantin Khorenko <khorenko@virtuozzo.com>
---
 arch/x86/kvm/mmu.c       | 7 ++++++-
 include/linux/kvm_host.h | 1 +
 virt/kvm/kvm_main.c      | 6 ++++++
 3 files changed, 13 insertions(+), 1 deletion(-)

Patch hide | download patch | download mbox

diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 0c3ded90dd38..18c7f63fcccd 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -5383,7 +5383,12 @@  mmu_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
 		      !kvm_has_zapped_obsolete_pages(kvm))
 			continue;
 
-		kvm_get_kvm(kvm);
+		/*
+		 * If try_get fails, we race with last kvm_put_kvm(),
+		 * so skip the VM, it will die soon anyway.
+		 */
+		if (!kvm_try_get_kvm(kvm))
+			continue;
 		spin_unlock(&kvm_lock);
 
 		idx = srcu_read_lock(&kvm->srcu);
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index ff50020dc91f..f0d028e6f9fb 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -542,6 +542,7 @@  int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,
 void kvm_exit(void);
 
 void kvm_get_kvm(struct kvm *kvm);
+int kvm_try_get_kvm(struct kvm *kvm);
 void kvm_put_kvm(struct kvm *kvm);
 
 static inline struct kvm_memslots *__kvm_memslots(struct kvm *kvm, int as_id)
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index ccab89847623..b8b0146f7c8b 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -733,6 +733,12 @@  void kvm_get_kvm(struct kvm *kvm)
 }
 EXPORT_SYMBOL_GPL(kvm_get_kvm);
 
+int kvm_try_get_kvm(struct kvm *kvm)
+{
+	return atomic_inc_not_zero(&kvm->users_count);
+}
+EXPORT_SYMBOL_GPL(kvm_try_get_kvm);
+
 void kvm_put_kvm(struct kvm *kvm)
 {
 	if (atomic_dec_and_test(&kvm->users_count))