From nobody Wed Apr 8 15:55:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EC21FECAAA1 for ; Thu, 27 Oct 2022 16:21:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236604AbiJ0QVB (ORCPT ); Thu, 27 Oct 2022 12:21:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54574 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236554AbiJ0QS5 (ORCPT ); Thu, 27 Oct 2022 12:18:57 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5711418F0CA for ; Thu, 27 Oct 2022 09:18:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666887534; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=S+lEpw8fz5CKI+PUTb/XkQrqBjkbb06nsx/UIPL+5rI=; b=hyK575s7f/omeE5JWjYSl9siGjZu66zhwoOlv4uIQUZDczrT8zoXkFyksFPAqqE+o7mdcM QoMhVPzEHrayFj17J8BXfTY2UowReFf4D7lr9SDSQ/Ses165o/aIQoewrkbh9VCL9IrjDr 0IWfEkkK7X6Fd6oStaR1rEVdDfiYlOo= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-271-zNLFflQqPsaVIbSbOgmE9Q-1; Thu, 27 Oct 2022 12:18:51 -0400 X-MC-Unique: zNLFflQqPsaVIbSbOgmE9Q-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 748DD185A78F; Thu, 27 Oct 2022 16:18:50 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4974D1415117; Thu, 27 Oct 2022 16:18:50 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: mhal@rbox.co, seanjc@google.com, stable@vger.kernel.org Subject: [PATCH 01/16] KVM: Initialize gfn_to_pfn_cache locks in dedicated helper Date: Thu, 27 Oct 2022 12:18:34 -0400 Message-Id: <20221027161849.2989332-2-pbonzini@redhat.com> In-Reply-To: <20221027161849.2989332-1-pbonzini@redhat.com> References: <20221027161849.2989332-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.7 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Michal Luczaj Move the gfn_to_pfn_cache lock initialization to another helper and call the new helper during VM/vCPU creation. There are race conditions possible due to kvm_gfn_to_pfn_cache_init()'s ability to re-initialize the cache's locks. For example: a race between ioctl(KVM_XEN_HVM_EVTCHN_SEND) and kvm_gfn_to_pfn_cache_init() leads to a corrupted shinfo gpc lock. (thread 1) | (thread 2) | kvm_xen_set_evtchn_fast | read_lock_irqsave(&gpc->lock, ...) | | kvm_gfn_to_pfn_cache_init | rwlock_init(&gpc->lock) read_unlock_irqrestore(&gpc->lock, ...) | Rename "cache_init" and "cache_destroy" to activate+deactivate to avoid implying that the cache really is destroyed/freed. Note, there more races in the newly named kvm_gpc_activate() that will be addressed separately. Fixes: 982ed0de4753 ("KVM: Reinstate gfn_to_pfn_cache with invalidation sup= port") Cc: stable@vger.kernel.org Suggested-by: Sean Christopherson Signed-off-by: Michal Luczaj [sean: call out that this is a bug fix] Signed-off-by: Sean Christopherson Message-Id: <20221013211234.1318131-2-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 12 +++++---- arch/x86/kvm/xen.c | 57 +++++++++++++++++++++------------------- include/linux/kvm_host.h | 24 ++++++++++++----- virt/kvm/pfncache.c | 21 ++++++++------- 4 files changed, 66 insertions(+), 48 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 104b72df33d6..521b433f978c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2315,11 +2315,11 @@ static void kvm_write_system_time(struct kvm_vcpu *= vcpu, gpa_t system_time, =20 /* we verify if the enable bit is set... */ if (system_time & 1) { - kvm_gfn_to_pfn_cache_init(vcpu->kvm, &vcpu->arch.pv_time, vcpu, - KVM_HOST_USES_PFN, system_time & ~1ULL, - sizeof(struct pvclock_vcpu_time_info)); + kvm_gpc_activate(vcpu->kvm, &vcpu->arch.pv_time, vcpu, + KVM_HOST_USES_PFN, system_time & ~1ULL, + sizeof(struct pvclock_vcpu_time_info)); } else { - kvm_gfn_to_pfn_cache_destroy(vcpu->kvm, &vcpu->arch.pv_time); + kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.pv_time); } =20 return; @@ -3388,7 +3388,7 @@ static int kvm_pv_enable_async_pf_int(struct kvm_vcpu= *vcpu, u64 data) =20 static void kvmclock_reset(struct kvm_vcpu *vcpu) { - kvm_gfn_to_pfn_cache_destroy(vcpu->kvm, &vcpu->arch.pv_time); + kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.pv_time); vcpu->arch.time =3D 0; } =20 @@ -11829,6 +11829,8 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) vcpu->arch.regs_avail =3D ~0; vcpu->arch.regs_dirty =3D ~0; =20 + kvm_gpc_init(&vcpu->arch.pv_time); + if (!irqchip_in_kernel(vcpu->kvm) || kvm_vcpu_is_reset_bsp(vcpu)) vcpu->arch.mp_state =3D KVM_MP_STATE_RUNNABLE; else diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 93c628d3e3a9..b2be60c6efa4 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -42,13 +42,13 @@ static int kvm_xen_shared_info_init(struct kvm *kvm, gf= n_t gfn) int idx =3D srcu_read_lock(&kvm->srcu); =20 if (gfn =3D=3D GPA_INVALID) { - kvm_gfn_to_pfn_cache_destroy(kvm, gpc); + kvm_gpc_deactivate(kvm, gpc); goto out; } =20 do { - ret =3D kvm_gfn_to_pfn_cache_init(kvm, gpc, NULL, KVM_HOST_USES_PFN, - gpa, PAGE_SIZE); + ret =3D kvm_gpc_activate(kvm, gpc, NULL, KVM_HOST_USES_PFN, gpa, + PAGE_SIZE); if (ret) goto out; =20 @@ -554,15 +554,15 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, stru= ct kvm_xen_vcpu_attr *data) offsetof(struct compat_vcpu_info, time)); =20 if (data->u.gpa =3D=3D GPA_INVALID) { - kvm_gfn_to_pfn_cache_destroy(vcpu->kvm, &vcpu->arch.xen.vcpu_info_cache= ); + kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.xen.vcpu_info_cache); r =3D 0; break; } =20 - r =3D kvm_gfn_to_pfn_cache_init(vcpu->kvm, - &vcpu->arch.xen.vcpu_info_cache, - NULL, KVM_HOST_USES_PFN, data->u.gpa, - sizeof(struct vcpu_info)); + r =3D kvm_gpc_activate(vcpu->kvm, + &vcpu->arch.xen.vcpu_info_cache, NULL, + KVM_HOST_USES_PFN, data->u.gpa, + sizeof(struct vcpu_info)); if (!r) kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); =20 @@ -570,16 +570,16 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, stru= ct kvm_xen_vcpu_attr *data) =20 case KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO: if (data->u.gpa =3D=3D GPA_INVALID) { - kvm_gfn_to_pfn_cache_destroy(vcpu->kvm, - &vcpu->arch.xen.vcpu_time_info_cache); + kvm_gpc_deactivate(vcpu->kvm, + &vcpu->arch.xen.vcpu_time_info_cache); r =3D 0; break; } =20 - r =3D kvm_gfn_to_pfn_cache_init(vcpu->kvm, - &vcpu->arch.xen.vcpu_time_info_cache, - NULL, KVM_HOST_USES_PFN, data->u.gpa, - sizeof(struct pvclock_vcpu_time_info)); + r =3D kvm_gpc_activate(vcpu->kvm, + &vcpu->arch.xen.vcpu_time_info_cache, + NULL, KVM_HOST_USES_PFN, data->u.gpa, + sizeof(struct pvclock_vcpu_time_info)); if (!r) kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); break; @@ -590,16 +590,15 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, stru= ct kvm_xen_vcpu_attr *data) break; } if (data->u.gpa =3D=3D GPA_INVALID) { - kvm_gfn_to_pfn_cache_destroy(vcpu->kvm, - &vcpu->arch.xen.runstate_cache); + kvm_gpc_deactivate(vcpu->kvm, + &vcpu->arch.xen.runstate_cache); r =3D 0; break; } =20 - r =3D kvm_gfn_to_pfn_cache_init(vcpu->kvm, - &vcpu->arch.xen.runstate_cache, - NULL, KVM_HOST_USES_PFN, data->u.gpa, - sizeof(struct vcpu_runstate_info)); + r =3D kvm_gpc_activate(vcpu->kvm, &vcpu->arch.xen.runstate_cache, + NULL, KVM_HOST_USES_PFN, data->u.gpa, + sizeof(struct vcpu_runstate_info)); break; =20 case KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT: @@ -1816,7 +1815,12 @@ void kvm_xen_init_vcpu(struct kvm_vcpu *vcpu) { vcpu->arch.xen.vcpu_id =3D vcpu->vcpu_idx; vcpu->arch.xen.poll_evtchn =3D 0; + timer_setup(&vcpu->arch.xen.poll_timer, cancel_evtchn_poll, 0); + + kvm_gpc_init(&vcpu->arch.xen.runstate_cache); + kvm_gpc_init(&vcpu->arch.xen.vcpu_info_cache); + kvm_gpc_init(&vcpu->arch.xen.vcpu_time_info_cache); } =20 void kvm_xen_destroy_vcpu(struct kvm_vcpu *vcpu) @@ -1824,18 +1828,17 @@ void kvm_xen_destroy_vcpu(struct kvm_vcpu *vcpu) if (kvm_xen_timer_enabled(vcpu)) kvm_xen_stop_timer(vcpu); =20 - kvm_gfn_to_pfn_cache_destroy(vcpu->kvm, - &vcpu->arch.xen.runstate_cache); - kvm_gfn_to_pfn_cache_destroy(vcpu->kvm, - &vcpu->arch.xen.vcpu_info_cache); - kvm_gfn_to_pfn_cache_destroy(vcpu->kvm, - &vcpu->arch.xen.vcpu_time_info_cache); + kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.xen.runstate_cache); + kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.xen.vcpu_info_cache); + kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.xen.vcpu_time_info_cache); + del_timer_sync(&vcpu->arch.xen.poll_timer); } =20 void kvm_xen_init_vm(struct kvm *kvm) { idr_init(&kvm->arch.xen.evtchn_ports); + kvm_gpc_init(&kvm->arch.xen.shinfo_cache); } =20 void kvm_xen_destroy_vm(struct kvm *kvm) @@ -1843,7 +1846,7 @@ void kvm_xen_destroy_vm(struct kvm *kvm) struct evtchnfd *evtchnfd; int i; =20 - kvm_gfn_to_pfn_cache_destroy(kvm, &kvm->arch.xen.shinfo_cache); + kvm_gpc_deactivate(kvm, &kvm->arch.xen.shinfo_cache); =20 idr_for_each_entry(&kvm->arch.xen.evtchn_ports, evtchnfd, i) { if (!evtchnfd->deliver.port.port) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 00c3448ba7f8..18592bdf4c1b 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1240,8 +1240,18 @@ int kvm_vcpu_write_guest(struct kvm_vcpu *vcpu, gpa_= t gpa, const void *data, void kvm_vcpu_mark_page_dirty(struct kvm_vcpu *vcpu, gfn_t gfn); =20 /** - * kvm_gfn_to_pfn_cache_init - prepare a cached kernel mapping and HPA for= a - * given guest physical address. + * kvm_gpc_init - initialize gfn_to_pfn_cache. + * + * @gpc: struct gfn_to_pfn_cache object. + * + * This sets up a gfn_to_pfn_cache by initializing locks. Note, the cache= must + * be zero-allocated (or zeroed by the caller before init). + */ +void kvm_gpc_init(struct gfn_to_pfn_cache *gpc); + +/** + * kvm_gpc_activate - prepare a cached kernel mapping and HPA for a given = guest + * physical address. * * @kvm: pointer to kvm instance. * @gpc: struct gfn_to_pfn_cache object. @@ -1265,9 +1275,9 @@ void kvm_vcpu_mark_page_dirty(struct kvm_vcpu *vcpu, = gfn_t gfn); * kvm_gfn_to_pfn_cache_check() to ensure that the cache is valid before * accessing the target page. */ -int kvm_gfn_to_pfn_cache_init(struct kvm *kvm, struct gfn_to_pfn_cache *gp= c, - struct kvm_vcpu *vcpu, enum pfn_cache_usage usage, - gpa_t gpa, unsigned long len); +int kvm_gpc_activate(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, + struct kvm_vcpu *vcpu, enum pfn_cache_usage usage, + gpa_t gpa, unsigned long len); =20 /** * kvm_gfn_to_pfn_cache_check - check validity of a gfn_to_pfn_cache. @@ -1324,7 +1334,7 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, str= uct gfn_to_pfn_cache *gpc, void kvm_gfn_to_pfn_cache_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *= gpc); =20 /** - * kvm_gfn_to_pfn_cache_destroy - destroy and unlink a gfn_to_pfn_cache. + * kvm_gpc_deactivate - deactivate and unlink a gfn_to_pfn_cache. * * @kvm: pointer to kvm instance. * @gpc: struct gfn_to_pfn_cache object. @@ -1332,7 +1342,7 @@ void kvm_gfn_to_pfn_cache_unmap(struct kvm *kvm, stru= ct gfn_to_pfn_cache *gpc); * This removes a cache from the @kvm's list to be processed on MMU notifi= er * invocation. */ -void kvm_gfn_to_pfn_cache_destroy(struct kvm *kvm, struct gfn_to_pfn_cache= *gpc); +void kvm_gpc_deactivate(struct kvm *kvm, struct gfn_to_pfn_cache *gpc); =20 void kvm_sigset_activate(struct kvm_vcpu *vcpu); void kvm_sigset_deactivate(struct kvm_vcpu *vcpu); diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 68ff41d39545..08f97cf97264 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -346,17 +346,20 @@ void kvm_gfn_to_pfn_cache_unmap(struct kvm *kvm, stru= ct gfn_to_pfn_cache *gpc) } EXPORT_SYMBOL_GPL(kvm_gfn_to_pfn_cache_unmap); =20 +void kvm_gpc_init(struct gfn_to_pfn_cache *gpc) +{ + rwlock_init(&gpc->lock); + mutex_init(&gpc->refresh_lock); +} +EXPORT_SYMBOL_GPL(kvm_gpc_init); =20 -int kvm_gfn_to_pfn_cache_init(struct kvm *kvm, struct gfn_to_pfn_cache *gp= c, - struct kvm_vcpu *vcpu, enum pfn_cache_usage usage, - gpa_t gpa, unsigned long len) +int kvm_gpc_activate(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, + struct kvm_vcpu *vcpu, enum pfn_cache_usage usage, + gpa_t gpa, unsigned long len) { WARN_ON_ONCE(!usage || (usage & KVM_GUEST_AND_HOST_USE_PFN) !=3D usage); =20 if (!gpc->active) { - rwlock_init(&gpc->lock); - mutex_init(&gpc->refresh_lock); - gpc->khva =3D NULL; gpc->pfn =3D KVM_PFN_ERR_FAULT; gpc->uhva =3D KVM_HVA_ERR_BAD; @@ -371,9 +374,9 @@ int kvm_gfn_to_pfn_cache_init(struct kvm *kvm, struct g= fn_to_pfn_cache *gpc, } return kvm_gfn_to_pfn_cache_refresh(kvm, gpc, gpa, len); } -EXPORT_SYMBOL_GPL(kvm_gfn_to_pfn_cache_init); +EXPORT_SYMBOL_GPL(kvm_gpc_activate); =20 -void kvm_gfn_to_pfn_cache_destroy(struct kvm *kvm, struct gfn_to_pfn_cache= *gpc) +void kvm_gpc_deactivate(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) { if (gpc->active) { spin_lock(&kvm->gpc_lock); @@ -384,4 +387,4 @@ void kvm_gfn_to_pfn_cache_destroy(struct kvm *kvm, stru= ct gfn_to_pfn_cache *gpc) gpc->active =3D false; } } -EXPORT_SYMBOL_GPL(kvm_gfn_to_pfn_cache_destroy); +EXPORT_SYMBOL_GPL(kvm_gpc_deactivate); --=20 2.31.1 From nobody Wed Apr 8 15:55:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id F302DFA3740 for ; Thu, 27 Oct 2022 16:19:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236664AbiJ0QTX (ORCPT ); Thu, 27 Oct 2022 12:19:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54322 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236542AbiJ0QSy (ORCPT ); Thu, 27 Oct 2022 12:18:54 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 70FAA1849BA for ; Thu, 27 Oct 2022 09:18:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666887532; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pAwdr8n+au2yPSsmcSNSMO7jptNZzm2/i9omRiHscEg=; b=ZDr//dKeyRUjH5WFI3LgZt5pBH9bA54e+9pV5BsxCkQzPm9Nhn4ltRAoWfgmpq+L7vXg1u XuMYv/E4y5mVUk5SSIr4wiq81rfr1znDKUCykavJke9tkFTSY70ZF93gwOu/htyAyrO7cP 602xCLBILIgOfPDinuw1XeHoFAM9NQE= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-134-2yuwjANSPrysrMyJPpDhYg-1; Thu, 27 Oct 2022 12:18:51 -0400 X-MC-Unique: 2yuwjANSPrysrMyJPpDhYg-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id A4A8885A59D; Thu, 27 Oct 2022 16:18:50 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7E19A1415117; Thu, 27 Oct 2022 16:18:50 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: mhal@rbox.co, seanjc@google.com, stable@vger.kernel.org Subject: [PATCH 02/16] KVM: Reject attempts to consume or refresh inactive gfn_to_pfn_cache Date: Thu, 27 Oct 2022 12:18:35 -0400 Message-Id: <20221027161849.2989332-3-pbonzini@redhat.com> In-Reply-To: <20221027161849.2989332-1-pbonzini@redhat.com> References: <20221027161849.2989332-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.7 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Sean Christopherson Reject kvm_gpc_check() and kvm_gpc_refresh() if the cache is inactive. Not checking the active flag during refresh is particularly egregious, as KVM can end up with a valid, inactive cache, which can lead to a variety of use-after-free bugs, e.g. consuming a NULL kernel pointer or missing an mmu_notifier invalidation due to the cache not being on the list of gfns to invalidate. Note, "active" needs to be set if and only if the cache is on the list of caches, i.e. is reachable via mmu_notifier events. If a relevant mmu_notifier event occurs while the cache is "active" but not on the list, KVM will not acquire the cache's lock and so will not serailize the mmu_notifier event with active users and/or kvm_gpc_refresh(). A race between KVM_XEN_ATTR_TYPE_SHARED_INFO and KVM_XEN_HVM_EVTCHN_SEND can be exploited to trigger the bug. 1. Deactivate shinfo cache: kvm_xen_hvm_set_attr case KVM_XEN_ATTR_TYPE_SHARED_INFO kvm_gpc_deactivate kvm_gpc_unmap gpc->valid =3D false gpc->khva =3D NULL gpc->active =3D false Result: active =3D false, valid =3D false 2. Cause cache refresh: kvm_arch_vm_ioctl case KVM_XEN_HVM_EVTCHN_SEND kvm_xen_hvm_evtchn_send kvm_xen_set_evtchn kvm_xen_set_evtchn_fast kvm_gpc_check return -EWOULDBLOCK because !gpc->valid kvm_xen_set_evtchn_fast return -EWOULDBLOCK kvm_gpc_refresh hva_to_pfn_retry gpc->valid =3D true gpc->khva =3D not NULL Result: active =3D false, valid =3D true 3. Race ioctl KVM_XEN_HVM_EVTCHN_SEND against ioctl KVM_XEN_ATTR_TYPE_SHARED_INFO: kvm_arch_vm_ioctl case KVM_XEN_HVM_EVTCHN_SEND kvm_xen_hvm_evtchn_send kvm_xen_set_evtchn kvm_xen_set_evtchn_fast read_lock gpc->lock kvm_xen_hvm_set_attr case KVM_XEN_ATTR_TYPE_SHARED_INFO mutex_lock kvm->lock kvm_xen_shared_info_init kvm_gpc_activate gpc->khva =3D NULL kvm_gpc_check [ Check passes because gpc->valid is still true, even though gpc->khva is already NULL. ] shinfo =3D gpc->khva pending_bits =3D shinfo->evtchn_pending CRASH: test_and_set_bit(..., pending_bits) Fixes: 982ed0de4753 ("KVM: Reinstate gfn_to_pfn_cache with invalidation sup= port") Cc: stable@vger.kernel.org Reported-by: : Michal Luczaj Signed-off-by: Sean Christopherson Message-Id: <20221013211234.1318131-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- virt/kvm/pfncache.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 08f97cf97264..346e47f15572 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -81,6 +81,9 @@ bool kvm_gfn_to_pfn_cache_check(struct kvm *kvm, struct g= fn_to_pfn_cache *gpc, { struct kvm_memslots *slots =3D kvm_memslots(kvm); =20 + if (!gpc->active) + return false; + if ((gpa & ~PAGE_MASK) + len > PAGE_SIZE) return false; =20 @@ -240,10 +243,11 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, str= uct gfn_to_pfn_cache *gpc, { struct kvm_memslots *slots =3D kvm_memslots(kvm); unsigned long page_offset =3D gpa & ~PAGE_MASK; - kvm_pfn_t old_pfn, new_pfn; + bool unmap_old =3D false; unsigned long old_uhva; + kvm_pfn_t old_pfn; void *old_khva; - int ret =3D 0; + int ret; =20 /* * If must fit within a single page. The 'len' argument is @@ -261,6 +265,11 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, stru= ct gfn_to_pfn_cache *gpc, =20 write_lock_irq(&gpc->lock); =20 + if (!gpc->active) { + ret =3D -EINVAL; + goto out_unlock; + } + old_pfn =3D gpc->pfn; old_khva =3D gpc->khva - offset_in_page(gpc->khva); old_uhva =3D gpc->uhva; @@ -291,6 +300,7 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struc= t gfn_to_pfn_cache *gpc, /* If the HVA\ufffd\ufffd\ufffdPFN mapping was already valid, don't unma= p it. */ old_pfn =3D KVM_PFN_ERR_FAULT; old_khva =3D NULL; + ret =3D 0; } =20 out: @@ -305,14 +315,15 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, str= uct gfn_to_pfn_cache *gpc, gpc->khva =3D NULL; } =20 - /* Snapshot the new pfn before dropping the lock! */ - new_pfn =3D gpc->pfn; + /* Detect a pfn change before dropping the lock! */ + unmap_old =3D (old_pfn !=3D gpc->pfn); =20 +out_unlock: write_unlock_irq(&gpc->lock); =20 mutex_unlock(&gpc->refresh_lock); =20 - if (old_pfn !=3D new_pfn) + if (unmap_old) gpc_unmap_khva(kvm, old_pfn, old_khva); =20 return ret; @@ -366,11 +377,19 @@ int kvm_gpc_activate(struct kvm *kvm, struct gfn_to_p= fn_cache *gpc, gpc->vcpu =3D vcpu; gpc->usage =3D usage; gpc->valid =3D false; - gpc->active =3D true; =20 spin_lock(&kvm->gpc_lock); list_add(&gpc->list, &kvm->gpc_list); spin_unlock(&kvm->gpc_lock); + + /* + * Activate the cache after adding it to the list, a concurrent + * refresh must not establish a mapping until the cache is + * reachable by mmu_notifier events. + */ + write_lock_irq(&gpc->lock); + gpc->active =3D true; + write_unlock_irq(&gpc->lock); } return kvm_gfn_to_pfn_cache_refresh(kvm, gpc, gpa, len); } @@ -379,12 +398,20 @@ EXPORT_SYMBOL_GPL(kvm_gpc_activate); void kvm_gpc_deactivate(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) { if (gpc->active) { + /* + * Deactivate the cache before removing it from the list, KVM + * must stall mmu_notifier events until all users go away, i.e. + * until gpc->lock is dropped and refresh is guaranteed to fail. + */ + write_lock_irq(&gpc->lock); + gpc->active =3D false; + write_unlock_irq(&gpc->lock); + spin_lock(&kvm->gpc_lock); list_del(&gpc->list); spin_unlock(&kvm->gpc_lock); =20 kvm_gfn_to_pfn_cache_unmap(kvm, gpc); - gpc->active =3D false; } } EXPORT_SYMBOL_GPL(kvm_gpc_deactivate); --=20 2.31.1 From nobody Wed Apr 8 15:55:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 12186FA3740 for ; Thu, 27 Oct 2022 16:19:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236649AbiJ0QTS (ORCPT ); Thu, 27 Oct 2022 12:19:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54130 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236515AbiJ0QSz (ORCPT ); Thu, 27 Oct 2022 12:18:55 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E12281958CE for ; Thu, 27 Oct 2022 09:18:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666887533; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=QUVijSFivcu94lUnkyEd2RGaEvfXWEp1CBYc7P4eIz8=; b=a/qs2mRyQQtQ1ANBA0qqgl0FQdgOVvrgGaTTTCpuU+1yMTdodQRVhOmKvhsuyvm9CzZfnH hQMrbxjn/FZlyGBUC4W/50b7ep2os+51bpL90NZ6i/pe658THEBqXNSxIi1wCyL+i0fQFi UulhIqkndc6G10S5kCG7KWXLYsZF17k= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-550-mg8LLvftPvWJXbuX6Lw-5Q-1; Thu, 27 Oct 2022 12:18:51 -0400 X-MC-Unique: mg8LLvftPvWJXbuX6Lw-5Q-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id CFC311C0896E; Thu, 27 Oct 2022 16:18:50 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id AD54E1415117; Thu, 27 Oct 2022 16:18:50 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: mhal@rbox.co, seanjc@google.com Subject: [PATCH 03/16] KVM: x86: set gfn-to-pfn cache length consistently with VM word size Date: Thu, 27 Oct 2022 12:18:36 -0400 Message-Id: <20221027161849.2989332-4-pbonzini@redhat.com> In-Reply-To: <20221027161849.2989332-1-pbonzini@redhat.com> References: <20221027161849.2989332-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.7 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" KVM unconditionally uses the "full" size of the Xen shared info page when activating the cache in kvm_xen_vcpu_set_attr(), but using the current mode matches what Xen does. While KVM did always use the 64-bit size when activating the cache, what matters is that Xen does not look beyond the size of the 32-bit struct if the vCPU was initialized in 32-bit mode. If the guest sets up the runstate info of a 32-bit VM so that the struct ends at the end of a page, the 64-bit struct size passed to kvm_gpc_activate() will cause the ioctl or hypercall to fail, because gfn-to-pfn caches can only be set up for data that fits in a single page. Nevertheless, keeping the Xen word size constant throughout the life of the gpc cache, i.e. not using a different size at check()+refresh() than at activate(), is desirable because it makes the length/size of the cache immutable. This in turn yields a cleaner set of APIs and avoids potential bugs that could occur if check() were invoked with a different size than refresh(). So, use the short size at activation time as well. This means re-activating the cache if the guest requests the hypercall page multiple times with different word sizes (this can happen when kexec-ing, for example). Signed-off-by: Paolo Bonzini --- arch/x86/kvm/xen.c | 47 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index b2be60c6efa4..512b4afa6785 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -198,6 +198,37 @@ static void kvm_xen_update_runstate(struct kvm_vcpu *v= , int state) vx->runstate_entry_time =3D now; } =20 +static inline size_t kvm_xen_runstate_info_size(struct kvm *kvm) +{ + if (IS_ENABLED(CONFIG_64BIT) && kvm->arch.xen.long_mode) + return sizeof(struct vcpu_runstate_info); + else + return sizeof(struct compat_vcpu_runstate_info); +} + +static int kvm_xen_activate_runstate_gpc(struct kvm_vcpu *vcpu, unsigned l= ong gpa) +{ + size_t user_len =3D kvm_xen_runstate_info_size(vcpu->kvm); + return kvm_gpc_activate(vcpu->kvm, &vcpu->arch.xen.runstate_cache, + NULL, KVM_HOST_USES_PFN, gpa, user_len); +} + +static int kvm_xen_reactivate_runstate_gpcs(struct kvm *kvm) +{ + struct kvm_vcpu *vcpu; + unsigned long i; + + kvm_for_each_vcpu(i, vcpu, kvm) { + if (vcpu->arch.xen.runstate_cache.active) { + int r =3D kvm_xen_activate_runstate_gpc(vcpu, + vcpu->arch.xen.runstate_cache.gpa); + if (r < 0) + return r; + } + } + return 0; +} + void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, int state) { struct kvm_vcpu_xen *vx =3D &v->arch.xen; @@ -212,11 +243,7 @@ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v,= int state) if (!vx->runstate_cache.active) return; =20 - if (IS_ENABLED(CONFIG_64BIT) && v->kvm->arch.xen.long_mode) - user_len =3D sizeof(struct vcpu_runstate_info); - else - user_len =3D sizeof(struct compat_vcpu_runstate_info); - + user_len =3D kvm_xen_runstate_info_size(v->kvm); read_lock_irqsave(&gpc->lock, flags); while (!kvm_gfn_to_pfn_cache_check(v->kvm, gpc, gpc->gpa, user_len)) { @@ -461,7 +488,7 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xe= n_hvm_attr *data) mutex_lock(&kvm->lock); kvm->arch.xen.long_mode =3D !!data->u.long_mode; mutex_unlock(&kvm->lock); - r =3D 0; + r =3D kvm_xen_reactivate_runstate_gpcs(kvm); } break; =20 @@ -596,9 +623,7 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct= kvm_xen_vcpu_attr *data) break; } =20 - r =3D kvm_gpc_activate(vcpu->kvm, &vcpu->arch.xen.runstate_cache, - NULL, KVM_HOST_USES_PFN, data->u.gpa, - sizeof(struct vcpu_runstate_info)); + r =3D kvm_xen_activate_runstate_gpc(vcpu, data->u.gpa); break; =20 case KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT: @@ -843,9 +868,13 @@ int kvm_xen_write_hypercall_page(struct kvm_vcpu *vcpu= , u64 data) u32 page_num =3D data & ~PAGE_MASK; u64 page_addr =3D data & PAGE_MASK; bool lm =3D is_long_mode(vcpu); + int r; =20 /* Latch long_mode for shared_info pages etc. */ vcpu->kvm->arch.xen.long_mode =3D lm; + r =3D kvm_xen_reactivate_runstate_gpcs(kvm); + if (r < 0) + return 1; =20 /* * If Xen hypercall intercept is enabled, fill the hypercall --=20 2.31.1 From nobody Wed Apr 8 15:55:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 53E0FFA3740 for ; Thu, 27 Oct 2022 16:20:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236544AbiJ0QUN (ORCPT ); Thu, 27 Oct 2022 12:20:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54868 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236587AbiJ0QTC (ORCPT ); Thu, 27 Oct 2022 12:19:02 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3BEEA196ED7 for ; Thu, 27 Oct 2022 09:18:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666887538; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pocYbtNwQ3MvVypXtGO80iv68zGgKlOFCP+Ib8XwyNc=; b=OAKzbBpwKMImyvh7JE2kCzxUts1LiyzDGjXlq/gm1hbiOnEH+sPz6KVS5HeoeB52RL5ZMc eYmOrSBX3huFXUgOq2yKn2UkFBHVuw0HiWlyT4ox6uZp1KtEf4bQ5+NHTywMTyW5Eg8gV4 m/ND3VWyH/F5xOmrODtdqlgQNqQ0fvQ= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-425-kQDA980AMI6vgn4Chz07YQ-1; Thu, 27 Oct 2022 12:18:52 -0400 X-MC-Unique: kQDA980AMI6vgn4Chz07YQ-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 0C43A85A5A6; Thu, 27 Oct 2022 16:18:51 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id DA00D1415117; Thu, 27 Oct 2022 16:18:50 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: mhal@rbox.co, seanjc@google.com Subject: [PATCH 04/16] KVM: Shorten gfn_to_pfn_cache function names Date: Thu, 27 Oct 2022 12:18:37 -0400 Message-Id: <20221027161849.2989332-5-pbonzini@redhat.com> In-Reply-To: <20221027161849.2989332-1-pbonzini@redhat.com> References: <20221027161849.2989332-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.7 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Michal Luczaj Formalize "gpc" as the acronym and use it in function names. No functional change intended. Suggested-by: Sean Christopherson Signed-off-by: Michal Luczaj Signed-off-by: Sean Christopherson Message-Id: <20221013211234.1318131-5-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 8 ++++---- arch/x86/kvm/xen.c | 29 ++++++++++++++--------------- include/linux/kvm_host.h | 21 ++++++++++----------- virt/kvm/pfncache.c | 20 ++++++++++---------- 4 files changed, 38 insertions(+), 40 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 521b433f978c..5e5c546cba66 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3034,12 +3034,12 @@ static void kvm_setup_guest_pvclock(struct kvm_vcpu= *v, unsigned long flags; =20 read_lock_irqsave(&gpc->lock, flags); - while (!kvm_gfn_to_pfn_cache_check(v->kvm, gpc, gpc->gpa, - offset + sizeof(*guest_hv_clock))) { + while (!kvm_gpc_check(v->kvm, gpc, gpc->gpa, + offset + sizeof(*guest_hv_clock))) { read_unlock_irqrestore(&gpc->lock, flags); =20 - if (kvm_gfn_to_pfn_cache_refresh(v->kvm, gpc, gpc->gpa, - offset + sizeof(*guest_hv_clock))) + if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa, + offset + sizeof(*guest_hv_clock))) return; =20 read_lock_irqsave(&gpc->lock, flags); diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 512b4afa6785..5ea8f82d60b1 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -245,15 +245,14 @@ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v= , int state) =20 user_len =3D kvm_xen_runstate_info_size(v->kvm); read_lock_irqsave(&gpc->lock, flags); - while (!kvm_gfn_to_pfn_cache_check(v->kvm, gpc, gpc->gpa, - user_len)) { + while (!kvm_gpc_check(v->kvm, gpc, gpc->gpa, user_len)) { read_unlock_irqrestore(&gpc->lock, flags); =20 /* When invoked from kvm_sched_out() we cannot sleep */ if (state =3D=3D RUNSTATE_runnable) return; =20 - if (kvm_gfn_to_pfn_cache_refresh(v->kvm, gpc, gpc->gpa, user_len)) + if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa, user_len)) return; =20 read_lock_irqsave(&gpc->lock, flags); @@ -379,12 +378,12 @@ void kvm_xen_inject_pending_events(struct kvm_vcpu *v) * little more honest about it. */ read_lock_irqsave(&gpc->lock, flags); - while (!kvm_gfn_to_pfn_cache_check(v->kvm, gpc, gpc->gpa, - sizeof(struct vcpu_info))) { + while (!kvm_gpc_check(v->kvm, gpc, gpc->gpa, + sizeof(struct vcpu_info))) { read_unlock_irqrestore(&gpc->lock, flags); =20 - if (kvm_gfn_to_pfn_cache_refresh(v->kvm, gpc, gpc->gpa, - sizeof(struct vcpu_info))) + if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa, + sizeof(struct vcpu_info))) return; =20 read_lock_irqsave(&gpc->lock, flags); @@ -444,8 +443,8 @@ int __kvm_xen_has_interrupt(struct kvm_vcpu *v) sizeof_field(struct compat_vcpu_info, evtchn_upcall_pending)); =20 read_lock_irqsave(&gpc->lock, flags); - while (!kvm_gfn_to_pfn_cache_check(v->kvm, gpc, gpc->gpa, - sizeof(struct vcpu_info))) { + while (!kvm_gpc_check(v->kvm, gpc, gpc->gpa, + sizeof(struct vcpu_info))) { read_unlock_irqrestore(&gpc->lock, flags); =20 /* @@ -459,8 +458,8 @@ int __kvm_xen_has_interrupt(struct kvm_vcpu *v) if (in_atomic() || !task_is_running(current)) return 1; =20 - if (kvm_gfn_to_pfn_cache_refresh(v->kvm, gpc, gpc->gpa, - sizeof(struct vcpu_info))) { + if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa, + sizeof(struct vcpu_info))) { /* * If this failed, userspace has screwed up the * vcpu_info mapping. No interrupts for you. @@ -995,7 +994,7 @@ static bool wait_pending_event(struct kvm_vcpu *vcpu, i= nt nr_ports, =20 read_lock_irqsave(&gpc->lock, flags); idx =3D srcu_read_lock(&kvm->srcu); - if (!kvm_gfn_to_pfn_cache_check(kvm, gpc, gpc->gpa, PAGE_SIZE)) + if (!kvm_gpc_check(kvm, gpc, gpc->gpa, PAGE_SIZE)) goto out_rcu; =20 ret =3D false; @@ -1386,7 +1385,7 @@ int kvm_xen_set_evtchn_fast(struct kvm_xen_evtchn *xe= , struct kvm *kvm) idx =3D srcu_read_lock(&kvm->srcu); =20 read_lock_irqsave(&gpc->lock, flags); - if (!kvm_gfn_to_pfn_cache_check(kvm, gpc, gpc->gpa, PAGE_SIZE)) + if (!kvm_gpc_check(kvm, gpc, gpc->gpa, PAGE_SIZE)) goto out_rcu; =20 if (IS_ENABLED(CONFIG_64BIT) && kvm->arch.xen.long_mode) { @@ -1420,7 +1419,7 @@ int kvm_xen_set_evtchn_fast(struct kvm_xen_evtchn *xe= , struct kvm *kvm) gpc =3D &vcpu->arch.xen.vcpu_info_cache; =20 read_lock_irqsave(&gpc->lock, flags); - if (!kvm_gfn_to_pfn_cache_check(kvm, gpc, gpc->gpa, sizeof(struct vcpu_i= nfo))) { + if (!kvm_gpc_check(kvm, gpc, gpc->gpa, sizeof(struct vcpu_info))) { /* * Could not access the vcpu_info. Set the bit in-kernel * and prod the vCPU to deliver it for itself. @@ -1518,7 +1517,7 @@ static int kvm_xen_set_evtchn(struct kvm_xen_evtchn *= xe, struct kvm *kvm) break; =20 idx =3D srcu_read_lock(&kvm->srcu); - rc =3D kvm_gfn_to_pfn_cache_refresh(kvm, gpc, gpc->gpa, PAGE_SIZE); + rc =3D kvm_gpc_refresh(kvm, gpc, gpc->gpa, PAGE_SIZE); srcu_read_unlock(&kvm->srcu, idx); } while(!rc); =20 diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 18592bdf4c1b..4dc6571c832f 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1271,16 +1271,15 @@ void kvm_gpc_init(struct gfn_to_pfn_cache *gpc); * -EFAULT for an untranslatable guest physical address. * * This primes a gfn_to_pfn_cache and links it into the @kvm's list for - * invalidations to be processed. Callers are required to use - * kvm_gfn_to_pfn_cache_check() to ensure that the cache is valid before - * accessing the target page. + * invalidations to be processed. Callers are required to use kvm_gpc_che= ck() + * to ensure that the cache is valid before accessing the target page. */ int kvm_gpc_activate(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, struct kvm_vcpu *vcpu, enum pfn_cache_usage usage, gpa_t gpa, unsigned long len); =20 /** - * kvm_gfn_to_pfn_cache_check - check validity of a gfn_to_pfn_cache. + * kvm_gpc_check - check validity of a gfn_to_pfn_cache. * * @kvm: pointer to kvm instance. * @gpc: struct gfn_to_pfn_cache object. @@ -1297,11 +1296,11 @@ int kvm_gpc_activate(struct kvm *kvm, struct gfn_to= _pfn_cache *gpc, * Callers in IN_GUEST_MODE may do so without locking, although they should * still hold a read lock on kvm->scru for the memslot checks. */ -bool kvm_gfn_to_pfn_cache_check(struct kvm *kvm, struct gfn_to_pfn_cache *= gpc, - gpa_t gpa, unsigned long len); +bool kvm_gpc_check(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpa_t gp= a, + unsigned long len); =20 /** - * kvm_gfn_to_pfn_cache_refresh - update a previously initialized cache. + * kvm_gpc_refresh - update a previously initialized cache. * * @kvm: pointer to kvm instance. * @gpc: struct gfn_to_pfn_cache object. @@ -1318,11 +1317,11 @@ bool kvm_gfn_to_pfn_cache_check(struct kvm *kvm, st= ruct gfn_to_pfn_cache *gpc, * still lock and check the cache status, as this function does not return * with the lock still held to permit access. */ -int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache = *gpc, - gpa_t gpa, unsigned long len); +int kvm_gpc_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpa_t g= pa, + unsigned long len); =20 /** - * kvm_gfn_to_pfn_cache_unmap - temporarily unmap a gfn_to_pfn_cache. + * kvm_gpc_unmap - temporarily unmap a gfn_to_pfn_cache. * * @kvm: pointer to kvm instance. * @gpc: struct gfn_to_pfn_cache object. @@ -1331,7 +1330,7 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, str= uct gfn_to_pfn_cache *gpc, * but at least the mapping from GPA to userspace HVA will remain cached * and can be reused on a subsequent refresh. */ -void kvm_gfn_to_pfn_cache_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *= gpc); +void kvm_gpc_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *gpc); =20 /** * kvm_gpc_deactivate - deactivate and unlink a gfn_to_pfn_cache. diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 346e47f15572..23180f1d9c1c 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -76,8 +76,8 @@ void gfn_to_pfn_cache_invalidate_start(struct kvm *kvm, u= nsigned long start, } } =20 -bool kvm_gfn_to_pfn_cache_check(struct kvm *kvm, struct gfn_to_pfn_cache *= gpc, - gpa_t gpa, unsigned long len) +bool kvm_gpc_check(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpa_t gp= a, + unsigned long len) { struct kvm_memslots *slots =3D kvm_memslots(kvm); =20 @@ -96,7 +96,7 @@ bool kvm_gfn_to_pfn_cache_check(struct kvm *kvm, struct g= fn_to_pfn_cache *gpc, =20 return true; } -EXPORT_SYMBOL_GPL(kvm_gfn_to_pfn_cache_check); +EXPORT_SYMBOL_GPL(kvm_gpc_check); =20 static void gpc_unmap_khva(struct kvm *kvm, kvm_pfn_t pfn, void *khva) { @@ -238,8 +238,8 @@ static kvm_pfn_t hva_to_pfn_retry(struct kvm *kvm, stru= ct gfn_to_pfn_cache *gpc) return -EFAULT; } =20 -int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache = *gpc, - gpa_t gpa, unsigned long len) +int kvm_gpc_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpa_t g= pa, + unsigned long len) { struct kvm_memslots *slots =3D kvm_memslots(kvm); unsigned long page_offset =3D gpa & ~PAGE_MASK; @@ -328,9 +328,9 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struc= t gfn_to_pfn_cache *gpc, =20 return ret; } -EXPORT_SYMBOL_GPL(kvm_gfn_to_pfn_cache_refresh); +EXPORT_SYMBOL_GPL(kvm_gpc_refresh); =20 -void kvm_gfn_to_pfn_cache_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *= gpc) +void kvm_gpc_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) { void *old_khva; kvm_pfn_t old_pfn; @@ -355,7 +355,7 @@ void kvm_gfn_to_pfn_cache_unmap(struct kvm *kvm, struct= gfn_to_pfn_cache *gpc) =20 gpc_unmap_khva(kvm, old_pfn, old_khva); } -EXPORT_SYMBOL_GPL(kvm_gfn_to_pfn_cache_unmap); +EXPORT_SYMBOL_GPL(kvm_gpc_unmap); =20 void kvm_gpc_init(struct gfn_to_pfn_cache *gpc) { @@ -391,7 +391,7 @@ int kvm_gpc_activate(struct kvm *kvm, struct gfn_to_pfn= _cache *gpc, gpc->active =3D true; write_unlock_irq(&gpc->lock); } - return kvm_gfn_to_pfn_cache_refresh(kvm, gpc, gpa, len); + return kvm_gpc_refresh(kvm, gpc, gpa, len); } EXPORT_SYMBOL_GPL(kvm_gpc_activate); =20 @@ -411,7 +411,7 @@ void kvm_gpc_deactivate(struct kvm *kvm, struct gfn_to_= pfn_cache *gpc) list_del(&gpc->list); spin_unlock(&kvm->gpc_lock); =20 - kvm_gfn_to_pfn_cache_unmap(kvm, gpc); + kvm_gpc_unmap(kvm, gpc); } } EXPORT_SYMBOL_GPL(kvm_gpc_deactivate); --=20 2.31.1 From nobody Wed Apr 8 15:55:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6FC34FA3740 for ; Thu, 27 Oct 2022 16:19:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236698AbiJ0QTg (ORCPT ); Thu, 27 Oct 2022 12:19:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54128 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236532AbiJ0QSz (ORCPT ); Thu, 27 Oct 2022 12:18:55 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AD4DC18E71B for ; Thu, 27 Oct 2022 09:18:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666887534; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sdeKLDOmzDc50wX69zF5oFbNHmj+GE1oHwYqIBezFig=; b=FJMRcqkV9EeVDQNcbqDaxEYKy1C7ghN6KzwTNdHapPg9/xAYdM+c5/VASgR+L5touXVIfN Uw4BRP7H2nmvjJQ5C1N9IrPwYeON2M/1qEMVts7qtlNh7K+zxBmOu6oNPQXikiFSwLOUry 5W1e40GUjOCNyKwpBmUtQWWcGDNvMfU= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-164-jk2I3IdsMVml6cTGwIp4ag-1; Thu, 27 Oct 2022 12:18:51 -0400 X-MC-Unique: jk2I3IdsMVml6cTGwIp4ag-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 36A8A185A7A3; Thu, 27 Oct 2022 16:18:51 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 14F131400B19; Thu, 27 Oct 2022 16:18:51 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: mhal@rbox.co, seanjc@google.com Subject: [PATCH 05/16] KVM: x86: Remove unused argument in gpc_unmap_khva() Date: Thu, 27 Oct 2022 12:18:38 -0400 Message-Id: <20221027161849.2989332-6-pbonzini@redhat.com> In-Reply-To: <20221027161849.2989332-1-pbonzini@redhat.com> References: <20221027161849.2989332-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.7 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Michal Luczaj Remove the unused @kvm argument from gpc_unmap_khva(). Signed-off-by: Michal Luczaj Signed-off-by: Sean Christopherson Message-Id: <20221013211234.1318131-6-seanjc@google.com> Signed-off-by: Paolo Bonzini --- virt/kvm/pfncache.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 23180f1d9c1c..32ccf168361b 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -98,7 +98,7 @@ bool kvm_gpc_check(struct kvm *kvm, struct gfn_to_pfn_cac= he *gpc, gpa_t gpa, } EXPORT_SYMBOL_GPL(kvm_gpc_check); =20 -static void gpc_unmap_khva(struct kvm *kvm, kvm_pfn_t pfn, void *khva) +static void gpc_unmap_khva(kvm_pfn_t pfn, void *khva) { /* Unmap the old pfn/page if it was mapped before. */ if (!is_error_noslot_pfn(pfn) && khva) { @@ -177,7 +177,7 @@ static kvm_pfn_t hva_to_pfn_retry(struct kvm *kvm, stru= ct gfn_to_pfn_cache *gpc) * the existing mapping and didn't create a new one. */ if (new_khva !=3D old_khva) - gpc_unmap_khva(kvm, new_pfn, new_khva); + gpc_unmap_khva(new_pfn, new_khva); =20 kvm_release_pfn_clean(new_pfn); =20 @@ -324,7 +324,7 @@ int kvm_gpc_refresh(struct kvm *kvm, struct gfn_to_pfn_= cache *gpc, gpa_t gpa, mutex_unlock(&gpc->refresh_lock); =20 if (unmap_old) - gpc_unmap_khva(kvm, old_pfn, old_khva); + gpc_unmap_khva(old_pfn, old_khva); =20 return ret; } @@ -353,7 +353,7 @@ void kvm_gpc_unmap(struct kvm *kvm, struct gfn_to_pfn_c= ache *gpc) write_unlock_irq(&gpc->lock); mutex_unlock(&gpc->refresh_lock); =20 - gpc_unmap_khva(kvm, old_pfn, old_khva); + gpc_unmap_khva(old_pfn, old_khva); } EXPORT_SYMBOL_GPL(kvm_gpc_unmap); =20 --=20 2.31.1 From nobody Wed Apr 8 15:55:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 57A05FA3740 for ; Thu, 27 Oct 2022 16:19:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236708AbiJ0QTk (ORCPT ); Thu, 27 Oct 2022 12:19:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54636 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236558AbiJ0QS5 (ORCPT ); Thu, 27 Oct 2022 12:18:57 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5AB16196B46 for ; Thu, 27 Oct 2022 09:18:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666887535; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=EkjjTNkRC1SrGcUT44WLfdm9dpHrtSyenxlLxXIz8CI=; b=LZzq5OqaSa/H5Lgw0NRvIyX74vihtdeO9gytEu91YbKKsu9O3uBUuK1k0W15ptNWZKlxR2 CZZpziZlaco831SbAKSO2pOB8xt5R6IpTDA/9728UN8i0vjkkMU4n49Hf70U9GdH+Md0pp pVCoNAEBb3jnHeXIONzkBY+YZd/Gv+A= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-377-TMIBKSFLO16KMYNE8nTx_w-1; Thu, 27 Oct 2022 12:18:52 -0400 X-MC-Unique: TMIBKSFLO16KMYNE8nTx_w-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 685BE800B30; Thu, 27 Oct 2022 16:18:51 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 417051415137; Thu, 27 Oct 2022 16:18:51 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: mhal@rbox.co, seanjc@google.com Subject: [PATCH 06/16] KVM: Store immutable gfn_to_pfn_cache properties Date: Thu, 27 Oct 2022 12:18:39 -0400 Message-Id: <20221027161849.2989332-7-pbonzini@redhat.com> In-Reply-To: <20221027161849.2989332-1-pbonzini@redhat.com> References: <20221027161849.2989332-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.7 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Michal Luczaj Move the assignment of immutable properties @kvm, @vcpu, and @usage to the initializer. Make _activate() and _deactivate() use stored values. Note, @len is also effectively immutable, but less obviously so. Leave @len as is for now, it will be addressed in a future patch. Suggested-by: Sean Christopherson Signed-off-by: Michal Luczaj [sean: handle @len in a separate patch] Signed-off-by: Sean Christopherson Message-Id: <20221013211234.1318131-7-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 14 +++++------- arch/x86/kvm/xen.c | 46 ++++++++++++++++++--------------------- include/linux/kvm_host.h | 37 +++++++++++++++---------------- include/linux/kvm_types.h | 1 + virt/kvm/pfncache.c | 22 ++++++++++++------- 5 files changed, 60 insertions(+), 60 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 5e5c546cba66..44e1330c9dfd 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2314,13 +2314,11 @@ static void kvm_write_system_time(struct kvm_vcpu *= vcpu, gpa_t system_time, kvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu); =20 /* we verify if the enable bit is set... */ - if (system_time & 1) { - kvm_gpc_activate(vcpu->kvm, &vcpu->arch.pv_time, vcpu, - KVM_HOST_USES_PFN, system_time & ~1ULL, + if (system_time & 1) + kvm_gpc_activate(&vcpu->arch.pv_time, system_time & ~1ULL, sizeof(struct pvclock_vcpu_time_info)); - } else { - kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.pv_time); - } + else + kvm_gpc_deactivate(&vcpu->arch.pv_time); =20 return; } @@ -3388,7 +3386,7 @@ static int kvm_pv_enable_async_pf_int(struct kvm_vcpu= *vcpu, u64 data) =20 static void kvmclock_reset(struct kvm_vcpu *vcpu) { - kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.pv_time); + kvm_gpc_deactivate(&vcpu->arch.pv_time); vcpu->arch.time =3D 0; } =20 @@ -11829,7 +11827,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) vcpu->arch.regs_avail =3D ~0; vcpu->arch.regs_dirty =3D ~0; =20 - kvm_gpc_init(&vcpu->arch.pv_time); + kvm_gpc_init(&vcpu->arch.pv_time, vcpu->kvm, vcpu, KVM_HOST_USES_PFN); =20 if (!irqchip_in_kernel(vcpu->kvm) || kvm_vcpu_is_reset_bsp(vcpu)) vcpu->arch.mp_state =3D KVM_MP_STATE_RUNNABLE; diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 5ea8f82d60b1..2d597d47b817 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -42,13 +42,12 @@ static int kvm_xen_shared_info_init(struct kvm *kvm, gf= n_t gfn) int idx =3D srcu_read_lock(&kvm->srcu); =20 if (gfn =3D=3D GPA_INVALID) { - kvm_gpc_deactivate(kvm, gpc); + kvm_gpc_deactivate(gpc); goto out; } =20 do { - ret =3D kvm_gpc_activate(kvm, gpc, NULL, KVM_HOST_USES_PFN, gpa, - PAGE_SIZE); + ret =3D kvm_gpc_activate(gpc, gpa, PAGE_SIZE); if (ret) goto out; =20 @@ -209,8 +208,7 @@ static inline size_t kvm_xen_runstate_info_size(struct = kvm *kvm) static int kvm_xen_activate_runstate_gpc(struct kvm_vcpu *vcpu, unsigned l= ong gpa) { size_t user_len =3D kvm_xen_runstate_info_size(vcpu->kvm); - return kvm_gpc_activate(vcpu->kvm, &vcpu->arch.xen.runstate_cache, - NULL, KVM_HOST_USES_PFN, gpa, user_len); + return kvm_gpc_activate(&vcpu->arch.xen.runstate_cache, gpa, user_len); } =20 static int kvm_xen_reactivate_runstate_gpcs(struct kvm *kvm) @@ -580,15 +578,13 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, stru= ct kvm_xen_vcpu_attr *data) offsetof(struct compat_vcpu_info, time)); =20 if (data->u.gpa =3D=3D GPA_INVALID) { - kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.xen.vcpu_info_cache); + kvm_gpc_deactivate(&vcpu->arch.xen.vcpu_info_cache); r =3D 0; break; } =20 - r =3D kvm_gpc_activate(vcpu->kvm, - &vcpu->arch.xen.vcpu_info_cache, NULL, - KVM_HOST_USES_PFN, data->u.gpa, - sizeof(struct vcpu_info)); + r =3D kvm_gpc_activate(&vcpu->arch.xen.vcpu_info_cache, + data->u.gpa, sizeof(struct vcpu_info)); if (!r) kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); =20 @@ -596,15 +592,13 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, stru= ct kvm_xen_vcpu_attr *data) =20 case KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO: if (data->u.gpa =3D=3D GPA_INVALID) { - kvm_gpc_deactivate(vcpu->kvm, - &vcpu->arch.xen.vcpu_time_info_cache); + kvm_gpc_deactivate(&vcpu->arch.xen.vcpu_time_info_cache); r =3D 0; break; } =20 - r =3D kvm_gpc_activate(vcpu->kvm, - &vcpu->arch.xen.vcpu_time_info_cache, - NULL, KVM_HOST_USES_PFN, data->u.gpa, + r =3D kvm_gpc_activate(&vcpu->arch.xen.vcpu_time_info_cache, + data->u.gpa, sizeof(struct pvclock_vcpu_time_info)); if (!r) kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); @@ -616,8 +610,7 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct= kvm_xen_vcpu_attr *data) break; } if (data->u.gpa =3D=3D GPA_INVALID) { - kvm_gpc_deactivate(vcpu->kvm, - &vcpu->arch.xen.runstate_cache); + kvm_gpc_deactivate(&vcpu->arch.xen.runstate_cache); r =3D 0; break; } @@ -1846,9 +1839,12 @@ void kvm_xen_init_vcpu(struct kvm_vcpu *vcpu) =20 timer_setup(&vcpu->arch.xen.poll_timer, cancel_evtchn_poll, 0); =20 - kvm_gpc_init(&vcpu->arch.xen.runstate_cache); - kvm_gpc_init(&vcpu->arch.xen.vcpu_info_cache); - kvm_gpc_init(&vcpu->arch.xen.vcpu_time_info_cache); + kvm_gpc_init(&vcpu->arch.xen.runstate_cache, vcpu->kvm, NULL, + KVM_HOST_USES_PFN); + kvm_gpc_init(&vcpu->arch.xen.vcpu_info_cache, vcpu->kvm, NULL, + KVM_HOST_USES_PFN); + kvm_gpc_init(&vcpu->arch.xen.vcpu_time_info_cache, vcpu->kvm, NULL, + KVM_HOST_USES_PFN); } =20 void kvm_xen_destroy_vcpu(struct kvm_vcpu *vcpu) @@ -1856,9 +1852,9 @@ void kvm_xen_destroy_vcpu(struct kvm_vcpu *vcpu) if (kvm_xen_timer_enabled(vcpu)) kvm_xen_stop_timer(vcpu); =20 - kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.xen.runstate_cache); - kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.xen.vcpu_info_cache); - kvm_gpc_deactivate(vcpu->kvm, &vcpu->arch.xen.vcpu_time_info_cache); + kvm_gpc_deactivate(&vcpu->arch.xen.runstate_cache); + kvm_gpc_deactivate(&vcpu->arch.xen.vcpu_info_cache); + kvm_gpc_deactivate(&vcpu->arch.xen.vcpu_time_info_cache); =20 del_timer_sync(&vcpu->arch.xen.poll_timer); } @@ -1866,7 +1862,7 @@ void kvm_xen_destroy_vcpu(struct kvm_vcpu *vcpu) void kvm_xen_init_vm(struct kvm *kvm) { idr_init(&kvm->arch.xen.evtchn_ports); - kvm_gpc_init(&kvm->arch.xen.shinfo_cache); + kvm_gpc_init(&kvm->arch.xen.shinfo_cache, kvm, NULL, KVM_HOST_USES_PFN); } =20 void kvm_xen_destroy_vm(struct kvm *kvm) @@ -1874,7 +1870,7 @@ void kvm_xen_destroy_vm(struct kvm *kvm) struct evtchnfd *evtchnfd; int i; =20 - kvm_gpc_deactivate(kvm, &kvm->arch.xen.shinfo_cache); + kvm_gpc_deactivate(&kvm->arch.xen.shinfo_cache); =20 idr_for_each_entry(&kvm->arch.xen.evtchn_ports, evtchnfd, i) { if (!evtchnfd->deliver.port.port) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 4dc6571c832f..7a913818ba3c 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1243,18 +1243,7 @@ void kvm_vcpu_mark_page_dirty(struct kvm_vcpu *vcpu,= gfn_t gfn); * kvm_gpc_init - initialize gfn_to_pfn_cache. * * @gpc: struct gfn_to_pfn_cache object. - * - * This sets up a gfn_to_pfn_cache by initializing locks. Note, the cache= must - * be zero-allocated (or zeroed by the caller before init). - */ -void kvm_gpc_init(struct gfn_to_pfn_cache *gpc); - -/** - * kvm_gpc_activate - prepare a cached kernel mapping and HPA for a given = guest - * physical address. - * * @kvm: pointer to kvm instance. - * @gpc: struct gfn_to_pfn_cache object. * @vcpu: vCPU to be used for marking pages dirty and to be woken on * invalidation. * @usage: indicates if the resulting host physical PFN is used while @@ -1263,20 +1252,31 @@ void kvm_gpc_init(struct gfn_to_pfn_cache *gpc); * changes!---will also force @vcpu to exit the guest and * refresh the cache); and/or if the PFN used directly * by KVM (and thus needs a kernel virtual mapping). + * + * This sets up a gfn_to_pfn_cache by initializing locks and assigning the + * immutable attributes. Note, the cache must be zero-allocated (or zeroe= d by + * the caller before init). + */ +void kvm_gpc_init(struct gfn_to_pfn_cache *gpc, struct kvm *kvm, + struct kvm_vcpu *vcpu, enum pfn_cache_usage usage); + +/** + * kvm_gpc_activate - prepare a cached kernel mapping and HPA for a given = guest + * physical address. + * + * @gpc: struct gfn_to_pfn_cache object. * @gpa: guest physical address to map. * @len: sanity check; the range being access must fit a single page. * * @return: 0 for success. * -EINVAL for a mapping which would cross a page boundary. - * -EFAULT for an untranslatable guest physical address. + * -EFAULT for an untranslatable guest physical address. * - * This primes a gfn_to_pfn_cache and links it into the @kvm's list for + * This primes a gfn_to_pfn_cache and links it into the @gpc->kvm's list f= or * invalidations to be processed. Callers are required to use kvm_gpc_che= ck() * to ensure that the cache is valid before accessing the target page. */ -int kvm_gpc_activate(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, - struct kvm_vcpu *vcpu, enum pfn_cache_usage usage, - gpa_t gpa, unsigned long len); +int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned lon= g len); =20 /** * kvm_gpc_check - check validity of a gfn_to_pfn_cache. @@ -1335,13 +1335,12 @@ void kvm_gpc_unmap(struct kvm *kvm, struct gfn_to_p= fn_cache *gpc); /** * kvm_gpc_deactivate - deactivate and unlink a gfn_to_pfn_cache. * - * @kvm: pointer to kvm instance. * @gpc: struct gfn_to_pfn_cache object. * - * This removes a cache from the @kvm's list to be processed on MMU notifi= er + * This removes a cache from the VM's list to be processed on MMU notifier * invocation. */ -void kvm_gpc_deactivate(struct kvm *kvm, struct gfn_to_pfn_cache *gpc); +void kvm_gpc_deactivate(struct gfn_to_pfn_cache *gpc); =20 void kvm_sigset_activate(struct kvm_vcpu *vcpu); void kvm_sigset_deactivate(struct kvm_vcpu *vcpu); diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h index 3ca3db020e0e..76de36e56cdf 100644 --- a/include/linux/kvm_types.h +++ b/include/linux/kvm_types.h @@ -67,6 +67,7 @@ struct gfn_to_pfn_cache { gpa_t gpa; unsigned long uhva; struct kvm_memory_slot *memslot; + struct kvm *kvm; struct kvm_vcpu *vcpu; struct list_head list; rwlock_t lock; diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 32ccf168361b..6756dfa60d5a 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -357,25 +357,29 @@ void kvm_gpc_unmap(struct kvm *kvm, struct gfn_to_pfn= _cache *gpc) } EXPORT_SYMBOL_GPL(kvm_gpc_unmap); =20 -void kvm_gpc_init(struct gfn_to_pfn_cache *gpc) +void kvm_gpc_init(struct gfn_to_pfn_cache *gpc, struct kvm *kvm, + struct kvm_vcpu *vcpu, enum pfn_cache_usage usage) { + WARN_ON_ONCE(!usage || (usage & KVM_GUEST_AND_HOST_USE_PFN) !=3D usage); + WARN_ON_ONCE((usage & KVM_GUEST_USES_PFN) && !vcpu); + rwlock_init(&gpc->lock); mutex_init(&gpc->refresh_lock); + + gpc->kvm =3D kvm; + gpc->vcpu =3D vcpu; + gpc->usage =3D usage; } EXPORT_SYMBOL_GPL(kvm_gpc_init); =20 -int kvm_gpc_activate(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, - struct kvm_vcpu *vcpu, enum pfn_cache_usage usage, - gpa_t gpa, unsigned long len) +int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsigned lon= g len) { - WARN_ON_ONCE(!usage || (usage & KVM_GUEST_AND_HOST_USE_PFN) !=3D usage); + struct kvm *kvm =3D gpc->kvm; =20 if (!gpc->active) { gpc->khva =3D NULL; gpc->pfn =3D KVM_PFN_ERR_FAULT; gpc->uhva =3D KVM_HVA_ERR_BAD; - gpc->vcpu =3D vcpu; - gpc->usage =3D usage; gpc->valid =3D false; =20 spin_lock(&kvm->gpc_lock); @@ -395,8 +399,10 @@ int kvm_gpc_activate(struct kvm *kvm, struct gfn_to_pf= n_cache *gpc, } EXPORT_SYMBOL_GPL(kvm_gpc_activate); =20 -void kvm_gpc_deactivate(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) +void kvm_gpc_deactivate(struct gfn_to_pfn_cache *gpc) { + struct kvm *kvm =3D gpc->kvm; + if (gpc->active) { /* * Deactivate the cache before removing it from the list, KVM --=20 2.31.1 From nobody Wed Apr 8 15:55:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E3A3BFA3741 for ; Thu, 27 Oct 2022 16:19:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236717AbiJ0QTn (ORCPT ); Thu, 27 Oct 2022 12:19:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54634 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236557AbiJ0QS5 (ORCPT ); Thu, 27 Oct 2022 12:18:57 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3A0B818F0CE for ; Thu, 27 Oct 2022 09:18:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666887535; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ucOT7iWRGadjrZPI9J/+ZpDTpnC7BK320XZ/Fl3Gc8o=; b=DyZEa/Y9u4gGtWiRuaN0UifVHBGiEgl9dPexVG4C1oYf2LxfIVtSQNbKTKH1A+qunIedlW eMc8Uj/jKjCNsO44WUbOY2pX+Gm+Jf293IphasO9BNLwiAjqbDPwswfuRNxkBGWgjxMApw a4VjYDvaU8/cnFytsEdbdwK0/TcGaLY= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-7-4IOqO1-GN-ybaIeqSRHVQA-1; Thu, 27 Oct 2022 12:18:52 -0400 X-MC-Unique: 4IOqO1-GN-ybaIeqSRHVQA-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 98AC5185A794; Thu, 27 Oct 2022 16:18:51 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 729051415117; Thu, 27 Oct 2022 16:18:51 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: mhal@rbox.co, seanjc@google.com Subject: [PATCH 07/16] KVM: Store gfn_to_pfn_cache length at activation time Date: Thu, 27 Oct 2022 12:18:40 -0400 Message-Id: <20221027161849.2989332-8-pbonzini@redhat.com> In-Reply-To: <20221027161849.2989332-1-pbonzini@redhat.com> References: <20221027161849.2989332-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.7 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Make the length of a gfn=3D>pfn cache constant between activation and deactivation to cleanup the APIs and avoid potential bugs, e.g calling check() with a larger size than refresh() could put KVM into an infinite loop. All current (and anticipated future) users access the cache with a predetermined size, which isn't a coincidence as using a dedicated cache really only make sense when the access pattern is "fixed". However, the size can change from one activation to another, so pull that setup outside the "if (!gpc->active)" conditional. Add a WARN in kvm_setup_guest_pvclock() to assert that the offset+size matches the length of the cache, both to make it more obvious that the length really is immutable in that case, and to detect future bugs. In kvm_xen_update_runstate_guest(), instead, the new field avoids guest shenanigans involving the VM's long mode setting and makes sure that the format of the data is consistent with the one that was used when setting up the cache. No functional change intended. Signed-off-by: Michal Luczaj Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson Co-developed-by: Paolo Bonzini Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 8 ++++---- arch/x86/kvm/xen.c | 28 +++++++++++----------------- include/linux/kvm_host.h | 7 ++----- include/linux/kvm_types.h | 1 + virt/kvm/pfncache.c | 18 ++++++++++++------ 5 files changed, 30 insertions(+), 32 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 44e1330c9dfd..9380fd9e1cf0 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3031,13 +3031,13 @@ static void kvm_setup_guest_pvclock(struct kvm_vcpu= *v, struct pvclock_vcpu_time_info *guest_hv_clock; unsigned long flags; =20 + WARN_ON_ONCE(gpc->len !=3D offset + sizeof(*guest_hv_clock)); + read_lock_irqsave(&gpc->lock, flags); - while (!kvm_gpc_check(v->kvm, gpc, gpc->gpa, - offset + sizeof(*guest_hv_clock))) { + while (!kvm_gpc_check(v->kvm, gpc, gpc->gpa)) { read_unlock_irqrestore(&gpc->lock, flags); =20 - if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa, - offset + sizeof(*guest_hv_clock))) + if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa)) return; =20 read_lock_irqsave(&gpc->lock, flags); diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 2d597d47b817..26c8a8dc2737 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -233,7 +233,6 @@ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, = int state) struct gfn_to_pfn_cache *gpc =3D &vx->runstate_cache; uint64_t *user_times; unsigned long flags; - size_t user_len; int *user_state; =20 kvm_xen_update_runstate(v, state); @@ -241,16 +240,15 @@ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v= , int state) if (!vx->runstate_cache.active) return; =20 - user_len =3D kvm_xen_runstate_info_size(v->kvm); read_lock_irqsave(&gpc->lock, flags); - while (!kvm_gpc_check(v->kvm, gpc, gpc->gpa, user_len)) { + while (!kvm_gpc_check(v->kvm, gpc, gpc->gpa)) { read_unlock_irqrestore(&gpc->lock, flags); =20 /* When invoked from kvm_sched_out() we cannot sleep */ if (state =3D=3D RUNSTATE_runnable) return; =20 - if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa, user_len)) + if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa)) return; =20 read_lock_irqsave(&gpc->lock, flags); @@ -278,7 +276,7 @@ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, = int state) =20 user_state =3D gpc->khva; =20 - if (IS_ENABLED(CONFIG_64BIT) && v->kvm->arch.xen.long_mode) + if (gpc->len =3D=3D sizeof(struct vcpu_runstate_info)) user_times =3D gpc->khva + offsetof(struct vcpu_runstate_info, state_entry_time); else @@ -376,12 +374,10 @@ void kvm_xen_inject_pending_events(struct kvm_vcpu *v) * little more honest about it. */ read_lock_irqsave(&gpc->lock, flags); - while (!kvm_gpc_check(v->kvm, gpc, gpc->gpa, - sizeof(struct vcpu_info))) { + while (!kvm_gpc_check(v->kvm, gpc, gpc->gpa)) { read_unlock_irqrestore(&gpc->lock, flags); =20 - if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa, - sizeof(struct vcpu_info))) + if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa)) return; =20 read_lock_irqsave(&gpc->lock, flags); @@ -441,8 +437,7 @@ int __kvm_xen_has_interrupt(struct kvm_vcpu *v) sizeof_field(struct compat_vcpu_info, evtchn_upcall_pending)); =20 read_lock_irqsave(&gpc->lock, flags); - while (!kvm_gpc_check(v->kvm, gpc, gpc->gpa, - sizeof(struct vcpu_info))) { + while (!kvm_gpc_check(v->kvm, gpc, gpc->gpa)) { read_unlock_irqrestore(&gpc->lock, flags); =20 /* @@ -456,8 +451,7 @@ int __kvm_xen_has_interrupt(struct kvm_vcpu *v) if (in_atomic() || !task_is_running(current)) return 1; =20 - if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa, - sizeof(struct vcpu_info))) { + if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa)) { /* * If this failed, userspace has screwed up the * vcpu_info mapping. No interrupts for you. @@ -987,7 +981,7 @@ static bool wait_pending_event(struct kvm_vcpu *vcpu, i= nt nr_ports, =20 read_lock_irqsave(&gpc->lock, flags); idx =3D srcu_read_lock(&kvm->srcu); - if (!kvm_gpc_check(kvm, gpc, gpc->gpa, PAGE_SIZE)) + if (!kvm_gpc_check(kvm, gpc, gpc->gpa)) goto out_rcu; =20 ret =3D false; @@ -1378,7 +1372,7 @@ int kvm_xen_set_evtchn_fast(struct kvm_xen_evtchn *xe= , struct kvm *kvm) idx =3D srcu_read_lock(&kvm->srcu); =20 read_lock_irqsave(&gpc->lock, flags); - if (!kvm_gpc_check(kvm, gpc, gpc->gpa, PAGE_SIZE)) + if (!kvm_gpc_check(kvm, gpc, gpc->gpa)) goto out_rcu; =20 if (IS_ENABLED(CONFIG_64BIT) && kvm->arch.xen.long_mode) { @@ -1412,7 +1406,7 @@ int kvm_xen_set_evtchn_fast(struct kvm_xen_evtchn *xe= , struct kvm *kvm) gpc =3D &vcpu->arch.xen.vcpu_info_cache; =20 read_lock_irqsave(&gpc->lock, flags); - if (!kvm_gpc_check(kvm, gpc, gpc->gpa, sizeof(struct vcpu_info))) { + if (!kvm_gpc_check(kvm, gpc, gpc->gpa)) { /* * Could not access the vcpu_info. Set the bit in-kernel * and prod the vCPU to deliver it for itself. @@ -1510,7 +1504,7 @@ static int kvm_xen_set_evtchn(struct kvm_xen_evtchn *= xe, struct kvm *kvm) break; =20 idx =3D srcu_read_lock(&kvm->srcu); - rc =3D kvm_gpc_refresh(kvm, gpc, gpc->gpa, PAGE_SIZE); + rc =3D kvm_gpc_refresh(kvm, gpc, gpc->gpa); srcu_read_unlock(&kvm->srcu, idx); } while(!rc); =20 diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 7a913818ba3c..931775e92f85 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1284,7 +1284,6 @@ int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gp= a_t gpa, unsigned long len) * @kvm: pointer to kvm instance. * @gpc: struct gfn_to_pfn_cache object. * @gpa: current guest physical address to map. - * @len: sanity check; the range being access must fit a single page. * * @return: %true if the cache is still valid and the address matches. * %false if the cache is not valid. @@ -1296,8 +1295,7 @@ int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gp= a_t gpa, unsigned long len) * Callers in IN_GUEST_MODE may do so without locking, although they should * still hold a read lock on kvm->scru for the memslot checks. */ -bool kvm_gpc_check(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpa_t gp= a, - unsigned long len); +bool kvm_gpc_check(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpa_t gp= a); =20 /** * kvm_gpc_refresh - update a previously initialized cache. @@ -1317,8 +1315,7 @@ bool kvm_gpc_check(struct kvm *kvm, struct gfn_to_pfn= _cache *gpc, gpa_t gpa, * still lock and check the cache status, as this function does not return * with the lock still held to permit access. */ -int kvm_gpc_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpa_t g= pa, - unsigned long len); +int kvm_gpc_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpa_t g= pa); =20 /** * kvm_gpc_unmap - temporarily unmap a gfn_to_pfn_cache. diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h index 76de36e56cdf..d66b276d29e0 100644 --- a/include/linux/kvm_types.h +++ b/include/linux/kvm_types.h @@ -74,6 +74,7 @@ struct gfn_to_pfn_cache { struct mutex refresh_lock; void *khva; kvm_pfn_t pfn; + unsigned long len; enum pfn_cache_usage usage; bool active; bool valid; diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 6756dfa60d5a..96008b69d48c 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -76,15 +76,14 @@ void gfn_to_pfn_cache_invalidate_start(struct kvm *kvm,= unsigned long start, } } =20 -bool kvm_gpc_check(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpa_t gp= a, - unsigned long len) +bool kvm_gpc_check(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpa_t gp= a) { struct kvm_memslots *slots =3D kvm_memslots(kvm); =20 if (!gpc->active) return false; =20 - if ((gpa & ~PAGE_MASK) + len > PAGE_SIZE) + if ((gpa & ~PAGE_MASK) + gpc->len > PAGE_SIZE) return false; =20 if (gpc->gpa !=3D gpa || gpc->generation !=3D slots->generation || @@ -238,8 +237,8 @@ static kvm_pfn_t hva_to_pfn_retry(struct kvm *kvm, stru= ct gfn_to_pfn_cache *gpc) return -EFAULT; } =20 -int kvm_gpc_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpa_t g= pa, - unsigned long len) +static int __kvm_gpc_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc= , gpa_t gpa, + unsigned long len) { struct kvm_memslots *slots =3D kvm_memslots(kvm); unsigned long page_offset =3D gpa & ~PAGE_MASK; @@ -270,6 +269,8 @@ int kvm_gpc_refresh(struct kvm *kvm, struct gfn_to_pfn_= cache *gpc, gpa_t gpa, goto out_unlock; } =20 + gpc->len =3D len; + old_pfn =3D gpc->pfn; old_khva =3D gpc->khva - offset_in_page(gpc->khva); old_uhva =3D gpc->uhva; @@ -328,6 +329,11 @@ int kvm_gpc_refresh(struct kvm *kvm, struct gfn_to_pfn= _cache *gpc, gpa_t gpa, =20 return ret; } + +int kvm_gpc_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpa_t g= pa) +{ + return __kvm_gpc_refresh(kvm, gpc, gpa, gpc->len); +} EXPORT_SYMBOL_GPL(kvm_gpc_refresh); =20 void kvm_gpc_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) @@ -395,7 +401,7 @@ int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gpa_= t gpa, unsigned long len) gpc->active =3D true; write_unlock_irq(&gpc->lock); } - return kvm_gpc_refresh(kvm, gpc, gpa, len); + return __kvm_gpc_refresh(kvm, gpc, gpa, len); } EXPORT_SYMBOL_GPL(kvm_gpc_activate); =20 --=20 2.31.1 From nobody Wed Apr 8 15:55:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 69851FA3741 for ; Thu, 27 Oct 2022 16:19:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236731AbiJ0QTy (ORCPT ); Thu, 27 Oct 2022 12:19:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54838 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236576AbiJ0QTB (ORCPT ); Thu, 27 Oct 2022 12:19:01 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 847AC196B7E for ; Thu, 27 Oct 2022 09:18:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666887536; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=c8dxvWw7cc00qYC3G7D2Ly6NMtjgd9FL+mjGaKcWOw4=; b=byPkmMl5734XXj5w/Re/f7Y5VRRGQLhI4nCmFY2hatCJePn4lrHdb/cHn5TW0LXpHcvWKJ B7FxE373C+7HkAaLPZxNj00vnLAsBx/RWUCtxv29/iUVerLPS16i7iXH99yayRktp3IcBm IxGkvRSy8/8aVP061pqfN+qZiHMF+Fs= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-457-5dryEaD3NAeEPOlTCwg0bg-1; Thu, 27 Oct 2022 12:18:52 -0400 X-MC-Unique: 5dryEaD3NAeEPOlTCwg0bg-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id C3CB1185A78B; Thu, 27 Oct 2022 16:18:51 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id A20481415117; Thu, 27 Oct 2022 16:18:51 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: mhal@rbox.co, seanjc@google.com Subject: [PATCH 08/16] KVM: Use gfn_to_pfn_cache's immutable "kvm" in kvm_gpc_check() Date: Thu, 27 Oct 2022 12:18:41 -0400 Message-Id: <20221027161849.2989332-9-pbonzini@redhat.com> In-Reply-To: <20221027161849.2989332-1-pbonzini@redhat.com> References: <20221027161849.2989332-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.7 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Michal Luczaj Make kvm_gpc_check() use kvm instance cached in gfn_to_pfn_cache. Suggested-by: Sean Christopherson Signed-off-by: Michal Luczaj Signed-off-by: Sean Christopherson Message-Id: <20221013211234.1318131-9-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 2 +- arch/x86/kvm/xen.c | 12 ++++++------ include/linux/kvm_host.h | 3 +-- virt/kvm/pfncache.c | 4 ++-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 9380fd9e1cf0..0e3546aa34dd 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3034,7 +3034,7 @@ static void kvm_setup_guest_pvclock(struct kvm_vcpu *= v, WARN_ON_ONCE(gpc->len !=3D offset + sizeof(*guest_hv_clock)); =20 read_lock_irqsave(&gpc->lock, flags); - while (!kvm_gpc_check(v->kvm, gpc, gpc->gpa)) { + while (!kvm_gpc_check(gpc, gpc->gpa)) { read_unlock_irqrestore(&gpc->lock, flags); =20 if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa)) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 26c8a8dc2737..d3cb28388e3c 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -241,7 +241,7 @@ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, = int state) return; =20 read_lock_irqsave(&gpc->lock, flags); - while (!kvm_gpc_check(v->kvm, gpc, gpc->gpa)) { + while (!kvm_gpc_check(gpc, gpc->gpa)) { read_unlock_irqrestore(&gpc->lock, flags); =20 /* When invoked from kvm_sched_out() we cannot sleep */ @@ -374,7 +374,7 @@ void kvm_xen_inject_pending_events(struct kvm_vcpu *v) * little more honest about it. */ read_lock_irqsave(&gpc->lock, flags); - while (!kvm_gpc_check(v->kvm, gpc, gpc->gpa)) { + while (!kvm_gpc_check(gpc, gpc->gpa)) { read_unlock_irqrestore(&gpc->lock, flags); =20 if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa)) @@ -437,7 +437,7 @@ int __kvm_xen_has_interrupt(struct kvm_vcpu *v) sizeof_field(struct compat_vcpu_info, evtchn_upcall_pending)); =20 read_lock_irqsave(&gpc->lock, flags); - while (!kvm_gpc_check(v->kvm, gpc, gpc->gpa)) { + while (!kvm_gpc_check(gpc, gpc->gpa)) { read_unlock_irqrestore(&gpc->lock, flags); =20 /* @@ -981,7 +981,7 @@ static bool wait_pending_event(struct kvm_vcpu *vcpu, i= nt nr_ports, =20 read_lock_irqsave(&gpc->lock, flags); idx =3D srcu_read_lock(&kvm->srcu); - if (!kvm_gpc_check(kvm, gpc, gpc->gpa)) + if (!kvm_gpc_check(gpc, gpc->gpa)) goto out_rcu; =20 ret =3D false; @@ -1372,7 +1372,7 @@ int kvm_xen_set_evtchn_fast(struct kvm_xen_evtchn *xe= , struct kvm *kvm) idx =3D srcu_read_lock(&kvm->srcu); =20 read_lock_irqsave(&gpc->lock, flags); - if (!kvm_gpc_check(kvm, gpc, gpc->gpa)) + if (!kvm_gpc_check(gpc, gpc->gpa)) goto out_rcu; =20 if (IS_ENABLED(CONFIG_64BIT) && kvm->arch.xen.long_mode) { @@ -1406,7 +1406,7 @@ int kvm_xen_set_evtchn_fast(struct kvm_xen_evtchn *xe= , struct kvm *kvm) gpc =3D &vcpu->arch.xen.vcpu_info_cache; =20 read_lock_irqsave(&gpc->lock, flags); - if (!kvm_gpc_check(kvm, gpc, gpc->gpa)) { + if (!kvm_gpc_check(gpc, gpc->gpa)) { /* * Could not access the vcpu_info. Set the bit in-kernel * and prod the vCPU to deliver it for itself. diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 931775e92f85..466988b8b5f6 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1281,7 +1281,6 @@ int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gp= a_t gpa, unsigned long len) /** * kvm_gpc_check - check validity of a gfn_to_pfn_cache. * - * @kvm: pointer to kvm instance. * @gpc: struct gfn_to_pfn_cache object. * @gpa: current guest physical address to map. * @@ -1295,7 +1294,7 @@ int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gp= a_t gpa, unsigned long len) * Callers in IN_GUEST_MODE may do so without locking, although they should * still hold a read lock on kvm->scru for the memslot checks. */ -bool kvm_gpc_check(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpa_t gp= a); +bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc, gpa_t gpa); =20 /** * kvm_gpc_refresh - update a previously initialized cache. diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 96008b69d48c..dfcf883ca298 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -76,9 +76,9 @@ void gfn_to_pfn_cache_invalidate_start(struct kvm *kvm, u= nsigned long start, } } =20 -bool kvm_gpc_check(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpa_t gp= a) +bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc, gpa_t gpa) { - struct kvm_memslots *slots =3D kvm_memslots(kvm); + struct kvm_memslots *slots =3D kvm_memslots(gpc->kvm); =20 if (!gpc->active) return false; --=20 2.31.1 From nobody Wed Apr 8 15:55:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B8AC1ECAAA1 for ; Thu, 27 Oct 2022 16:19:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236726AbiJ0QTv (ORCPT ); Thu, 27 Oct 2022 12:19:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54284 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236569AbiJ0QTB (ORCPT ); Thu, 27 Oct 2022 12:19:01 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 103D8196B5F for ; Thu, 27 Oct 2022 09:18:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666887536; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nHpsDXiz+aHYtK+0lAoWeHJtx3zrlQWx8bxkmWSYZoI=; b=gQa8San15Dl5oT1qq0O+g5yCgwqcyJpdMtjQ+KTCThHzXFaLDQlqktmP/QRX6tp7MWr9If j8IPnZOS63Q5nGwWZaLdPTY9AuK54/uXBz2OIXJH8niW0WEacY7S71pQyYmighubTH25Lx uwwUo4kgsrILCsI/eSp0WC5QtYguZ8I= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-423-4cbIMR2gNtSLMgLC42Eb8w-1; Thu, 27 Oct 2022 12:18:52 -0400 X-MC-Unique: 4cbIMR2gNtSLMgLC42Eb8w-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.rdu2.redhat.com [10.11.54.7]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id ED5101C0896D; Thu, 27 Oct 2022 16:18:51 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id CC29C1401C21; Thu, 27 Oct 2022 16:18:51 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: mhal@rbox.co, seanjc@google.com Subject: [PATCH 09/16] KVM: Clean up hva_to_pfn_retry() Date: Thu, 27 Oct 2022 12:18:42 -0400 Message-Id: <20221027161849.2989332-10-pbonzini@redhat.com> In-Reply-To: <20221027161849.2989332-1-pbonzini@redhat.com> References: <20221027161849.2989332-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.7 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Michal Luczaj Make hva_to_pfn_retry() use kvm instance cached in gfn_to_pfn_cache. Suggested-by: Sean Christopherson Signed-off-by: Michal Luczaj Signed-off-by: Sean Christopherson Message-Id: <20221013211234.1318131-10-seanjc@google.com> Signed-off-by: Paolo Bonzini --- virt/kvm/pfncache.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index dfcf883ca298..48f400819d1e 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -138,7 +138,7 @@ static inline bool mmu_notifier_retry_cache(struct kvm = *kvm, unsigned long mmu_s return kvm->mmu_invalidate_seq !=3D mmu_seq; } =20 -static kvm_pfn_t hva_to_pfn_retry(struct kvm *kvm, struct gfn_to_pfn_cache= *gpc) +static kvm_pfn_t hva_to_pfn_retry(struct gfn_to_pfn_cache *gpc) { /* Note, the new page offset may be different than the old! */ void *old_khva =3D gpc->khva - offset_in_page(gpc->khva); @@ -158,7 +158,7 @@ static kvm_pfn_t hva_to_pfn_retry(struct kvm *kvm, stru= ct gfn_to_pfn_cache *gpc) gpc->valid =3D false; =20 do { - mmu_seq =3D kvm->mmu_invalidate_seq; + mmu_seq =3D gpc->kvm->mmu_invalidate_seq; smp_rmb(); =20 write_unlock_irq(&gpc->lock); @@ -216,7 +216,7 @@ static kvm_pfn_t hva_to_pfn_retry(struct kvm *kvm, stru= ct gfn_to_pfn_cache *gpc) * attempting to refresh. */ WARN_ON_ONCE(gpc->valid); - } while (mmu_notifier_retry_cache(kvm, mmu_seq)); + } while (mmu_notifier_retry_cache(gpc->kvm, mmu_seq)); =20 gpc->valid =3D true; gpc->pfn =3D new_pfn; @@ -296,7 +296,7 @@ static int __kvm_gpc_refresh(struct kvm *kvm, struct gf= n_to_pfn_cache *gpc, gpa_ * drop the lock and do the HVA to PFN lookup again. */ if (!gpc->valid || old_uhva !=3D gpc->uhva) { - ret =3D hva_to_pfn_retry(kvm, gpc); + ret =3D hva_to_pfn_retry(gpc); } else { /* If the HVA\ufffd\ufffd\ufffdPFN mapping was already valid, don't unma= p it. */ old_pfn =3D KVM_PFN_ERR_FAULT; --=20 2.31.1 From nobody Wed Apr 8 15:55:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9431DFA3740 for ; Thu, 27 Oct 2022 16:19:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236691AbiJ0QTc (ORCPT ); Thu, 27 Oct 2022 12:19:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54344 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236547AbiJ0QSz (ORCPT ); Thu, 27 Oct 2022 12:18:55 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 034241960A8 for ; Thu, 27 Oct 2022 09:18:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666887534; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3Z1kaLdFzke5U8bpkOkEt06MM3WX8Rjl7B7du7C4v3A=; b=IkmAIPkaUgQmSsf9gAOubFgILcyqR4wcdT9ogqRM30fvqyoY7AUVOekxmgU41KaRVMSdOy GjvrBCGscjQ7di3euKJolnavY07IbgVnM1wXxXEPkeQ0NznCTPhRIt7o+zSLOV8Tmt7+QN ODXpUwec+Sbcz5pTPbkcprc/Kf2d88A= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-558-lTJ2-pLfMdGqfACIo29oWw-1; Thu, 27 Oct 2022 12:18:52 -0400 X-MC-Unique: lTJ2-pLfMdGqfACIo29oWw-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 3BC4529AA2EC; Thu, 27 Oct 2022 16:18:52 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 19C3917593; Thu, 27 Oct 2022 16:18:52 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: mhal@rbox.co, seanjc@google.com Subject: [PATCH 10/16] KVM: Use gfn_to_pfn_cache's immutable "kvm" in kvm_gpc_refresh() Date: Thu, 27 Oct 2022 12:18:43 -0400 Message-Id: <20221027161849.2989332-11-pbonzini@redhat.com> In-Reply-To: <20221027161849.2989332-1-pbonzini@redhat.com> References: <20221027161849.2989332-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.5 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Michal Luczaj Make kvm_gpc_refresh() use kvm instance cached in gfn_to_pfn_cache. No functional change intended. Suggested-by: Sean Christopherson Signed-off-by: Michal Luczaj [sean: leave kvm_gpc_unmap() as-is] Signed-off-by: Sean Christopherson Message-Id: <20221013211234.1318131-11-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 2 +- arch/x86/kvm/xen.c | 8 ++++---- include/linux/kvm_host.h | 8 +++----- virt/kvm/pfncache.c | 11 +++++------ 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0e3546aa34dd..bdc3110650d3 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3037,7 +3037,7 @@ static void kvm_setup_guest_pvclock(struct kvm_vcpu *= v, while (!kvm_gpc_check(gpc, gpc->gpa)) { read_unlock_irqrestore(&gpc->lock, flags); =20 - if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa)) + if (kvm_gpc_refresh(gpc, gpc->gpa)) return; =20 read_lock_irqsave(&gpc->lock, flags); diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index d3cb28388e3c..545ecbd0ca36 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -248,7 +248,7 @@ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, = int state) if (state =3D=3D RUNSTATE_runnable) return; =20 - if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa)) + if (kvm_gpc_refresh(gpc, gpc->gpa)) return; =20 read_lock_irqsave(&gpc->lock, flags); @@ -377,7 +377,7 @@ void kvm_xen_inject_pending_events(struct kvm_vcpu *v) while (!kvm_gpc_check(gpc, gpc->gpa)) { read_unlock_irqrestore(&gpc->lock, flags); =20 - if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa)) + if (kvm_gpc_refresh(gpc, gpc->gpa)) return; =20 read_lock_irqsave(&gpc->lock, flags); @@ -451,7 +451,7 @@ int __kvm_xen_has_interrupt(struct kvm_vcpu *v) if (in_atomic() || !task_is_running(current)) return 1; =20 - if (kvm_gpc_refresh(v->kvm, gpc, gpc->gpa)) { + if (kvm_gpc_refresh(gpc, gpc->gpa)) { /* * If this failed, userspace has screwed up the * vcpu_info mapping. No interrupts for you. @@ -1504,7 +1504,7 @@ static int kvm_xen_set_evtchn(struct kvm_xen_evtchn *= xe, struct kvm *kvm) break; =20 idx =3D srcu_read_lock(&kvm->srcu); - rc =3D kvm_gpc_refresh(kvm, gpc, gpc->gpa); + rc =3D kvm_gpc_refresh(gpc, gpc->gpa); srcu_read_unlock(&kvm->srcu, idx); } while(!rc); =20 diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 466988b8b5f6..d4a49c89bc08 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1299,22 +1299,20 @@ bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc, gp= a_t gpa); /** * kvm_gpc_refresh - update a previously initialized cache. * - * @kvm: pointer to kvm instance. * @gpc: struct gfn_to_pfn_cache object. * @gpa: updated guest physical address to map. - * @len: sanity check; the range being access must fit a single page. * * @return: 0 for success. * -EINVAL for a mapping which would cross a page boundary. - * -EFAULT for an untranslatable guest physical address. + * -EFAULT for an untranslatable guest physical address. * * This will attempt to refresh a gfn_to_pfn_cache. Note that a successful - * returm from this function does not mean the page can be immediately + * return from this function does not mean the page can be immediately * accessed because it may have raced with an invalidation. Callers must * still lock and check the cache status, as this function does not return * with the lock still held to permit access. */ -int kvm_gpc_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpa_t g= pa); +int kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa); =20 /** * kvm_gpc_unmap - temporarily unmap a gfn_to_pfn_cache. diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 48f400819d1e..e4ebea75dca9 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -237,10 +237,9 @@ static kvm_pfn_t hva_to_pfn_retry(struct gfn_to_pfn_ca= che *gpc) return -EFAULT; } =20 -static int __kvm_gpc_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc= , gpa_t gpa, - unsigned long len) +static int __kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa, unsi= gned long len) { - struct kvm_memslots *slots =3D kvm_memslots(kvm); + struct kvm_memslots *slots =3D kvm_memslots(gpc->kvm); unsigned long page_offset =3D gpa & ~PAGE_MASK; bool unmap_old =3D false; unsigned long old_uhva; @@ -330,9 +329,9 @@ static int __kvm_gpc_refresh(struct kvm *kvm, struct gf= n_to_pfn_cache *gpc, gpa_ return ret; } =20 -int kvm_gpc_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpa_t g= pa) +int kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa) { - return __kvm_gpc_refresh(kvm, gpc, gpa, gpc->len); + return __kvm_gpc_refresh(gpc, gpa, gpc->len); } EXPORT_SYMBOL_GPL(kvm_gpc_refresh); =20 @@ -401,7 +400,7 @@ int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gpa_= t gpa, unsigned long len) gpc->active =3D true; write_unlock_irq(&gpc->lock); } - return __kvm_gpc_refresh(kvm, gpc, gpa, len); + return __kvm_gpc_refresh(gpc, gpa, len); } EXPORT_SYMBOL_GPL(kvm_gpc_activate); =20 --=20 2.31.1 From nobody Wed Apr 8 15:55:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 13D0BFA3740 for ; Thu, 27 Oct 2022 16:19:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236721AbiJ0QTr (ORCPT ); Thu, 27 Oct 2022 12:19:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54140 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236563AbiJ0QTA (ORCPT ); Thu, 27 Oct 2022 12:19:00 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 10369196B5E for ; Thu, 27 Oct 2022 09:18:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666887536; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=C6aHPqfRabBG7+Uh3PTVNYMLpzQUUZusTV/Bql6znhc=; b=Kbe1I/sNO75wMA2loxlsaDMI/D12wUSv/n6iAQNX6C9Ke+oWNACYf1BTZRpAiPCqBf2wmV 8NSYz9ETe65ISbdBllse8QKZNFlzUCwv1FVzX27aURWXfno6OAJ1yZSct0tNdPfydJMLXe bq+AUBg0WaGw9UygW8J/VzzXHlGpXVY= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-558-lUjuoMU0PFaeMn5n0Jqg-A-1; Thu, 27 Oct 2022 12:18:52 -0400 X-MC-Unique: lUjuoMU0PFaeMn5n0Jqg-A-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 6605E3C025CA; Thu, 27 Oct 2022 16:18:52 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 44CC717593; Thu, 27 Oct 2022 16:18:52 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: mhal@rbox.co, seanjc@google.com Subject: [PATCH 11/16] KVM: Drop KVM's API to allow temprorarily unmapping gfn=>pfn cache Date: Thu, 27 Oct 2022 12:18:44 -0400 Message-Id: <20221027161849.2989332-12-pbonzini@redhat.com> In-Reply-To: <20221027161849.2989332-1-pbonzini@redhat.com> References: <20221027161849.2989332-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.5 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Sean Christopherson Drop kvm_gpc_unmap() as it has no users and unclear requirements. The API was added as part of the original gfn_to_pfn_cache support, but its sole usage[*] was never merged. Fold the guts of kvm_gpc_unmap() into the deactivate path and drop the API. Omit acquiring refresh_lock as as concurrent calls to kvm_gpc_deactivate() are not allowed (this is not enforced, e.g. via lockdep. due to it being called during vCPU destruction). If/when temporary unmapping makes a comeback, the desirable behavior is likely to restrict temporary unmapping to vCPU-exclusive mappings and require the vcpu->mutex be held to serialize unmap. Use of the refresh_lock to protect unmapping was somewhat specuatively added by commit 93984f19e7bc ("KVM: Fully serialize gfn=3D>pfn cache refresh via mutex") to guard against concurrent unmaps, but the primary use case of the temporary unmap, nested virtualization[*], doesn't actually need or want concurrent unmaps. [*] https://lore.kernel.org/all/20211210163625.2886-7-dwmw2@infradead.org Signed-off-by: Sean Christopherson Message-Id: <20221013211234.1318131-12-seanjc@google.com> Signed-off-by: Paolo Bonzini --- include/linux/kvm_host.h | 12 ----------- virt/kvm/pfncache.c | 44 +++++++++++++++------------------------- 2 files changed, 16 insertions(+), 40 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index d4a49c89bc08..3847b721e753 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1314,18 +1314,6 @@ bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc, gpa= _t gpa); */ int kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa); =20 -/** - * kvm_gpc_unmap - temporarily unmap a gfn_to_pfn_cache. - * - * @kvm: pointer to kvm instance. - * @gpc: struct gfn_to_pfn_cache object. - * - * This unmaps the referenced page. The cache is left in the invalid state - * but at least the mapping from GPA to userspace HVA will remain cached - * and can be reused on a subsequent refresh. - */ -void kvm_gpc_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *gpc); - /** * kvm_gpc_deactivate - deactivate and unlink a gfn_to_pfn_cache. * diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index e4ebea75dca9..62429b2a6389 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -335,33 +335,6 @@ int kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_= t gpa) } EXPORT_SYMBOL_GPL(kvm_gpc_refresh); =20 -void kvm_gpc_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) -{ - void *old_khva; - kvm_pfn_t old_pfn; - - mutex_lock(&gpc->refresh_lock); - write_lock_irq(&gpc->lock); - - gpc->valid =3D false; - - old_khva =3D gpc->khva - offset_in_page(gpc->khva); - old_pfn =3D gpc->pfn; - - /* - * We can leave the GPA \ufffd\ufffd\ufffd uHVA map cache intact but the = PFN - * lookup will need to be redone even for the same page. - */ - gpc->khva =3D NULL; - gpc->pfn =3D KVM_PFN_ERR_FAULT; - - write_unlock_irq(&gpc->lock); - mutex_unlock(&gpc->refresh_lock); - - gpc_unmap_khva(old_pfn, old_khva); -} -EXPORT_SYMBOL_GPL(kvm_gpc_unmap); - void kvm_gpc_init(struct gfn_to_pfn_cache *gpc, struct kvm *kvm, struct kvm_vcpu *vcpu, enum pfn_cache_usage usage) { @@ -407,6 +380,8 @@ EXPORT_SYMBOL_GPL(kvm_gpc_activate); void kvm_gpc_deactivate(struct gfn_to_pfn_cache *gpc) { struct kvm *kvm =3D gpc->kvm; + kvm_pfn_t old_pfn; + void *old_khva; =20 if (gpc->active) { /* @@ -416,13 +391,26 @@ void kvm_gpc_deactivate(struct gfn_to_pfn_cache *gpc) */ write_lock_irq(&gpc->lock); gpc->active =3D false; + gpc->valid =3D false; + + /* + * Leave the GPA =3D> uHVA cache intact, it's protected by the + * memslot generation. The PFN lookup however will have to be + * redone after the cache is removed from the VM's gpc_list, + * as that loses mmu_notifier protection. + */ + old_khva =3D gpc->khva - offset_in_page(gpc->khva); + gpc->khva =3D NULL; + + old_pfn =3D gpc->pfn; + gpc->pfn =3D KVM_PFN_ERR_FAULT; write_unlock_irq(&gpc->lock); =20 spin_lock(&kvm->gpc_lock); list_del(&gpc->list); spin_unlock(&kvm->gpc_lock); =20 - kvm_gpc_unmap(kvm, gpc); + gpc_unmap_khva(old_pfn, old_khva); } } EXPORT_SYMBOL_GPL(kvm_gpc_deactivate); --=20 2.31.1 From nobody Wed Apr 8 15:55:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EAFEFFA3740 for ; Thu, 27 Oct 2022 16:20:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236633AbiJ0QUE (ORCPT ); Thu, 27 Oct 2022 12:20:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54820 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236572AbiJ0QTB (ORCPT ); Thu, 27 Oct 2022 12:19:01 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6375D1958FA for ; Thu, 27 Oct 2022 09:18:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666887536; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=W4jlslF5VNxKyOc4aJjoGknzZszIqLvBjQKfttjSBRM=; b=DDTtOA5w+u/8MpcA8VWe7aN83cHq7kqmTEtC+ZTd5ZmMJD4/nWVSnxY4S1RQ9/8oNvnmDV EctpbIsmYsNjfaiCNuWq/PUbce4hTR7gHZ//s5nbHIxrTtgXh0BArA/jCFNebLWb5FKhom Pu4QOAwA7vEyGjPKwHHv3rJ7X6qE5WA= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-306-tkL1K6RmOhWJ2BYpozAGpg-1; Thu, 27 Oct 2022 12:18:52 -0400 X-MC-Unique: tkL1K6RmOhWJ2BYpozAGpg-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 8F6F9811E67; Thu, 27 Oct 2022 16:18:52 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6E6BE17593; Thu, 27 Oct 2022 16:18:52 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: mhal@rbox.co, seanjc@google.com Subject: [PATCH 12/16] KVM: Do not partially reinitialize gfn=>pfn cache during activation Date: Thu, 27 Oct 2022 12:18:45 -0400 Message-Id: <20221027161849.2989332-13-pbonzini@redhat.com> In-Reply-To: <20221027161849.2989332-1-pbonzini@redhat.com> References: <20221027161849.2989332-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.5 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Sean Christopherson Don't partially reinitialize a gfn=3D>pfn cache when activating the cache, and instead assert that the cache is not valid during activation. Bug the VM if the assertion fails, as use-after-free and/or data corruption is all but guaranteed if KVM ends up with a valid-but-inactive cache. Signed-off-by: Sean Christopherson Message-Id: <20221013211234.1318131-13-seanjc@google.com> Signed-off-by: Paolo Bonzini --- virt/kvm/pfncache.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 62429b2a6389..06fcf03c2da6 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -347,6 +347,8 @@ void kvm_gpc_init(struct gfn_to_pfn_cache *gpc, struct = kvm *kvm, gpc->kvm =3D kvm; gpc->vcpu =3D vcpu; gpc->usage =3D usage; + gpc->pfn =3D KVM_PFN_ERR_FAULT; + gpc->uhva =3D KVM_HVA_ERR_BAD; } EXPORT_SYMBOL_GPL(kvm_gpc_init); =20 @@ -355,10 +357,8 @@ int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gpa= _t gpa, unsigned long len) struct kvm *kvm =3D gpc->kvm; =20 if (!gpc->active) { - gpc->khva =3D NULL; - gpc->pfn =3D KVM_PFN_ERR_FAULT; - gpc->uhva =3D KVM_HVA_ERR_BAD; - gpc->valid =3D false; + if (KVM_BUG_ON(gpc->valid, kvm)) + return -EIO; =20 spin_lock(&kvm->gpc_lock); list_add(&gpc->list, &kvm->gpc_list); --=20 2.31.1 From nobody Wed Apr 8 15:55:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D54E5FA3740 for ; Thu, 27 Oct 2022 16:20:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236776AbiJ0QUR (ORCPT ); Thu, 27 Oct 2022 12:20:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54128 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236606AbiJ0QTE (ORCPT ); Thu, 27 Oct 2022 12:19:04 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0F85F18DD75 for ; Thu, 27 Oct 2022 09:19:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666887539; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pXzajH97NHl0gEvAvhaePvRNuVty75RFHBFDXcj4E30=; b=argqq2J+nea1SfUcxbd9D0xZkcNnzUKIOytwlYeXh3+LJV4H/bKsFgsUv3KHPT/NI1DdGh LHYGgeD1mX474FGu0257ypPaqq9GFVS6nnTHn6IOXmjlr6yy4yC3FfRBHFW/b573vA60jG oacDEGh+l7S1AVjLbBh0CMQBKhu43mQ= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-332-NzG0FtqCNMWX5O91G12vAA-1; Thu, 27 Oct 2022 12:18:53 -0400 X-MC-Unique: NzG0FtqCNMWX5O91G12vAA-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id B993D811E81; Thu, 27 Oct 2022 16:18:52 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 98CEE39DB3; Thu, 27 Oct 2022 16:18:52 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: mhal@rbox.co, seanjc@google.com Subject: [PATCH 13/16] KVM: Drop @gpa from exported gfn=>pfn cache check() and refresh() helpers Date: Thu, 27 Oct 2022 12:18:46 -0400 Message-Id: <20221027161849.2989332-14-pbonzini@redhat.com> In-Reply-To: <20221027161849.2989332-1-pbonzini@redhat.com> References: <20221027161849.2989332-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.5 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Sean Christopherson Drop the @gpa param from the exported check()+refresh() helpers and limit changing the cache's GPA to the activate path. All external users just feed in gpc->gpa, i.e. this is a fancy nop. Allowing users to change the GPA at check()+refresh() is dangerous as those helpers explicitly allow concurrent calls, e.g. KVM could get into a livelock scenario. It's also unclear as to what the expected behavior should be if multiple tasks attempt to refresh with different GPAs. Signed-off-by: Sean Christopherson Message-Id: <20221013211234.1318131-14-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 4 ++-- arch/x86/kvm/xen.c | 20 ++++++++++---------- include/linux/kvm_host.h | 6 ++---- virt/kvm/pfncache.c | 11 ++++------- 4 files changed, 18 insertions(+), 23 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index bdc3110650d3..f7ee5ee58990 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3034,10 +3034,10 @@ static void kvm_setup_guest_pvclock(struct kvm_vcpu= *v, WARN_ON_ONCE(gpc->len !=3D offset + sizeof(*guest_hv_clock)); =20 read_lock_irqsave(&gpc->lock, flags); - while (!kvm_gpc_check(gpc, gpc->gpa)) { + while (!kvm_gpc_check(gpc)) { read_unlock_irqrestore(&gpc->lock, flags); =20 - if (kvm_gpc_refresh(gpc, gpc->gpa)) + if (kvm_gpc_refresh(gpc)) return; =20 read_lock_irqsave(&gpc->lock, flags); diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 545ecbd0ca36..7b7b1eb88a0b 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -241,14 +241,14 @@ void kvm_xen_update_runstate_guest(struct kvm_vcpu *v= , int state) return; =20 read_lock_irqsave(&gpc->lock, flags); - while (!kvm_gpc_check(gpc, gpc->gpa)) { + while (!kvm_gpc_check(gpc)) { read_unlock_irqrestore(&gpc->lock, flags); =20 /* When invoked from kvm_sched_out() we cannot sleep */ if (state =3D=3D RUNSTATE_runnable) return; =20 - if (kvm_gpc_refresh(gpc, gpc->gpa)) + if (kvm_gpc_refresh(gpc)) return; =20 read_lock_irqsave(&gpc->lock, flags); @@ -374,10 +374,10 @@ void kvm_xen_inject_pending_events(struct kvm_vcpu *v) * little more honest about it. */ read_lock_irqsave(&gpc->lock, flags); - while (!kvm_gpc_check(gpc, gpc->gpa)) { + while (!kvm_gpc_check(gpc)) { read_unlock_irqrestore(&gpc->lock, flags); =20 - if (kvm_gpc_refresh(gpc, gpc->gpa)) + if (kvm_gpc_refresh(gpc)) return; =20 read_lock_irqsave(&gpc->lock, flags); @@ -437,7 +437,7 @@ int __kvm_xen_has_interrupt(struct kvm_vcpu *v) sizeof_field(struct compat_vcpu_info, evtchn_upcall_pending)); =20 read_lock_irqsave(&gpc->lock, flags); - while (!kvm_gpc_check(gpc, gpc->gpa)) { + while (!kvm_gpc_check(gpc)) { read_unlock_irqrestore(&gpc->lock, flags); =20 /* @@ -451,7 +451,7 @@ int __kvm_xen_has_interrupt(struct kvm_vcpu *v) if (in_atomic() || !task_is_running(current)) return 1; =20 - if (kvm_gpc_refresh(gpc, gpc->gpa)) { + if (kvm_gpc_refresh(gpc)) { /* * If this failed, userspace has screwed up the * vcpu_info mapping. No interrupts for you. @@ -981,7 +981,7 @@ static bool wait_pending_event(struct kvm_vcpu *vcpu, i= nt nr_ports, =20 read_lock_irqsave(&gpc->lock, flags); idx =3D srcu_read_lock(&kvm->srcu); - if (!kvm_gpc_check(gpc, gpc->gpa)) + if (!kvm_gpc_check(gpc)) goto out_rcu; =20 ret =3D false; @@ -1372,7 +1372,7 @@ int kvm_xen_set_evtchn_fast(struct kvm_xen_evtchn *xe= , struct kvm *kvm) idx =3D srcu_read_lock(&kvm->srcu); =20 read_lock_irqsave(&gpc->lock, flags); - if (!kvm_gpc_check(gpc, gpc->gpa)) + if (!kvm_gpc_check(gpc)) goto out_rcu; =20 if (IS_ENABLED(CONFIG_64BIT) && kvm->arch.xen.long_mode) { @@ -1406,7 +1406,7 @@ int kvm_xen_set_evtchn_fast(struct kvm_xen_evtchn *xe= , struct kvm *kvm) gpc =3D &vcpu->arch.xen.vcpu_info_cache; =20 read_lock_irqsave(&gpc->lock, flags); - if (!kvm_gpc_check(gpc, gpc->gpa)) { + if (!kvm_gpc_check(gpc)) { /* * Could not access the vcpu_info. Set the bit in-kernel * and prod the vCPU to deliver it for itself. @@ -1504,7 +1504,7 @@ static int kvm_xen_set_evtchn(struct kvm_xen_evtchn *= xe, struct kvm *kvm) break; =20 idx =3D srcu_read_lock(&kvm->srcu); - rc =3D kvm_gpc_refresh(gpc, gpc->gpa); + rc =3D kvm_gpc_refresh(gpc); srcu_read_unlock(&kvm->srcu, idx); } while(!rc); =20 diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 3847b721e753..fd6b58c870cf 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1282,7 +1282,6 @@ int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, gp= a_t gpa, unsigned long len) * kvm_gpc_check - check validity of a gfn_to_pfn_cache. * * @gpc: struct gfn_to_pfn_cache object. - * @gpa: current guest physical address to map. * * @return: %true if the cache is still valid and the address matches. * %false if the cache is not valid. @@ -1294,13 +1293,12 @@ int kvm_gpc_activate(struct gfn_to_pfn_cache *gpc, = gpa_t gpa, unsigned long len) * Callers in IN_GUEST_MODE may do so without locking, although they should * still hold a read lock on kvm->scru for the memslot checks. */ -bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc, gpa_t gpa); +bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc); =20 /** * kvm_gpc_refresh - update a previously initialized cache. * * @gpc: struct gfn_to_pfn_cache object. - * @gpa: updated guest physical address to map. * * @return: 0 for success. * -EINVAL for a mapping which would cross a page boundary. @@ -1312,7 +1310,7 @@ bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc, gpa_= t gpa); * still lock and check the cache status, as this function does not return * with the lock still held to permit access. */ -int kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa); +int kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc); =20 /** * kvm_gpc_deactivate - deactivate and unlink a gfn_to_pfn_cache. diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 06fcf03c2da6..68e2e53eac8a 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -76,17 +76,14 @@ void gfn_to_pfn_cache_invalidate_start(struct kvm *kvm,= unsigned long start, } } =20 -bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc, gpa_t gpa) +bool kvm_gpc_check(struct gfn_to_pfn_cache *gpc) { struct kvm_memslots *slots =3D kvm_memslots(gpc->kvm); =20 if (!gpc->active) return false; =20 - if ((gpa & ~PAGE_MASK) + gpc->len > PAGE_SIZE) - return false; - - if (gpc->gpa !=3D gpa || gpc->generation !=3D slots->generation || + if (gpc->generation !=3D slots->generation || kvm_is_error_hva(gpc->uhva)) return false; =20 @@ -329,9 +326,9 @@ static int __kvm_gpc_refresh(struct gfn_to_pfn_cache *g= pc, gpa_t gpa, unsigned l return ret; } =20 -int kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc, gpa_t gpa) +int kvm_gpc_refresh(struct gfn_to_pfn_cache *gpc) { - return __kvm_gpc_refresh(gpc, gpa, gpc->len); + return __kvm_gpc_refresh(gpc, gpc->gpa, gpc->len); } EXPORT_SYMBOL_GPL(kvm_gpc_refresh); =20 --=20 2.31.1 From nobody Wed Apr 8 15:55:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B857FECAAA1 for ; Thu, 27 Oct 2022 16:20:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236741AbiJ0QUB (ORCPT ); Thu, 27 Oct 2022 12:20:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54826 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236573AbiJ0QTB (ORCPT ); Thu, 27 Oct 2022 12:19:01 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7C43A196085 for ; Thu, 27 Oct 2022 09:18:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666887536; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=+cor0KkOwTJItYQfjwJp6M8Gzu8KNstW05/3cHmtpUg=; b=GujaRbwDPn39Xig8DrPWRTezKZjhDT+g1bNPrJ2me77U/AZj3+zlcCPOAf1Z8pCtrRNZEr dSL46XJjbHnSZPEkN416hlXxElYPRR9bnpONwGjdV2d8zYXi52uaMBmikSDkuHdugeAyHg k4fY/1sKkjfp6i5zMGrvQzEpJkXbLBQ= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-380-hzHo1hAyNE6NbZsqvCRP6Q-1; Thu, 27 Oct 2022 12:18:53 -0400 X-MC-Unique: hzHo1hAyNE6NbZsqvCRP6Q-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id E30D2185A7A3; Thu, 27 Oct 2022 16:18:52 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id C223017593; Thu, 27 Oct 2022 16:18:52 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: mhal@rbox.co, seanjc@google.com Subject: [PATCH 14/16] KVM: Skip unnecessary "unmap" if gpc is already valid during refresh Date: Thu, 27 Oct 2022 12:18:47 -0400 Message-Id: <20221027161849.2989332-15-pbonzini@redhat.com> In-Reply-To: <20221027161849.2989332-1-pbonzini@redhat.com> References: <20221027161849.2989332-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.5 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Sean Christopherson When refreshing a gfn=3D>pfn cache, skip straight to unlocking if the cache already valid instead of stuffing the "old" variables to turn the unmapping outro into a nop. Signed-off-by: Sean Christopherson Message-Id: <20221013211234.1318131-15-seanjc@google.com> Signed-off-by: Paolo Bonzini --- virt/kvm/pfncache.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 68e2e53eac8a..b408a4b81e74 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -295,9 +295,8 @@ static int __kvm_gpc_refresh(struct gfn_to_pfn_cache *g= pc, gpa_t gpa, unsigned l ret =3D hva_to_pfn_retry(gpc); } else { /* If the HVA\ufffd\ufffd\ufffdPFN mapping was already valid, don't unma= p it. */ - old_pfn =3D KVM_PFN_ERR_FAULT; - old_khva =3D NULL; ret =3D 0; + goto out_unlock; } =20 out: --=20 2.31.1 From nobody Wed Apr 8 15:55:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CBAEEFA3740 for ; Thu, 27 Oct 2022 16:20:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236757AbiJ0QUH (ORCPT ); Thu, 27 Oct 2022 12:20:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54264 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236584AbiJ0QTC (ORCPT ); Thu, 27 Oct 2022 12:19:02 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B5B4C196ED1 for ; Thu, 27 Oct 2022 09:18:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666887537; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=QaDAbir+sBpdMoPRaLpYkTZYt9qrVnwqD4RdJh4hW+c=; b=Ta/z+y7wQ/7/X6FFGQ7F/4QpW6rxzYtlVtUKd3Na/dUabRPqpLwkmQ7Zbl+Mb1g+U0iQ1S nyEW8u29XUA5vsrAtTa/uDZPdC/DCDtmVRw8dp9Bfk5LsEAuFu0cHY9/GTxxd6COE19kN9 87JESg6G23ChweCi2TXMiLUSyiu9UYE= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-394-oPKGmDcSNq2tSVS_9m5HIQ-1; Thu, 27 Oct 2022 12:18:54 -0400 X-MC-Unique: oPKGmDcSNq2tSVS_9m5HIQ-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 1E6433C0F66F; Thu, 27 Oct 2022 16:18:53 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id ECBAB17593; Thu, 27 Oct 2022 16:18:52 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: mhal@rbox.co, seanjc@google.com Subject: [PATCH 15/16] KVM: selftests: Add tests in xen_shinfo_test to detect lock races Date: Thu, 27 Oct 2022 12:18:48 -0400 Message-Id: <20221027161849.2989332-16-pbonzini@redhat.com> In-Reply-To: <20221027161849.2989332-1-pbonzini@redhat.com> References: <20221027161849.2989332-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.5 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Michal Luczaj Tests for races between shinfo_cache (de)activation and hypercall+ioctl() processing. KVM has had bugs where activating the shared info cache multiple times and/or with concurrent users results in lock corruption, NULL pointer dereferences, and other fun. For the timer injection testcase (#22), re-arm the timer until the IRQ is successfully injected. If the timer expires while the shared info is deactivated (invalid), KVM will drop the event. Signed-off-by: Michal Luczaj Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson Message-Id: <20221013211234.1318131-16-seanjc@google.com> Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/xen_shinfo_test.c | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c b/tools/t= esting/selftests/kvm/x86_64/xen_shinfo_test.c index 8a5cb800f50e..caa3f5ab9e10 100644 --- a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c +++ b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c @@ -15,9 +15,13 @@ #include #include #include +#include =20 #include =20 +/* Defined in include/linux/kvm_types.h */ +#define GPA_INVALID (~(ulong)0) + #define SHINFO_REGION_GVA 0xc0000000ULL #define SHINFO_REGION_GPA 0xc0000000ULL #define SHINFO_REGION_SLOT 10 @@ -44,6 +48,8 @@ =20 #define MIN_STEAL_TIME 50000 =20 +#define SHINFO_RACE_TIMEOUT 2 /* seconds */ + #define __HYPERVISOR_set_timer_op 15 #define __HYPERVISOR_sched_op 29 #define __HYPERVISOR_event_channel_op 32 @@ -148,6 +154,7 @@ static void guest_wait_for_irq(void) static void guest_code(void) { struct vcpu_runstate_info *rs =3D (void *)RUNSTATE_VADDR; + int i; =20 __asm__ __volatile__( "sti\n" @@ -325,6 +332,49 @@ static void guest_code(void) guest_wait_for_irq(); =20 GUEST_SYNC(21); + /* Racing host ioctls */ + + guest_wait_for_irq(); + + GUEST_SYNC(22); + /* Racing vmcall against host ioctl */ + + ports[0] =3D 0; + + p =3D (struct sched_poll) { + .ports =3D ports, + .nr_ports =3D 1, + .timeout =3D 0 + }; + +wait_for_timer: + /* + * Poll for a timer wake event while the worker thread is mucking with + * the shared info. KVM XEN drops timer IRQs if the shared info is + * invalid when the timer expires. Arbitrarily poll 100 times before + * giving up and asking the VMM to re-arm the timer. 100 polls should + * consume enough time to beat on KVM without taking too long if the + * timer IRQ is dropped due to an invalid event channel. + */ + for (i =3D 0; i < 100 && !guest_saw_irq; i++) + asm volatile("vmcall" + : "=3Da" (rax) + : "a" (__HYPERVISOR_sched_op), + "D" (SCHEDOP_poll), + "S" (&p) + : "memory"); + + /* + * Re-send the timer IRQ if it was (likely) dropped due to the timer + * expiring while the event channel was invalid. + */ + if (!guest_saw_irq) { + GUEST_SYNC(23); + goto wait_for_timer; + } + guest_saw_irq =3D false; + + GUEST_SYNC(24); } =20 static int cmp_timespec(struct timespec *a, struct timespec *b) @@ -352,11 +402,36 @@ static void handle_alrm(int sig) TEST_FAIL("IRQ delivery timed out"); } =20 +static void *juggle_shinfo_state(void *arg) +{ + struct kvm_vm *vm =3D (struct kvm_vm *)arg; + + struct kvm_xen_hvm_attr cache_init =3D { + .type =3D KVM_XEN_ATTR_TYPE_SHARED_INFO, + .u.shared_info.gfn =3D SHINFO_REGION_GPA / PAGE_SIZE + }; + + struct kvm_xen_hvm_attr cache_destroy =3D { + .type =3D KVM_XEN_ATTR_TYPE_SHARED_INFO, + .u.shared_info.gfn =3D GPA_INVALID + }; + + for (;;) { + __vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &cache_init); + __vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &cache_destroy); + pthread_testcancel(); + }; + + return NULL; +} + int main(int argc, char *argv[]) { struct timespec min_ts, max_ts, vm_ts; struct kvm_vm *vm; + pthread_t thread; bool verbose; + int ret; =20 verbose =3D argc > 1 && (!strncmp(argv[1], "-v", 3) || !strncmp(argv[1], "--verbose", 10)); @@ -785,6 +860,71 @@ int main(int argc, char *argv[]) case 21: TEST_ASSERT(!evtchn_irq_expected, "Expected event channel IRQ but it didn't happen"); + alarm(0); + + if (verbose) + printf("Testing shinfo lock corruption (KVM_XEN_HVM_EVTCHN_SEND)\n"); + + ret =3D pthread_create(&thread, NULL, &juggle_shinfo_state, (void *)vm= ); + TEST_ASSERT(ret =3D=3D 0, "pthread_create() failed: %s", strerror(ret)= ); + + struct kvm_irq_routing_xen_evtchn uxe =3D { + .port =3D 1, + .vcpu =3D vcpu->id, + .priority =3D KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL + }; + + evtchn_irq_expected =3D true; + for (time_t t =3D time(NULL) + SHINFO_RACE_TIMEOUT; time(NULL) < t;) + __vm_ioctl(vm, KVM_XEN_HVM_EVTCHN_SEND, &uxe); + break; + + case 22: + TEST_ASSERT(!evtchn_irq_expected, + "Expected event channel IRQ but it didn't happen"); + + if (verbose) + printf("Testing shinfo lock corruption (SCHEDOP_poll)\n"); + + shinfo->evtchn_pending[0] =3D 1; + + evtchn_irq_expected =3D true; + tmr.u.timer.expires_ns =3D rs->state_entry_time + + SHINFO_RACE_TIMEOUT * 1000000000ULL; + vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &tmr); + break; + + case 23: + /* + * Optional and possibly repeated sync point. + * Injecting the timer IRQ may fail if the + * shinfo is invalid when the timer expires. + * If the timer has expired but the IRQ hasn't + * been delivered, rearm the timer and retry. + */ + vcpu_ioctl(vcpu, KVM_XEN_VCPU_GET_ATTR, &tmr); + + /* Resume the guest if the timer is still pending. */ + if (tmr.u.timer.expires_ns) + break; + + /* All done if the IRQ was delivered. */ + if (!evtchn_irq_expected) + break; + + tmr.u.timer.expires_ns =3D rs->state_entry_time + + SHINFO_RACE_TIMEOUT * 1000000000ULL; + vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &tmr); + break; + case 24: + TEST_ASSERT(!evtchn_irq_expected, + "Expected event channel IRQ but it didn't happen"); + + ret =3D pthread_cancel(thread); + TEST_ASSERT(ret =3D=3D 0, "pthread_cancel() failed: %s", strerror(ret)= ); + + ret =3D pthread_join(thread, 0); + TEST_ASSERT(ret =3D=3D 0, "pthread_join() failed: %s", strerror(ret)); goto done; =20 case 0x20: --=20 2.31.1 From nobody Wed Apr 8 15:55:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E3D6EFA3740 for ; Thu, 27 Oct 2022 16:20:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236781AbiJ0QUV (ORCPT ); Thu, 27 Oct 2022 12:20:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54282 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236629AbiJ0QTH (ORCPT ); Thu, 27 Oct 2022 12:19:07 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B063D185408 for ; Thu, 27 Oct 2022 09:19:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666887545; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=WkzKsdsqzO0BIwMIdmac25pTJyVcLWN5ODcskpn+bp4=; b=UdozvJpRqgGXi99I2lR1OJp7oWnCI7Tl81tv7mwZfsPf1ORu+dFBzgW59qNoOvhMvdR2FF N5EzWMKCl9ODsghWxmT8tEYfh0N9bF8XFfj47t3EDmQm0x+dCIu0I8HU0V3eK0qiJZowg8 owphDW+Un667buT8emx6qo+kwpF39bU= Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-438-hecbMnxFOY2Oz2srGaoKUw-1; Thu, 27 Oct 2022 12:18:55 -0400 X-MC-Unique: hecbMnxFOY2Oz2srGaoKUw-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 4816D29AA2FF; Thu, 27 Oct 2022 16:18:53 +0000 (UTC) Received: from virtlab701.virt.lab.eng.bos.redhat.com (virtlab701.virt.lab.eng.bos.redhat.com [10.19.152.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2718A17593; Thu, 27 Oct 2022 16:18:53 +0000 (UTC) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: mhal@rbox.co, seanjc@google.com Subject: [PATCH 16/16] KVM: selftests: Mark "guest_saw_irq" as volatile in xen_shinfo_test Date: Thu, 27 Oct 2022 12:18:49 -0400 Message-Id: <20221027161849.2989332-17-pbonzini@redhat.com> In-Reply-To: <20221027161849.2989332-1-pbonzini@redhat.com> References: <20221027161849.2989332-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.1 on 10.11.54.5 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Sean Christopherson Tag "guest_saw_irq" as "volatile" to ensure that the compiler will never optimize away lookups. Relying on the compiler thinking that the flag is global and thus might change also works, but it's subtle, less robust, and looks like a bug at first glance, e.g. risks being "fixed" and breaking the test. Make the flag "static" as well since convincing the compiler it's global is no longer necessary. Alternatively, the flag could be accessed with {READ,WRITE}_ONCE(), but literally every access would need the wrappers, and eking out performance isn't exactly top priority for selftests. Signed-off-by: Sean Christopherson Message-Id: <20221013211234.1318131-17-seanjc@google.com> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c b/tools/t= esting/selftests/kvm/x86_64/xen_shinfo_test.c index caa3f5ab9e10..2a5727188c8d 100644 --- a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c +++ b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c @@ -132,7 +132,7 @@ struct { struct kvm_irq_routing_entry entries[2]; } irq_routes; =20 -bool guest_saw_irq; +static volatile bool guest_saw_irq; =20 static void evtchn_handler(struct ex_regs *regs) { --=20 2.31.1