Bus locks monopolize the memory bus for thousands of cycles, stalling all CPUs and degrading system performance for every workload on the system. Cloud providers running multiple VMs need a way to identify which guest is responsible, so the offending VM can be flagged. Bus lock VMEXITs on AMD are fault-style, i.e. the vCPU's RIP points to the offending instruction at the time of the exit. Log guest's linear RIP and vCPU info to give operators the data needed to attribute the bus lock to a specific VM and instruction. Keep policy enforcement to userspace via KVM_EXIT_X86_BUS_LOCK and let userspace implement throttling or other mitigations. Reuse current->reported_split_lock to limit the warning to the once per vCPU thread. Note that, current->reported_split_lock tracks the vCPU thread, not the individual guest process, i.e. the warning fires once per vCPU for the lifetime of thread regardless of how many distinct guest processes trigger bus locks on that vCPU. ---- The intent is purely observational — give hypervisor owners visibility into which guest is generating bus locks so they can act accordingly. No policy enforcement is done in the kernel. Suggestions on the approach are welcome. Suggested-by: Nikunj A Dadhania Signed-off-by: Manali Shukla --- arch/x86/include/asm/cpu.h | 2 ++ arch/x86/kernel/cpu/bus_lock.c | 19 +++++++++++++++++++ arch/x86/kvm/svm/svm.c | 1 + 3 files changed, 22 insertions(+) diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index ad235dda1ded..4ac5011e10b2 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -29,6 +29,7 @@ unsigned int x86_stepping(unsigned int sig); extern void __init sld_setup(struct cpuinfo_x86 *c); extern bool handle_user_split_lock(struct pt_regs *regs, long error_code); extern bool handle_guest_split_lock(unsigned long ip); +extern void handle_guest_bus_lock(unsigned long ip); extern void handle_bus_lock(struct pt_regs *regs); void split_lock_init(void); void bus_lock_init(void); @@ -44,6 +45,7 @@ static inline bool handle_guest_split_lock(unsigned long ip) return false; } +static inline void handle_guest_bus_lock(unsigned long ip) {} static inline void handle_bus_lock(struct pt_regs *regs) {} static inline void split_lock_init(void) {} static inline void bus_lock_init(void) {} diff --git a/arch/x86/kernel/cpu/bus_lock.c b/arch/x86/kernel/cpu/bus_lock.c index fb166662bc0d..a6d231410535 100644 --- a/arch/x86/kernel/cpu/bus_lock.c +++ b/arch/x86/kernel/cpu/bus_lock.c @@ -292,6 +292,25 @@ bool handle_guest_split_lock(unsigned long ip) } EXPORT_SYMBOL_FOR_KVM(handle_guest_split_lock); +void handle_guest_bus_lock(unsigned long ip) +{ + /* + * Log bus lock exit when called from KVM exit handlers. Policy + * enforcement is delegated to userspace via KVM_EXIT_X86_BUS_LOCK. + * Let userspace implement throttling or other mitigations. + * + * Only log when split lock detection is active to respect system-wide + * bus lock detection policy. Use the reported_split_lock flag to + * prevent log spam from the same vCPU. + */ + if (sld_state != sld_off && !current->reported_split_lock) { + pr_warn_ratelimited("%s/%d buslock at rip: 0x%lx\n", + current->comm, current->pid, ip); + current->reported_split_lock = 1; + } +} +EXPORT_SYMBOL_FOR_KVM(handle_guest_bus_lock); + void bus_lock_init(void) { u64 val; diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index d98fbc0e58e8..bb8efd877876 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -3258,6 +3258,7 @@ static int bus_lock_exit(struct kvm_vcpu *vcpu) vcpu->arch.cui_linear_rip = kvm_get_linear_rip(vcpu); vcpu->arch.complete_userspace_io = complete_userspace_buslock; + handle_guest_bus_lock(vcpu->arch.cui_linear_rip); if (is_guest_mode(vcpu)) svm->nested.last_bus_lock_rip = vcpu->arch.cui_linear_rip; -- 2.43.0