From nobody Wed Aug 26 01:49:54 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=none dis=none) header.from=infradead.org ARC-Seal: i=1; a=rsa-sha256; t=1783113764; cv=none; d=zohomail.com; s=zohoarc; b=m2qEDLPy7fYh5bx1vz5nUnC3JZ/CrGGi9vakgTkWauuHTYTXLvdiPzInpx/rXVzTR5t0DCt0m+Td7DdqIMBx4Dk0Ycb0KVUKde4+6pjLDTojJm3Sf5lcxDOU9BoiUHAWHAzjRKzNZI6Fq8Z1To++MDMLtqSAE/ioSxiH/qKttxM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113764; h=Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To:Cc; bh=CzWz4Us7r/rEWP66HSxuHNlM7/EVQzg+tC4fjHgL8hU=; b=D5d5BCeE/sxfQwPZsUH5N9/Mhl94pqyM9dhOqONePZTHxNh3Qzkk8yOu+IvIGdgtpTHu6oqO9jJEz0iUEaNg2pCrbDcDUvV3ZDAUnnflqLrdaz54PH68gsgOtLpqGHKpgDGvIp7cEg4SidPAkpAKQZqTI3b9qj/3DzeBWFyV8NE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1783113764437203.12266108284382; Fri, 3 Jul 2026 14:22:44 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353751.1609454 (Exim 4.92) (envelope-from ) id 1wflKn-0005Fb-BS; Fri, 03 Jul 2026 21:22:05 +0000 Received: by outflank-mailman (output) from mailman id 1353751.1609454; Fri, 03 Jul 2026 21:22:05 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKn-0005Eh-60; Fri, 03 Jul 2026 21:22:05 +0000 Received: by outflank-mailman (input) for mailman id 1353751; Fri, 03 Jul 2026 21:22:03 +0000 Received: from mx.expurgate.net ([194.145.224.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKk-00051P-Kz for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:22:03 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflKk-001t36-1i; Fri, 03 Jul 2026 23:22:02 +0200 Received: from [10.42.69.3] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4827ca-bab6-0a2a0a5309dd-0a2a4503bf3c-16 for ; Fri, 03 Jul 2026 23:22:01 +0200 Received: from [90.155.50.34] (helo=casper.infradead.org) by tlsNG-33051d.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a4827f9-ec1a-0a2a45030019-5a9b3222c562-3 for ; Fri, 03 Jul 2026 23:22:01 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKX-0000000AsYG-1i3E; Fri, 03 Jul 2026 21:21:49 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKX-00000001RPb-1H0I; Fri, 03 Jul 2026 22:21:49 +0100 X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Authentication-Results: eu.smtp.expurgate.cloud; dkim=pass header.s=casper.20170209 header.d=infradead.org header.i="@infradead.org" header.h="Sender:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To:From" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To:From:Reply-To: Cc:Content-Type:Content-ID:Content-Description; bh=CzWz4Us7r/rEWP66HSxuHNlM7/EVQzg+tC4fjHgL8hU=; b=mTF1YHeydnaypEa+INXWx9qXoR M0PqgmKfFa4z677E1dsW1eEvyWkF6xUV1PdB8gg/x+CCYBbTc8AfTSe7OkZPaq2U5ubShAbVjKgct kCMUrQtwKWJRjjP9W7glXLslomFXL1Uab3oPmtTv/VeXByun+aTfqAFILzp5HUTkuKh4m1NdyROs6 HNxK1P0nee9tkb0MG2OqepLt57YqRuJjvJlfa11a8OWJs2g1z30A2IGWV3whrfTOf0xpAlQC1+teG DfqFxOoVBfqyecjXVw+McN+dGdz8Nmn7AjS0GmGwMHLWHq8299lfwPp8dMCfRogqtIfbHaA41RpTZ GQMkyl5A==; From: David Woodhouse To: Paolo Bonzini , Jonathan Corbet , Shuah Khan , Sean Christopherson , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , Vitaly Kuznetsov , Juergen Gross , Boris Ostrovsky , David Woodhouse , Paul Durrant , Jonathan Cameron , Sascha Bischoff , Marc Zyngier , Joey Gouly , Jack Allister , Dongli Zhang , joe.jin@oracle.com, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, xen-devel@lists.xenproject.org, linux-kselftest@vger.kernel.org Subject: [PATCH v6 27/36] KVM: x86: Avoid redundant masterclock updates from multiple vCPUs Date: Fri, 3 Jul 2026 22:18:06 +0100 Message-ID: <20260703212145.343527-28-dwmw2@infradead.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260703212145.343527-1-dwmw2@infradead.org> References: <20260703212145.343527-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-33051d/1783113721-B63305D1-3A59CD18/0/0 X-purgate-type: clean X-purgate-size: 5183 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113766549158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse When a masterclock update is triggered (e.g. by the clocksource change notifier), KVM_REQ_MASTERCLOCK_UPDATE is set on all vCPUs. Without this fix, each vCPU independently processes the request and redundantly re-executes the entire pvclock_update_vm_gtod_copy() sequence, serialized only by tsc_write_lock. Each redundant re-snapshot of the master clock reference point introduces potential clock drift. Fix this by having __kvm_start_pvclock_update() check, after acquiring the lock, whether the requesting vCPU's KVM_REQ_MASTERCLOCK_UPDATE is still set. If another vCPU already did the update and cleared it, bail out. Otherwise, clear the request on all other vCPUs before proceeding. The caller in vcpu_enter_guest() now uses kvm_test_request() (non-clearing) since the clearing is done inside __kvm_start_pvclock_update() under the lock. Suggested-by: Dongli Zhang Signed-off-by: David Woodhouse Tested-by: Dongli Zhang --- arch/x86/kvm/x86.c | 60 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 2a1e1a1ab6ee..80fe69974ded 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3282,10 +3282,39 @@ static void kvm_make_mclock_inprogress_request(stru= ct kvm *kvm) kvm_make_all_cpus_request(kvm, KVM_REQ_MCLOCK_INPROGRESS); } =20 -static void __kvm_start_pvclock_update(struct kvm *kvm) +static void kvm_clear_mclock_inprogress_request(struct kvm *kvm) { + struct kvm_vcpu *vcpu; + unsigned long i; + + kvm_for_each_vcpu(i, vcpu, kvm) + kvm_clear_request(KVM_REQ_MCLOCK_INPROGRESS, vcpu); +} + +static bool __kvm_start_pvclock_update(struct kvm *kvm, struct kvm_vcpu *r= equesting_vcpu) +{ + struct kvm_vcpu *vcpu; + unsigned long i; + raw_spin_lock_irq(&kvm->arch.tsc_write_lock); + + /* + * If another vCPU already did the update while we were waiting + * for the lock, our request will have been cleared. Bail out. + */ + if (requesting_vcpu && + !kvm_test_request(KVM_REQ_MASTERCLOCK_UPDATE, requesting_vcpu)) { + kvm_clear_mclock_inprogress_request(kvm); + raw_spin_unlock_irq(&kvm->arch.tsc_write_lock); + return false; + } + + /* The update is VM-wide; prevent other vCPUs from redoing it. */ + kvm_for_each_vcpu(i, vcpu, kvm) + kvm_clear_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu); + write_seqcount_begin(&kvm->arch.pvclock_sc); + return true; } =20 static void kvm_start_pvclock_update(struct kvm *kvm) @@ -3293,7 +3322,7 @@ static void kvm_start_pvclock_update(struct kvm *kvm) kvm_make_mclock_inprogress_request(kvm); =20 /* no guest entries from this point */ - __kvm_start_pvclock_update(kvm); + __kvm_start_pvclock_update(kvm, NULL); } =20 static void kvm_end_pvclock_update(struct kvm *kvm) @@ -3302,22 +3331,25 @@ static void kvm_end_pvclock_update(struct kvm *kvm) struct kvm_vcpu *vcpu; unsigned long i; =20 - write_seqcount_end(&ka->pvclock_sc); - raw_spin_unlock_irq(&ka->tsc_write_lock); kvm_for_each_vcpu(i, vcpu, kvm) kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); =20 /* guest entries allowed */ - kvm_for_each_vcpu(i, vcpu, kvm) - kvm_clear_request(KVM_REQ_MCLOCK_INPROGRESS, vcpu); + kvm_clear_mclock_inprogress_request(kvm); + + write_seqcount_end(&ka->pvclock_sc); + raw_spin_unlock_irq(&ka->tsc_write_lock); } =20 -static void kvm_update_masterclock(struct kvm *kvm) +static void kvm_update_masterclock(struct kvm *kvm, struct kvm_vcpu *vcpu) { kvm_hv_request_tsc_page_update(kvm); - kvm_start_pvclock_update(kvm); - pvclock_update_vm_gtod_copy(kvm); - kvm_end_pvclock_update(kvm); + kvm_make_mclock_inprogress_request(kvm); + + if (__kvm_start_pvclock_update(kvm, vcpu)) { + pvclock_update_vm_gtod_copy(kvm); + kvm_end_pvclock_update(kvm); + } } =20 /* @@ -10144,7 +10176,7 @@ static void kvm_hyperv_tsc_notifier(void) kvm_caps.max_guest_tsc_khz =3D tsc_khz; =20 list_for_each_entry(kvm, &vm_list, vm_list) { - __kvm_start_pvclock_update(kvm); + __kvm_start_pvclock_update(kvm, NULL); pvclock_update_vm_gtod_copy(kvm); kvm_end_pvclock_update(kvm); } @@ -11522,8 +11554,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) kvm_mmu_free_obsolete_roots(vcpu); if (kvm_check_request(KVM_REQ_MIGRATE_TIMER, vcpu)) __kvm_migrate_timers(vcpu); - if (kvm_check_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu)) - kvm_update_masterclock(vcpu->kvm); + if (kvm_test_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu)) + kvm_update_masterclock(vcpu->kvm, vcpu); if (kvm_check_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu)) kvm_gen_kvmclock_update(vcpu); if (kvm_check_request(KVM_REQ_CLOCK_UPDATE, vcpu)) { @@ -13260,7 +13292,7 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) vcpu_load(vcpu); kvm_synchronize_tsc(vcpu, NULL); if (!vcpu->kvm->arch.use_master_clock) - kvm_update_masterclock(vcpu->kvm); + kvm_update_masterclock(vcpu->kvm, NULL); vcpu_put(vcpu); =20 /* poll control enabled by default */ --=20 2.54.0