From: Keir Fraser <keirf@google.com>
To: Yao Yuan <yaoyuan@linux.alibaba.com>
Cc: linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, kvm@vger.kernel.org,
Sean Christopherson <seanjc@google.com>,
Eric Auger <eric.auger@redhat.com>,
Oliver Upton <oliver.upton@linux.dev>,
Marc Zyngier <maz@kernel.org>, Will Deacon <will@kernel.org>,
Paolo Bonzini <pbonzini@redhat.com>
Subject: Re: [PATCH v2 3/4] KVM: Implement barriers before accessing kvm->buses[] on SRCU read paths
Date: Fri, 18 Jul 2025 14:56:25 +0000 [thread overview]
Message-ID: <aHpgmTD0J9UpTzQb@google.com> (raw)
In-Reply-To: <ndwhwg4lmy22vnqy3yqnpdqj7o366crbrhgj5py5fm3g3l2ow3@5s24dzpkswa2>
On Thu, Jul 17, 2025 at 02:01:32PM +0800, Yao Yuan wrote:
> On Wed, Jul 16, 2025 at 11:07:36AM +0800, Keir Fraser wrote:
> > This ensures that, if a VCPU has "observed" that an IO registration has
> > occurred, the instruction currently being trapped or emulated will also
> > observe the IO registration.
> >
> > At the same time, enforce that kvm_get_bus() is used only on the
> > update side, ensuring that a long-term reference cannot be obtained by
> > an SRCU reader.
> >
> > Signed-off-by: Keir Fraser <keirf@google.com>
> > ---
> > arch/x86/kvm/vmx/vmx.c | 7 +++++++
> > include/linux/kvm_host.h | 10 +++++++---
> > virt/kvm/kvm_main.c | 33 +++++++++++++++++++++++++++------
> > 3 files changed, 41 insertions(+), 9 deletions(-)
> >
> > diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> > index 191a9ed0da22..425e3d8074ab 100644
> > --- a/arch/x86/kvm/vmx/vmx.c
> > +++ b/arch/x86/kvm/vmx/vmx.c
> > @@ -5861,6 +5861,13 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu)
> > if (kvm_test_request(KVM_REQ_EVENT, vcpu))
> > return 1;
> >
> > + /*
> > + * Ensure that any updates to kvm->buses[] observed by the
> > + * previous instruction (emulated or otherwise) are also
> > + * visible to the instruction we are about to emulate.
> > + */
> > + smp_rmb();
> > +
> > if (!kvm_emulate_instruction(vcpu, 0))
> > return 0;
> >
> > diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> > index 3bde4fb5c6aa..9132148fb467 100644
> > --- a/include/linux/kvm_host.h
> > +++ b/include/linux/kvm_host.h
> > @@ -965,11 +965,15 @@ static inline bool kvm_dirty_log_manual_protect_and_init_set(struct kvm *kvm)
> > return !!(kvm->manual_dirty_log_protect & KVM_DIRTY_LOG_INITIALLY_SET);
> > }
> >
> > +/*
> > + * Get a bus reference under the update-side lock. No long-term SRCU reader
> > + * references are permitted, to avoid stale reads vs concurrent IO
> > + * registrations.
> > + */
> > static inline struct kvm_io_bus *kvm_get_bus(struct kvm *kvm, enum kvm_bus idx)
> > {
> > - return srcu_dereference_check(kvm->buses[idx], &kvm->srcu,
> > - lockdep_is_held(&kvm->slots_lock) ||
> > - !refcount_read(&kvm->users_count));
> > + return rcu_dereference_protected(kvm->buses[idx],
> > + lockdep_is_held(&kvm->slots_lock));
>
> I want to consult the true reason for using protected version here,
> save unnecessary READ_ONCE() ?
We don't want this function to be callable from SRCU read section, but
*only* during teardown. Hence protected version provides a better,
stricter safety check (that there are no users).
-- Keir
> > }
> >
> > static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i)
> > diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> > index 222f0e894a0c..9ec3b96b9666 100644
> > --- a/virt/kvm/kvm_main.c
> > +++ b/virt/kvm/kvm_main.c
> > @@ -1103,6 +1103,15 @@ void __weak kvm_arch_create_vm_debugfs(struct kvm *kvm)
> > {
> > }
> >
> > +/* Called only on cleanup and destruction paths when there are no users. */
> > +static inline struct kvm_io_bus *kvm_get_bus_for_destruction(struct kvm *kvm,
> > + enum kvm_bus idx)
> > +{
> > + return rcu_dereference_protected(kvm->buses[idx],
> > + !refcount_read(&kvm->users_count));
> > +}
> > +
> > +
> > static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
> > {
> > struct kvm *kvm = kvm_arch_alloc_vm();
> > @@ -1228,7 +1237,7 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
> > out_err_no_arch_destroy_vm:
> > WARN_ON_ONCE(!refcount_dec_and_test(&kvm->users_count));
> > for (i = 0; i < KVM_NR_BUSES; i++)
> > - kfree(kvm_get_bus(kvm, i));
> > + kfree(kvm_get_bus_for_destruction(kvm, i));
> > kvm_free_irq_routing(kvm);
> > out_err_no_irq_routing:
> > cleanup_srcu_struct(&kvm->irq_srcu);
> > @@ -1276,7 +1285,7 @@ static void kvm_destroy_vm(struct kvm *kvm)
> >
> > kvm_free_irq_routing(kvm);
> > for (i = 0; i < KVM_NR_BUSES; i++) {
> > - struct kvm_io_bus *bus = kvm_get_bus(kvm, i);
> > + struct kvm_io_bus *bus = kvm_get_bus_for_destruction(kvm, i);
> >
> > if (bus)
> > kvm_io_bus_destroy(bus);
> > @@ -5838,6 +5847,18 @@ static int __kvm_io_bus_write(struct kvm_vcpu *vcpu, struct kvm_io_bus *bus,
> > return -EOPNOTSUPP;
> > }
> >
> > +static struct kvm_io_bus *kvm_get_bus_srcu(struct kvm *kvm, enum kvm_bus idx)
> > +{
> > + /*
> > + * Ensure that any updates to kvm_buses[] observed by the previous VCPU
> > + * machine instruction are also visible to the VCPU machine instruction
> > + * that triggered this call.
> > + */
> > + smp_mb__after_srcu_read_lock();
> > +
> > + return srcu_dereference(kvm->buses[idx], &kvm->srcu);
> > +}
> > +
> > int kvm_io_bus_write(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr,
> > int len, const void *val)
> > {
> > @@ -5850,7 +5871,7 @@ int kvm_io_bus_write(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr,
> > .len = len,
> > };
> >
> > - bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu);
> > + bus = kvm_get_bus_srcu(vcpu->kvm, bus_idx);
> > if (!bus)
> > return -ENOMEM;
> > r = __kvm_io_bus_write(vcpu, bus, &range, val);
> > @@ -5869,7 +5890,7 @@ int kvm_io_bus_write_cookie(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx,
> > .len = len,
> > };
> >
> > - bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu);
> > + bus = kvm_get_bus_srcu(vcpu->kvm, bus_idx);
> > if (!bus)
> > return -ENOMEM;
> >
> > @@ -5919,7 +5940,7 @@ int kvm_io_bus_read(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr,
> > .len = len,
> > };
> >
> > - bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu);
> > + bus = kvm_get_bus_srcu(vcpu->kvm, bus_idx);
> > if (!bus)
> > return -ENOMEM;
> > r = __kvm_io_bus_read(vcpu, bus, &range, val);
> > @@ -6028,7 +6049,7 @@ struct kvm_io_device *kvm_io_bus_get_dev(struct kvm *kvm, enum kvm_bus bus_idx,
> >
> > srcu_idx = srcu_read_lock(&kvm->srcu);
> >
> > - bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
> > + bus = kvm_get_bus_srcu(kvm, bus_idx);
> > if (!bus)
> > goto out_unlock;
> >
> > --
> > 2.50.0.727.gbf7dc18ff4-goog
> >
next prev parent reply other threads:[~2025-07-18 14:56 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-16 11:07 [PATCH v2 0/4] KVM: Speed up MMIO registrations Keir Fraser
2025-07-16 11:07 ` [PATCH v2 1/4] KVM: arm64: vgic-init: Remove vgic_ready() macro Keir Fraser
2025-07-16 11:07 ` [PATCH v2 2/4] KVM: arm64: vgic: Explicitly implement vgic_dist::ready ordering Keir Fraser
2025-07-17 5:44 ` Yao Yuan
2025-07-18 14:53 ` Keir Fraser
2025-07-18 15:01 ` Sean Christopherson
2025-07-18 15:25 ` Keir Fraser
2025-07-19 2:23 ` Yao Yuan
2025-07-18 15:00 ` Sean Christopherson
2025-07-19 2:15 ` Yao Yuan
2025-07-19 7:58 ` Keir Fraser
2025-07-20 0:08 ` Yao Yuan
2025-07-21 7:49 ` Keir Fraser
2025-07-22 2:01 ` Yao Yuan
2025-07-22 2:22 ` Yao Yuan
2025-07-16 11:07 ` [PATCH v2 3/4] KVM: Implement barriers before accessing kvm->buses[] on SRCU read paths Keir Fraser
2025-07-17 6:01 ` Yao Yuan
2025-07-18 14:54 ` Sean Christopherson
2025-07-19 2:37 ` Yao Yuan
2025-07-18 14:56 ` Keir Fraser [this message]
2025-07-19 2:33 ` Yao Yuan
2025-07-16 11:07 ` [PATCH v2 4/4] KVM: Avoid synchronize_srcu() in kvm_io_bus_register_dev() Keir Fraser
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aHpgmTD0J9UpTzQb@google.com \
--to=keirf@google.com \
--cc=eric.auger@redhat.com \
--cc=kvm@vger.kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=maz@kernel.org \
--cc=oliver.upton@linux.dev \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
--cc=will@kernel.org \
--cc=yaoyuan@linux.alibaba.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.