[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 15/15] perf: KVM: Indicate "in guest" via NULL ->is_in_guest callback



Interpret a null ->is_in_guest callback as meaning "in guest" and use
the new semantics in KVM, which currently returns 'true' unconditionally
in its implementation of ->is_in_guest().  This avoids a retpoline on
the indirect call for PMIs that arrive in a KVM guest, and also provides
a handy excuse for a wrapper around retrieval of perf_get_guest_cbs,
e.g. to reduce the probability of an errant direct read of perf_guest_cbs.

Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx>
---
 arch/x86/events/core.c       | 16 ++++++++--------
 arch/x86/events/intel/core.c |  5 ++---
 include/linux/perf_event.h   | 17 +++++++++++++++++
 virt/kvm/kvm_main.c          |  9 ++-------
 4 files changed, 29 insertions(+), 18 deletions(-)

diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index 34155a52e498..b60c339ae06b 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -2761,11 +2761,11 @@ static bool perf_hw_regs(struct pt_regs *regs)
 void
 perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs 
*regs)
 {
-       struct perf_guest_info_callbacks *guest_cbs = 
this_cpu_read(perf_guest_cbs);
+       struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
        struct unwind_state state;
        unsigned long addr;
 
-       if (guest_cbs && guest_cbs->is_in_guest()) {
+       if (guest_cbs) {
                /* TODO: We don't support guest os callchain now */
                return;
        }
@@ -2865,11 +2865,11 @@ perf_callchain_user32(struct pt_regs *regs, struct 
perf_callchain_entry_ctx *ent
 void
 perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs 
*regs)
 {
-       struct perf_guest_info_callbacks *guest_cbs = 
this_cpu_read(perf_guest_cbs);
+       struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
        struct stack_frame frame;
        const struct stack_frame __user *fp;
 
-       if (guest_cbs && guest_cbs->is_in_guest()) {
+       if (guest_cbs) {
                /* TODO: We don't support guest os callchain now */
                return;
        }
@@ -2946,9 +2946,9 @@ static unsigned long code_segment_base(struct pt_regs 
*regs)
 
 unsigned long perf_instruction_pointer(struct pt_regs *regs)
 {
-       struct perf_guest_info_callbacks *guest_cbs = 
this_cpu_read(perf_guest_cbs);
+       struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
 
-       if (guest_cbs && guest_cbs->is_in_guest())
+       if (guest_cbs)
                return guest_cbs->get_guest_ip();
 
        return regs->ip + code_segment_base(regs);
@@ -2956,10 +2956,10 @@ unsigned long perf_instruction_pointer(struct pt_regs 
*regs)
 
 unsigned long perf_misc_flags(struct pt_regs *regs)
 {
-       struct perf_guest_info_callbacks *guest_cbs = 
this_cpu_read(perf_guest_cbs);
+       struct perf_guest_info_callbacks *guest_cbs = perf_get_guest_cbs();
        int misc = 0;
 
-       if (guest_cbs && guest_cbs->is_in_guest()) {
+       if (guest_cbs) {
                if (guest_cbs->is_user_mode())
                        misc |= PERF_RECORD_MISC_GUEST_USER;
                else
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 96001962c24d..9a8c18b51a96 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -2853,9 +2853,8 @@ static int handle_pmi_common(struct pt_regs *regs, u64 
status)
         */
        if (__test_and_clear_bit(GLOBAL_STATUS_TRACE_TOPAPMI_BIT, (unsigned 
long *)&status)) {
                handled++;
-               guest_cbs = this_cpu_read(perf_guest_cbs);
-               if (unlikely(guest_cbs && guest_cbs->is_in_guest() &&
-                            guest_cbs->handle_intel_pt_intr))
+               guest_cbs = perf_get_guest_cbs();
+               if (unlikely(guest_cbs && guest_cbs->handle_intel_pt_intr))
                        guest_cbs->handle_intel_pt_intr();
                else
                        intel_pt_interrupt();
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index db701409a62f..6e3a10784d24 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1241,6 +1241,23 @@ 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_all_cpus(struct 
perf_guest_info_callbacks *cbs);
+/*
+ * Returns guest callbacks for the current CPU if callbacks are registered and
+ * the PMI fired while a guest was running, otherwise returns NULL.
+ */
+static inline struct perf_guest_info_callbacks *perf_get_guest_cbs(void)
+{
+       struct perf_guest_info_callbacks *guest_cbs = 
this_cpu_read(perf_guest_cbs);
+
+       /*
+        * Implementing is_in_guest is optional if the callbacks are registered
+        * only when "in guest".
+        */
+       if (guest_cbs && (!guest_cbs->is_in_guest || guest_cbs->is_in_guest()))
+               return guest_cbs;
+
+       return NULL;
+}
 #endif /* CONFIG_HAVE_GUEST_PERF_EVENTS */
 
 extern void perf_event_exec(void);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 1bcc3eab510b..fa83d3846785 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -5461,12 +5461,6 @@ struct kvm_vcpu * __percpu *kvm_get_running_vcpus(void)
 }
 
 #ifdef __KVM_WANT_PERF_CALLBACKS
-static int kvm_is_in_guest(void)
-{
-       /* Registration of KVM's callback signifies "in guest". */
-       return true;
-}
-
 static int kvm_is_user_mode(void)
 {
        struct kvm_vcpu *vcpu = kvm_get_running_vcpu();
@@ -5488,7 +5482,8 @@ static unsigned long kvm_get_guest_ip(void)
 }
 
 static struct perf_guest_info_callbacks kvm_guest_cbs = {
-       .is_in_guest            = kvm_is_in_guest,
+       /* Registration of KVM's callback signifies "in guest". */
+       .is_in_guest            = NULL,
        .is_user_mode           = kvm_is_user_mode,
        .get_guest_ip           = kvm_get_guest_ip,
        .handle_intel_pt_intr   = NULL,
-- 
2.33.0.259.gc128427fd7-goog




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.