summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/paravirt-spinlock.h2
-rw-r--r--arch/x86/kernel/paravirt-spinlocks.c53
2 files changed, 53 insertions, 2 deletions
diff --git a/arch/x86/include/asm/paravirt-spinlock.h b/arch/x86/include/asm/paravirt-spinlock.h
index ff735830de4a..302bc2ba3a75 100644
--- a/arch/x86/include/asm/paravirt-spinlock.h
+++ b/arch/x86/include/asm/paravirt-spinlock.h
@@ -99,6 +99,8 @@ bool __raw_callee_save___native_vcpu_is_preempted(long cpu);
void __init native_pv_lock_init(void);
__visible void __native_queued_spin_unlock(struct qspinlock *lock);
+__visible void native_queued_spin_unlock_traced(struct qspinlock *lock);
+__visible void pv_queued_spin_unlock_traced(struct qspinlock *lock);
bool pv_is_native_spin_unlock(void);
__visible bool __native_vcpu_is_preempted(long cpu);
bool pv_is_native_vcpu_is_preempted(void);
diff --git a/arch/x86/kernel/paravirt-spinlocks.c b/arch/x86/kernel/paravirt-spinlocks.c
index ddc19dc28ba1..ca12b3655307 100644
--- a/arch/x86/kernel/paravirt-spinlocks.c
+++ b/arch/x86/kernel/paravirt-spinlocks.c
@@ -7,6 +7,7 @@
#include <linux/spinlock.h>
#include <linux/export.h>
#include <linux/jump_label.h>
+#include <trace/events/lock.h>
DEFINE_STATIC_KEY_FALSE(virt_spin_lock_key);
@@ -30,10 +31,58 @@ EXPORT_STATIC_CALL_TRAMP(queued_spin_lock_slowpath);
DEFINE_STATIC_CALL(queued_spin_unlock, __raw_callee_save___native_queued_spin_unlock);
EXPORT_STATIC_CALL_TRAMP(queued_spin_unlock);
+/*
+ * Traced unlock variants, swapped in via static_call while the
+ * contended_release tracepoint is enabled. Two of them, so each tail calls its
+ * own base directly.
+ */
+__visible void native_queued_spin_unlock_traced(struct qspinlock *lock)
+{
+ if (queued_spin_is_contended(lock))
+ trace_call__contended_release(lock);
+ native_queued_spin_unlock(lock);
+}
+PV_CALLEE_SAVE_REGS_THUNK(native_queued_spin_unlock_traced);
+
+__visible void pv_queued_spin_unlock_traced(struct qspinlock *lock)
+{
+ if (queued_spin_is_contended(lock))
+ trace_call__contended_release(lock);
+ __raw_callee_save___pv_queued_spin_unlock(lock);
+}
+PV_CALLEE_SAVE_REGS_THUNK(pv_queued_spin_unlock_traced);
+
bool pv_is_native_spin_unlock(void)
{
- return static_call_query(queued_spin_unlock) ==
- __raw_callee_save___native_queued_spin_unlock;
+ void *unlock = static_call_query(queued_spin_unlock);
+
+ return unlock == __raw_callee_save___native_queued_spin_unlock ||
+ unlock == __raw_callee_save_native_queued_spin_unlock_traced;
+}
+
+int arch_contended_release_trace_reg(void)
+{
+ void *cur = static_call_query(queued_spin_unlock);
+
+ if (cur == __raw_callee_save___native_queued_spin_unlock)
+ static_call_update(queued_spin_unlock,
+ __raw_callee_save_native_queued_spin_unlock_traced);
+ else if (cur == __raw_callee_save___pv_queued_spin_unlock)
+ static_call_update(queued_spin_unlock,
+ __raw_callee_save_pv_queued_spin_unlock_traced);
+ return 0;
+}
+
+void arch_contended_release_trace_unreg(void)
+{
+ void *cur = static_call_query(queued_spin_unlock);
+
+ if (cur == __raw_callee_save_native_queued_spin_unlock_traced)
+ static_call_update(queued_spin_unlock,
+ __raw_callee_save___native_queued_spin_unlock);
+ else if (cur == __raw_callee_save_pv_queued_spin_unlock_traced)
+ static_call_update(queued_spin_unlock,
+ __raw_callee_save___pv_queued_spin_unlock);
}
__visible bool __native_vcpu_is_preempted(long cpu)