All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sean Christopherson <seanjc@google.com>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, pgonda@google.com
Subject: Re: [PATCH 10/12] KVM: SEV: Prohibit migration of a VM that has mirrors
Date: Mon, 29 Nov 2021 22:54:53 +0000	[thread overview]
Message-ID: <YaVaPbT2FOkcpY+n@google.com> (raw)
In-Reply-To: <20211123005036.2954379-11-pbonzini@redhat.com>

On Mon, Nov 22, 2021, Paolo Bonzini wrote:
> VMs that mirror an encryption context rely on the owner to keep the
> ASID allocated.  Performing a KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM
> would cause a dangling ASID:
> 
> 1. copy context from A to B (gets ref to A)
> 2. move context from A to L (moves ASID from A to L)
> 3. close L (releases ASID from L, B still references it)
> 
> The right way to do the handoff instead is to create a fresh mirror VM
> on the destination first:
> 
> 1. copy context from A to B (gets ref to A)
> [later] 2. close B (releases ref to A)
> 3. move context from A to L (moves ASID from A to L)
> 4. copy context from L to M
> 
> So, catch the situation by adding a count of how many VMs are
> mirroring this one's encryption context.
> 
> Fixes: 0b020f5af092 ("KVM: SEV: Add support for SEV-ES intra host migration")
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  arch/x86/kvm/svm/sev.c                        | 22 ++++++++++-
>  arch/x86/kvm/svm/svm.h                        |  1 +
>  .../selftests/kvm/x86_64/sev_migrate_tests.c  | 37 +++++++++++++++++++
>  3 files changed, 59 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
> index 025d9731b66c..89a716290fac 100644
> --- a/arch/x86/kvm/svm/sev.c
> +++ b/arch/x86/kvm/svm/sev.c
> @@ -1696,6 +1696,16 @@ int svm_vm_migrate_from(struct kvm *kvm, unsigned int source_fd)
>  	}
>  
>  	src_sev = &to_kvm_svm(source_kvm)->sev_info;
> +
> +	/*
> +	 * VMs mirroring src's encryption context rely on it to keep the
> +	 * ASID allocated, but below we are clearing src_sev->asid.

Prefer something to explan why this is disallowed instead of simply saying the
src's ASID is cleared/released, e.g.

	/*
	 * Disallow migrating a VM with active mirrors, as the mirrors rely on
	 * the VM to keep the ASID allocated.  Transferring all mirrors to dst
	 * would require locking all mirrors, and there's no known use case for
	 * intra-host migration of a VM with mirrors.
	 */

> +	 */
> +	if (src_sev->num_mirrored_vms) {
> +		ret = -EBUSY;
> +		goto out_unlock;
> +	}
> +
>  	dst_sev->misc_cg = get_current_misc_cg();
>  	cg_cleanup_sev = dst_sev;
>  	if (dst_sev->misc_cg != src_sev->misc_cg) {
> @@ -1987,6 +1997,7 @@ int svm_vm_copy_asid_from(struct kvm *kvm, unsigned int source_fd)
>  	 */
>  	source_sev = &to_kvm_svm(source_kvm)->sev_info;
>  	kvm_get_kvm(source_kvm);
> +	source_sev->num_mirrored_vms++;
>  
>  	/* Set enc_context_owner and copy its encryption context over */
>  	mirror_sev = &to_kvm_svm(kvm)->sev_info;
> @@ -2019,12 +2030,21 @@ void sev_vm_destroy(struct kvm *kvm)
>  	struct list_head *head = &sev->regions_list;
>  	struct list_head *pos, *q;
>  
> +	WARN_ON(sev->num_mirrored_vms);
> +
>  	if (!sev_guest(kvm))
>  		return;
>  
>  	/* If this is a mirror_kvm release the enc_context_owner and skip sev cleanup */
>  	if (is_mirroring_enc_context(kvm)) {
> -		kvm_put_kvm(sev->enc_context_owner);
> +		struct kvm *owner_kvm = sev->enc_context_owner;
> +		struct kvm_sev_info *owner_sev = &to_kvm_svm(owner_kvm)->sev_info;
> +
> +		mutex_lock(&owner_kvm->lock);
> +		if (!WARN_ON(!owner_sev->num_mirrored_vms))

Why not make num_mirrored_vms an atomic_t so that the destruction path doesn't
need to take owner_kvm->lock?  The asymmetry is a bit odd, but this feels worse
in its own way.

And since this is effectively a refcount, I almost wonder if it would make sense
to do:

	if (!refcount_inc_not_zero(&source_sev->num_mirrored_vms)) {
		refcount_set(&source_sev->num_mirrored_vms, 1);
		kvm_get_kvm(source_kvm);
	}

and then

	if (refcount_dec_and_test(&source_sev->num_mirrored_vms))
		kvm_put_kvm(owner_kvm);

to "officially" refcount something.


> +			owner_sev->num_mirrored_vms--;
> +		mutex_unlock(&owner_kvm->lock);
> +		kvm_put_kvm(owner_kvm);
>  		return;
>  	}
>  
> diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
> index 5faad3dc10e2..1c7306c370fa 100644
> --- a/arch/x86/kvm/svm/svm.h
> +++ b/arch/x86/kvm/svm/svm.h
> @@ -79,6 +79,7 @@ struct kvm_sev_info {
>  	struct list_head regions_list;  /* List of registered regions */
>  	u64 ap_jump_table;	/* SEV-ES AP Jump Table address */
>  	struct kvm *enc_context_owner; /* Owner of copied encryption context */
> +	unsigned long num_mirrored_vms; /* Number of VMs sharing this ASID */

Unsigned long is odd.  It's guaranteed to be u64 since SEV is 64-bit only.  If
it really is possible to overflow a refcount_t/int, than u64 or atomic64_t seems
more appropriate.

>  	struct misc_cg *misc_cg; /* For misc cgroup accounting */
>  	atomic_t migration_in_progress;
>  };

  reply	other threads:[~2021-11-29 23:12 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-23  0:50 [PATCH 00/12] Fixes for KVM_CAP_VM_MOVE/COPY_ENC_CONTEXT_FROM Paolo Bonzini
2021-11-23  0:50 ` [PATCH 01/12] selftests: fix check for circular KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM Paolo Bonzini
2021-12-01 15:52   ` Peter Gonda
2021-11-23  0:50 ` [PATCH 02/12] selftests: sev_migrate_tests: free all VMs Paolo Bonzini
2021-12-01 15:54   ` Peter Gonda
2021-11-23  0:50 ` [PATCH 03/12] KVM: SEV: expose KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM capability Paolo Bonzini
2021-11-29 22:28   ` Sean Christopherson
2021-12-01 15:55     ` Peter Gonda
2021-11-23  0:50 ` [PATCH 04/12] KVM: SEV: do not use list_replace_init on an empty list Paolo Bonzini
2021-11-29 22:27   ` Sean Christopherson
2021-11-23  0:50 ` [PATCH 05/12] KVM: SEV: cleanup locking for KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM Paolo Bonzini
2021-12-01 16:11   ` Peter Gonda
2021-11-23  0:50 ` [PATCH 06/12] KVM: SEV: initialize regions_list of a mirror VM Paolo Bonzini
2021-11-29 23:00   ` Sean Christopherson
2021-11-23  0:50 ` [PATCH 07/12] KVM: SEV: move mirror status to destination of KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM Paolo Bonzini
2021-11-29 23:02   ` Sean Christopherson
2021-11-23  0:50 ` [PATCH 08/12] selftests: sev_migrate_tests: add tests for KVM_CAP_VM_COPY_ENC_CONTEXT_FROM Paolo Bonzini
2021-12-01 18:09   ` Peter Gonda
2021-12-07 20:11     ` Peter Gonda
2021-11-23  0:50 ` [PATCH 09/12] KVM: SEV: Do COPY_ENC_CONTEXT_FROM with both VMs locked Paolo Bonzini
2021-11-29 23:08   ` Sean Christopherson
2021-11-23  0:50 ` [PATCH 10/12] KVM: SEV: Prohibit migration of a VM that has mirrors Paolo Bonzini
2021-11-29 22:54   ` Sean Christopherson [this message]
2021-12-01 18:17   ` Peter Gonda
2021-12-01 18:21     ` Paolo Bonzini
2021-11-23  0:50 ` [PATCH 11/12] KVM: SEV: do not take kvm->lock when destroying Paolo Bonzini
2021-11-29 22:31   ` Sean Christopherson
2021-11-23  0:50 ` [PATCH 12/12] KVM: SEV: accept signals in sev_lock_two_vms Paolo Bonzini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=YaVaPbT2FOkcpY+n@google.com \
    --to=seanjc@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=pgonda@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.