static u8 sev_enc_bit;
static DECLARE_RWSEM(sev_deactivate_lock);
static DEFINE_MUTEX(sev_bitmap_lock);
+/* Protects kvm_sev_info's enc_context_owner, mirror_vms and mirror_entry. */
+static DEFINE_MUTEX(sev_mirror_lock);
unsigned int max_sev_asid;
static unsigned int min_sev_asid;
static unsigned int max_sev_es_asid;
dst->asid = src->asid;
dst->handle = src->handle;
dst->pages_locked = src->pages_locked;
- dst->enc_context_owner = src->enc_context_owner;
dst->es_active = src->es_active;
dst->vmsa_features = src->vmsa_features;
src->active = false;
src->handle = 0;
src->pages_locked = 0;
- src->enc_context_owner = NULL;
src->es_active = false;
list_cut_before(&dst->regions_list, &src->regions_list, &src->regions_list);
+ mutex_lock(&sev_mirror_lock);
+
/*
* If this VM has mirrors, "transfer" each mirror's refcount of the
* source to the destination (this KVM). The caller holds a reference
* If this VM is a mirror, remove the old mirror from the owners list
* and add the new mirror to the list.
*/
- if (is_mirroring_enc_context(dst_kvm)) {
- struct kvm_sev_info *owner_sev_info = to_kvm_sev_info(dst->enc_context_owner);
+ if (is_mirroring_enc_context(src_kvm)) {
+ struct kvm_sev_info *owner_sev_info = to_kvm_sev_info(src->enc_context_owner);
+ dst->enc_context_owner = src->enc_context_owner;
+ src->enc_context_owner = NULL;
list_del(&src->mirror_entry);
list_add_tail(&dst->mirror_entry, &owner_sev_info->mirror_vms);
}
+ mutex_unlock(&sev_mirror_lock);
kvm_for_each_vcpu(i, dst_vcpu, dst_kvm) {
dst_svm = to_svm(dst_vcpu);
* disappear until we're done with it
*/
source_sev = to_kvm_sev_info(source_kvm);
- kvm_get_kvm(source_kvm);
- list_add_tail(&mirror_sev->mirror_entry, &source_sev->mirror_vms);
/* Set enc_context_owner and copy its encryption context over */
+ mutex_lock(&sev_mirror_lock);
+ kvm_get_kvm(source_kvm);
+ list_add_tail(&mirror_sev->mirror_entry, &source_sev->mirror_vms);
mirror_sev->enc_context_owner = source_kvm;
+ mutex_unlock(&sev_mirror_lock);
+
mirror_sev->active = true;
mirror_sev->asid = source_sev->asid;
mirror_sev->fd = source_sev->fd;
* Note, mirror VMs don't support registering encrypted regions.
*/
if (is_mirroring_enc_context(kvm)) {
- struct kvm *owner_kvm = sev->enc_context_owner;
+ struct kvm *owner_kvm;
- mutex_lock(&owner_kvm->lock);
+ mutex_lock(&sev_mirror_lock);
+ owner_kvm = sev->enc_context_owner;
list_del(&sev->mirror_entry);
- mutex_unlock(&owner_kvm->lock);
+ sev->enc_context_owner = NULL;
+
+ /*
+ * The reference to owner_kvm cannot move after sev_mirror_lock is
+ * released. Release it before kvm_put_kvm() so that owner_kvm is
+ * never destroyed inside sev_mirror_lock.
+ */
+ mutex_unlock(&sev_mirror_lock);
kvm_put_kvm(owner_kvm);
return;
}