From: Sean Christopherson <seanjc@google.com>
To: Will Deacon <will@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>,
Arnaldo Carvalho de Melo <acme@kernel.org>,
Catalin Marinas <catalin.marinas@arm.com>,
Marc Zyngier <maz@kernel.org>, Guo Ren <guoren@kernel.org>,
Nick Hu <nickhu@andestech.com>, Greentime Hu <green.hu@gmail.com>,
Vincent Chen <deanbo422@gmail.com>,
Paul Walmsley <paul.walmsley@sifive.com>,
Palmer Dabbelt <palmer@dabbelt.com>,
Albert Ou <aou@eecs.berkeley.edu>,
Thomas Gleixner <tglx@linutronix.de>,
Borislav Petkov <bp@alien8.de>,
x86@kernel.org, Paolo Bonzini <pbonzini@redhat.com>,
Boris Ostrovsky <boris.ostrovsky@oracle.com>,
Juergen Gross <jgross@suse.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Jiri Olsa <jolsa@redhat.com>, Namhyung Kim <namhyung@kernel.org>,
James Morse <james.morse@arm.com>,
Alexandru Elisei <alexandru.elisei@arm.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
"H. Peter Anvin" <hpa@zytor.com>,
Sean Christopherson <seanjc@google.com>,
Vitaly Kuznetsov <vkuznets@redhat.com>,
Wanpeng Li <wanpengli@tencent.com>,
Jim Mattson <jmattson@google.com>, Joerg Roedel <joro@8bytes.org>,
Stefano Stabellini <sstabellini@kernel.org>,
linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
kvmarm@lists.cs.columbia.edu, linux-csky@vger.kernel.org,
linux-riscv@lists.infradead.org, kvm@vger.kernel.org,
xen-devel@lists.xenproject.org,
Artem Kashkanov <artem.kashkanov@intel.com>,
Like Xu <like.xu.linux@gmail.com>,
Zhu Lingshan <lingshan.zhu@intel.com>
Subject: [PATCH 06/15] KVM: x86: Register perf callbacks only when actively handling interrupt
Date: Thu, 26 Aug 2021 17:57:09 -0700 [thread overview]
Message-ID: <20210827005718.585190-7-seanjc@google.com> (raw)
In-Reply-To: <20210827005718.585190-1-seanjc@google.com>
Register KVM's perf callback only when handling an interrupt that may be
a PMI (sadly this includes IRQs), and unregister the callback immediately
after handling the interrupt (or closing the window). Registering the
callback on a per-CPU basis (with preemption disabled!), fixes a mostly
theoretical bug where perf could dereference a NULL pointer due to KVM
unloading and unregistering the callbacks in between perf queries of the
callback functions. The precise registration will also allow for future
cleanups and optimizations, e.g. the existence of the callbacks can serve
as the "in guest" check.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/kvm/x86.c | 27 +++++++++++++++++----------
arch/x86/kvm/x86.h | 10 ++++++++++
include/linux/perf_event.h | 2 ++
kernel/events/core.c | 12 ++++++++++++
4 files changed, 41 insertions(+), 10 deletions(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index bae951344e28..bc4ee6ea7752 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8274,28 +8274,31 @@ int kvm_is_in_guest(void)
static int kvm_is_user_mode(void)
{
- int user_mode = 3;
+ struct kvm_vcpu *vcpu = __this_cpu_read(current_vcpu);
- if (__this_cpu_read(current_vcpu))
- user_mode = static_call(kvm_x86_get_cpl)(__this_cpu_read(current_vcpu));
+ if (WARN_ON_ONCE(!vcpu))
+ return 0;
- return user_mode != 0;
+ return static_call(kvm_x86_get_cpl)(vcpu) != 0;
}
static unsigned long kvm_get_guest_ip(void)
{
- unsigned long ip = 0;
+ struct kvm_vcpu *vcpu = __this_cpu_read(current_vcpu);
- if (__this_cpu_read(current_vcpu))
- ip = kvm_rip_read(__this_cpu_read(current_vcpu));
+ if (WARN_ON_ONCE(!vcpu))
+ return 0;
- return ip;
+ return kvm_rip_read(vcpu);
}
static void kvm_handle_intel_pt_intr(void)
{
struct kvm_vcpu *vcpu = __this_cpu_read(current_vcpu);
+ if (WARN_ON_ONCE(!vcpu))
+ return;
+
kvm_make_request(KVM_REQ_PMI, vcpu);
__set_bit(MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI_BIT,
(unsigned long *)&vcpu->arch.pmu.global_status);
@@ -8308,6 +8311,12 @@ static struct perf_guest_info_callbacks kvm_guest_cbs = {
.handle_intel_pt_intr = NULL,
};
+void kvm_register_perf_callbacks(void)
+{
+ __perf_register_guest_info_callbacks(&kvm_guest_cbs);
+}
+EXPORT_SYMBOL_GPL(kvm_register_perf_callbacks);
+
#ifdef CONFIG_X86_64
static void pvclock_gtod_update_fn(struct work_struct *work)
{
@@ -11063,7 +11072,6 @@ int kvm_arch_hardware_setup(void *opaque)
if (ops->intel_pt_intr_in_guest && ops->intel_pt_intr_in_guest())
kvm_guest_cbs.handle_intel_pt_intr = kvm_handle_intel_pt_intr;
- perf_register_guest_info_callbacks(&kvm_guest_cbs);
if (!kvm_cpu_cap_has(X86_FEATURE_XSAVES))
supported_xss = 0;
@@ -11092,7 +11100,6 @@ int kvm_arch_hardware_setup(void *opaque)
void kvm_arch_hardware_unsetup(void)
{
- perf_unregister_guest_info_callbacks();
kvm_guest_cbs.handle_intel_pt_intr = NULL;
static_call(kvm_x86_hardware_unsetup)();
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index 7d66d63dc55a..5cedc0e8a5d5 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -387,15 +387,25 @@ static inline bool kvm_cstate_in_guest(struct kvm *kvm)
return kvm->arch.cstate_in_guest;
}
+void kvm_register_perf_callbacks(void);
+static inline void kvm_unregister_perf_callbacks(void)
+{
+ __perf_unregister_guest_info_callbacks();
+}
+
DECLARE_PER_CPU(struct kvm_vcpu *, current_vcpu);
static inline void kvm_before_interrupt(struct kvm_vcpu *vcpu)
{
__this_cpu_write(current_vcpu, vcpu);
+
+ kvm_register_perf_callbacks();
}
static inline void kvm_after_interrupt(struct kvm_vcpu *vcpu)
{
+ kvm_unregister_perf_callbacks();
+
__this_cpu_write(current_vcpu, NULL);
}
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index c98253dae037..7a367bf1b78d 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1238,6 +1238,8 @@ extern void perf_event_bpf_event(struct bpf_prog *prog,
#ifdef CONFIG_HAVE_GUEST_PERF_EVENTS
DECLARE_PER_CPU(struct perf_guest_info_callbacks *, perf_guest_cbs);
+extern void __perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *cbs);
+extern void __perf_unregister_guest_info_callbacks(void);
extern void perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks);
extern void perf_unregister_guest_info_callbacks(void);
#endif /* CONFIG_HAVE_GUEST_PERF_EVENTS */
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 9bc1375d6ed9..2f28d9d8dc94 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -6485,6 +6485,18 @@ static void perf_pending_event(struct irq_work *entry)
#ifdef CONFIG_HAVE_GUEST_PERF_EVENTS
DEFINE_PER_CPU(struct perf_guest_info_callbacks *, perf_guest_cbs);
+void __perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *cbs)
+{
+ __this_cpu_write(perf_guest_cbs, cbs);
+}
+EXPORT_SYMBOL_GPL(__perf_register_guest_info_callbacks);
+
+void __perf_unregister_guest_info_callbacks(void)
+{
+ __this_cpu_write(perf_guest_cbs, NULL);
+}
+EXPORT_SYMBOL_GPL(__perf_unregister_guest_info_callbacks);
+
void perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *cbs)
{
int cpu;
--
2.33.0.259.gc128427fd7-goog
next prev parent reply other threads:[~2021-08-27 0:57 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-27 0:57 [PATCH 00/15] perf: KVM: Fix, optimize, and clean up callbacks Sean Christopherson
2021-08-27 0:57 ` [PATCH 01/15] KVM: x86: Register perf callbacks after calling vendor's hardware_setup() Sean Christopherson
2021-08-27 0:57 ` [PATCH 02/15] KVM: x86: Register Processor Trace interrupt hook iff PT enabled in guest Sean Christopherson
2021-08-27 0:57 ` [PATCH 03/15] perf: Stop pretending that perf can handle multiple guest callbacks Sean Christopherson
2021-08-27 0:57 ` [PATCH 04/15] perf: Force architectures to opt-in to " Sean Christopherson
2021-08-27 0:57 ` [PATCH 05/15] perf: Track guest callbacks on a per-CPU basis Sean Christopherson
2021-08-27 7:15 ` Peter Zijlstra
2021-08-27 14:49 ` Sean Christopherson
2021-08-27 14:56 ` Peter Zijlstra
2021-08-27 15:22 ` Sean Christopherson
2021-08-27 0:57 ` Sean Christopherson [this message]
2021-08-27 7:21 ` [PATCH 06/15] KVM: x86: Register perf callbacks only when actively handling interrupt Peter Zijlstra
2021-08-27 0:57 ` [PATCH 07/15] KVM: Use dedicated flag to track if KVM is handling an NMI from guest Sean Christopherson
2021-08-27 7:30 ` Peter Zijlstra
2021-08-27 14:58 ` Sean Christopherson
2021-08-27 0:57 ` [PATCH 08/15] KVM: x86: Drop current_vcpu in favor of kvm_running_vcpu Sean Christopherson
2021-08-27 0:57 ` [PATCH 09/15] KVM: arm64: Register/unregister perf callbacks at vcpu load/put Sean Christopherson
2021-08-27 0:57 ` [PATCH 10/15] KVM: Move x86's perf guest info callbacks to generic KVM Sean Christopherson
2021-08-27 0:57 ` [PATCH 11/15] KVM: x86: Move Intel Processor Trace interrupt handler to vmx.c Sean Christopherson
2021-08-27 7:34 ` Peter Zijlstra
2021-08-27 0:57 ` [PATCH 12/15] KVM: arm64: Convert to the generic perf callbacks Sean Christopherson
2021-08-27 0:57 ` [PATCH 13/15] KVM: arm64: Drop perf.c and fold its tiny bit of code into pmu.c Sean Christopherson
2021-08-27 0:57 ` [PATCH 14/15] perf: Disallow bulk unregistering of guest callbacks and do cleanup Sean Christopherson
2021-08-27 0:57 ` [PATCH 15/15] perf: KVM: Indicate "in guest" via NULL ->is_in_guest callback Sean Christopherson
2021-08-27 6:52 ` [PATCH 00/15] perf: KVM: Fix, optimize, and clean up callbacks Like Xu
2021-08-27 7:44 ` Peter Zijlstra
2021-08-27 8:01 ` Like Xu
2021-08-27 10:47 ` Peter Zijlstra
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=20210827005718.585190-7-seanjc@google.com \
--to=seanjc@google.com \
--cc=acme@kernel.org \
--cc=alexander.shishkin@linux.intel.com \
--cc=alexandru.elisei@arm.com \
--cc=aou@eecs.berkeley.edu \
--cc=artem.kashkanov@intel.com \
--cc=boris.ostrovsky@oracle.com \
--cc=bp@alien8.de \
--cc=catalin.marinas@arm.com \
--cc=deanbo422@gmail.com \
--cc=green.hu@gmail.com \
--cc=guoren@kernel.org \
--cc=hpa@zytor.com \
--cc=james.morse@arm.com \
--cc=jgross@suse.com \
--cc=jmattson@google.com \
--cc=jolsa@redhat.com \
--cc=joro@8bytes.org \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.cs.columbia.edu \
--cc=like.xu.linux@gmail.com \
--cc=lingshan.zhu@intel.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-csky@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=mark.rutland@arm.com \
--cc=maz@kernel.org \
--cc=mingo@redhat.com \
--cc=namhyung@kernel.org \
--cc=nickhu@andestech.com \
--cc=palmer@dabbelt.com \
--cc=paul.walmsley@sifive.com \
--cc=pbonzini@redhat.com \
--cc=peterz@infradead.org \
--cc=sstabellini@kernel.org \
--cc=suzuki.poulose@arm.com \
--cc=tglx@linutronix.de \
--cc=vkuznets@redhat.com \
--cc=wanpengli@tencent.com \
--cc=will@kernel.org \
--cc=x86@kernel.org \
--cc=xen-devel@lists.xenproject.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).