[rh7,3/2] kvm: fix race between mmu_shrink_scan() and VM destroy

Submitted by Konstantin Khorenko on June 7, 2019, 11:49 a.m.

Details

Message ID 20190607114914.13357-1-khorenko@virtuozzo.com
State New
Series "Series without cover letter"
Headers show

Commit Message

Konstantin Khorenko June 7, 2019, 11:49 a.m.
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))

Comments

Kirill Tkhai June 7, 2019, 12:18 p.m.
On 07.06.2019 14:49, Konstantin Khorenko wrote:
> 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>

Reviewed-by: Kirill Tkhai <ktkhai@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(-)
> 
> 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))
>