Received: by 2002:a05:6a10:1a4d:0:0:0:0 with SMTP id nk13csp1618045pxb; Wed, 9 Feb 2022 00:13:31 -0800 (PST) X-Google-Smtp-Source: ABdhPJxgRPbCcEEAiELlC5RDyCq11IQYyKQJvEstGJEtVDtQravYXU1lB96nPWy7PMDeq7gy938C X-Received: by 2002:a05:6402:5109:: with SMTP id m9mr960463edd.325.1644394410892; Wed, 09 Feb 2022 00:13:30 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1644394410; cv=none; d=google.com; s=arc-20160816; b=Kc/nWJK0pcPJ9QRfy2MwlnbOzTAsqDLbsbJxGexJclheil9w3lpDf87m2P6cIiyEgF BeEZAB/psdMwAZgZrrrtPShwY4J48inoZXvi1CcyBN7S2HrI+9eDHL1pK/2EbVOsMOdX 7/UJkCU6VINT5cbh6t1K7DpWrVc+OJyvrXBDoBLEkkrVpr54DZBrawP5kbw7dlLnXS4n 7OLnpCNkWn/ChHqH0Ne1YcdR1L7qQJcXkr/WRAI/vgmTekxce2V6iduYwUHq5KuUtuAl s/3GuuWL3HN1hsteU/7yh8T/yElTGiZB/8LIaaGtGqT92RwY08sJumOvKKJQJMxV9aXG EYKw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:in-reply-to:content-disposition:mime-version :references:message-id:subject:cc:to:from:date:dkim-signature; bh=ThSHxAOPclKygYpsG6VmV+qfMk9x1IPAyMO8Co5HbOc=; b=bP10X6/xcYb9dgXLbFb5kGG+c+PU36/7v3EbnSMBvZhAq0midiIr/7M097p0luLZZx qm7nQhVxKJbLyrzKHRyoKi2mJegaF1OG6w7E/Ll7uV2t0Tgc3CdDawoDZAFuPG5himgd l5ogcr2SGF2QVzC+uQ0py+Hy+0ha+weTFflXAQfR7zojToWBdbE/UP8djz+JJUlkWVUL DSY3Tpd3QRo2JEEtoibawYf1++5hbqcMFnhkNAl2tDY0aaTzFSMbWt+LEnQE7EaE8rwn MY7kng12tZIityDPr2TQgwpQ9H0VwWKfxvA13ANFKhKoVaSGsATxVguK8Xm7CRZbcETE jacA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=kmb14pxu; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id w5si2241755edv.510.2022.02.09.00.13.05; Wed, 09 Feb 2022 00:13:30 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=kmb14pxu; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345088AbiBHBE0 (ORCPT + 99 others); Mon, 7 Feb 2022 20:04:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39340 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233102AbiBGXTd (ORCPT ); Mon, 7 Feb 2022 18:19:33 -0500 Received: from mail-pj1-x1035.google.com (mail-pj1-x1035.google.com [IPv6:2607:f8b0:4864:20::1035]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 73A0CC0612A4 for ; Mon, 7 Feb 2022 15:19:32 -0800 (PST) Received: by mail-pj1-x1035.google.com with SMTP id v4so8550751pjh.2 for ; Mon, 07 Feb 2022 15:19:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=ThSHxAOPclKygYpsG6VmV+qfMk9x1IPAyMO8Co5HbOc=; b=kmb14pxupGC2sDAnbX9Bh5L1woRvkv3WkvbZIKkM3MMG262WOPVKK1LtB05kz7o8V+ B7OjeVwlXI8mBEHkADnt89aw5Xxa/lep6snbGzcw4p/9IQm7xyHWeCJbaltKlok9XRZV AylZGLQomu8E1huNtupY74xKbIDWCw7GFavFGmjLX+vlIZURQTSX/7iqrjFxBVqxBPnj OcrCzCT7h8UJPu2yyadZG8wGYAfEFbHPOjFokH61y4YV2cJY83o9BSUVJp64mRUyU3/j /MuMYDsoi7wxyPUc8GXI/0TuY9/VfzRFkohcTySRa7fb0Sh88s0y/39UF0ENE6sE9zab NMBw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=ThSHxAOPclKygYpsG6VmV+qfMk9x1IPAyMO8Co5HbOc=; b=eHpdVqhNVxlFZsLfyGC5riQV6XJLREA+WUdFI0yrx969OHrivmcbWZpQMD4Ink05Bx NyFQb2gV9VZWrz3nEKMaLz/Tp7FBt96yWv9liOkxh91Ewwqk2OjfiaFN+BREymWlrMpO I95Sx58h9/Wg1Ezg1HyHtsHNhlur0s/toGgciFE1LBYuw6G0gkMEFgS0qiS+cdy34OQi oTle3r/68l7A9Vga9j/3VKjhWXXwbwiZaF5vGw73V35YYltudC7OXOWkeH0NwsN2oT2c s9jr0c5/oWoyElMjOmJ4hZnzWpjwBXX0t1bjPHgH+Xi7eCy8shggr5nDXcio5WBl+s5E 79sg== X-Gm-Message-State: AOAM530xtujGfmkl/frs1hbnBrqWj5cB54wXcmQQVuTHf2eR5/s7reeO bf0TTHEF46YqPMQsYKUUD2Sv9A== X-Received: by 2002:a17:902:7e06:: with SMTP id b6mr1915957plm.58.1644275971681; Mon, 07 Feb 2022 15:19:31 -0800 (PST) Received: from google.com (157.214.185.35.bc.googleusercontent.com. [35.185.214.157]) by smtp.gmail.com with ESMTPSA id o125sm9725998pfb.116.2022.02.07.15.19.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Feb 2022 15:19:31 -0800 (PST) Date: Mon, 7 Feb 2022 23:19:27 +0000 From: Sean Christopherson To: Peter Gonda Cc: kvm@vger.kernel.org, Paolo Bonzini , Marc Orr , linux-kernel@vger.kernel.org Subject: Re: [PATCH] KVM: SEV: Allow SEV intra-host migration of VM with mirrors Message-ID: References: <20220111154048.2108264-1-pgonda@google.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20220111154048.2108264-1-pgonda@google.com> X-Spam-Status: No, score=-17.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, ENV_AND_HDR_SPF_MATCH,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE,USER_IN_DEF_DKIM_WL,USER_IN_DEF_SPF_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Tue, Jan 11, 2022, Peter Gonda wrote: > @@ -1623,22 +1624,41 @@ static void sev_unlock_vcpus_for_migration(struct kvm *kvm) > } > } > > -static void sev_migrate_from(struct kvm_sev_info *dst, > - struct kvm_sev_info *src) > +static void sev_migrate_from(struct kvm *dst_kvm, struct kvm *src_kvm) > { > + struct kvm_sev_info *dst = &to_kvm_svm(dst_kvm)->sev_info; > + struct kvm_sev_info *src = &to_kvm_svm(src_kvm)->sev_info; > + struct kvm_sev_info *mirror, *tmp; > + > dst->active = true; > dst->asid = src->asid; > dst->handle = src->handle; > dst->pages_locked = src->pages_locked; > dst->enc_context_owner = src->enc_context_owner; > + dst->num_mirrored_vms = src->num_mirrored_vms; > > src->asid = 0; > src->active = false; > src->handle = 0; > src->pages_locked = 0; > src->enc_context_owner = NULL; > + src->num_mirrored_vms = 0; > > list_cut_before(&dst->regions_list, &src->regions_list, &src->regions_list); > + list_cut_before(&dst->mirror_vms, &src->mirror_vms, &src->mirror_vms); > + > + /* > + * If this VM has mirrors we need to update the KVM refcounts from the > + * source to the destination. > + */ It's worth calling out that a reference is being taken on behalf of the mirror, that detail is easy to miss. And maybe call out that the caller holds a reference to @src_kvm? /* * If this VM has mirrors, "transfer" each mirror's refcount of the * source to the destination (this KVM). The caller holds a reference * to the source, so there's no danger of use-after-free. */ > + if (dst->num_mirrored_vms > 0) { > + list_for_each_entry_safe(mirror, tmp, &dst->mirror_vms, > + mirror_entry) { > + kvm_get_kvm(dst_kvm); > + kvm_put_kvm(src_kvm); > + mirror->enc_context_owner = dst_kvm; > + } > + } > } > > static int sev_es_migrate_from(struct kvm *dst, struct kvm *src) ... > @@ -2050,10 +2062,17 @@ void sev_vm_destroy(struct kvm *kvm) > if (is_mirroring_enc_context(kvm)) { > struct kvm *owner_kvm = sev->enc_context_owner; > struct kvm_sev_info *owner_sev = &to_kvm_svm(owner_kvm)->sev_info; > + struct kvm_sev_info *mirror, *tmp; > > mutex_lock(&owner_kvm->lock); > if (!WARN_ON(!owner_sev->num_mirrored_vms)) > owner_sev->num_mirrored_vms--; > + > + list_for_each_entry_safe(mirror, tmp, &owner_sev->mirror_vms, > + mirror_entry) > + if (mirror == sev) > + list_del(&mirror->mirror_entry); > + There's no need to walk the list just to find the entry you already have. Maaaaybe if you were sanity checking, but it's not like we can do anything helpful if the sanity check fails, so eating a #GP due to consuming e.g. LIST_POISON1 is just as good as anything else. if (is_mirroring_enc_context(kvm)) { struct kvm *owner_kvm = sev->enc_context_owner; mutex_lock(&owner_kvm->lock); list_del(&->mirror_entry); mutex_unlock(&owner_kvm->lock); kvm_put_kvm(owner_kvm); return; } > 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 daa8ca84afcc..b9f5e33d5232 100644 > --- a/arch/x86/kvm/svm/svm.h > +++ b/arch/x86/kvm/svm/svm.h > @@ -81,6 +81,10 @@ struct kvm_sev_info { > 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 */ > + union { > + struct list_head mirror_vms; /* List of VMs mirroring */ > + struct list_head mirror_entry; /* Use as a list entry of mirrors */ > + }; Whoops. IIRC, I suggested a union for tracking mirrors vs mirrored. After seeing the code, that was a bad suggestion. Memory isn't at a premimum for a per-VM object, so storing an extra list_head is a non-issue. If we split the two, then num_mirrored_vms goes away, and more importantly we won't have to deal with bugs where we inevitably forget to guard access to the union with a check against num_mirrored_vms. E.g. (completely untested and probably incomplete) --- arch/x86/kvm/svm/sev.c | 32 +++++++++----------------------- arch/x86/kvm/svm/svm.h | 7 ++----- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 369cf8c4da61..41f7e733c33e 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -1635,29 +1635,25 @@ static void sev_migrate_from(struct kvm *dst_kvm, struct kvm *src_kvm) dst->handle = src->handle; dst->pages_locked = src->pages_locked; dst->enc_context_owner = src->enc_context_owner; - dst->num_mirrored_vms = src->num_mirrored_vms; src->asid = 0; src->active = false; src->handle = 0; src->pages_locked = 0; src->enc_context_owner = NULL; - src->num_mirrored_vms = 0; list_cut_before(&dst->regions_list, &src->regions_list, &src->regions_list); list_cut_before(&dst->mirror_vms, &src->mirror_vms, &src->mirror_vms); /* - * If this VM has mirrors we need to update the KVM refcounts from the - * source to the destination. + * If this VM has mirrors, "transfer" each mirror's refcount from the + * source to the destination (this KVM). The caller holds a reference + * to the source, so there's no danger of use-after-free. */ - if (dst->num_mirrored_vms > 0) { - list_for_each_entry_safe(mirror, tmp, &dst->mirror_vms, - mirror_entry) { - kvm_get_kvm(dst_kvm); - kvm_put_kvm(src_kvm); - mirror->enc_context_owner = dst_kvm; - } + list_for_each_entry_safe(mirror, tmp, &dst->mirror_vms, mirror_entry) { + kvm_get_kvm(dst_kvm); + kvm_put_kvm(src_kvm); + mirror->enc_context_owner = dst_kvm; } } @@ -2019,7 +2015,6 @@ int sev_vm_copy_enc_context_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++; mirror_sev = &to_kvm_svm(kvm)->sev_info; list_add_tail(&mirror_sev->mirror_entry, &source_sev->mirror_vms); @@ -2053,7 +2048,7 @@ 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); + WARN_ON(!list_empty(&sev->mirror_vms)); if (!sev_guest(kvm)) return; @@ -2061,18 +2056,9 @@ void sev_vm_destroy(struct kvm *kvm) /* If this is a mirror_kvm release the enc_context_owner and skip sev cleanup */ if (is_mirroring_enc_context(kvm)) { struct kvm *owner_kvm = sev->enc_context_owner; - struct kvm_sev_info *owner_sev = &to_kvm_svm(owner_kvm)->sev_info; - struct kvm_sev_info *mirror, *tmp; mutex_lock(&owner_kvm->lock); - if (!WARN_ON(!owner_sev->num_mirrored_vms)) - owner_sev->num_mirrored_vms--; - - list_for_each_entry_safe(mirror, tmp, &owner_sev->mirror_vms, - mirror_entry) - if (mirror == sev) - list_del(&mirror->mirror_entry); - + list_del(&mirror->mirror_entry); 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 0876329f273d..79bf568c2558 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -79,11 +79,8 @@ 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 */ - union { - struct list_head mirror_vms; /* List of VMs mirroring */ - struct list_head mirror_entry; /* Use as a list entry of mirrors */ - }; + struct list_head mirror_vms; /* List of VMs mirroring */ + struct list_head mirror_entry; /* Use as a list entry of mirrors */ struct misc_cg *misc_cg; /* For misc cgroup accounting */ atomic_t migration_in_progress; }; base-commit: 618a9a6fda17f48d86a1ce9851bd8ceffdc57d75 --