Messages in this thread Patch in this message | | | From | Maksim Davydov <> | Subject | [PATCH] x86/split_lock: add split lock counter | Date | Fri, 15 Dec 2023 17:01:13 +0300 |
| |
Provides per task split locks counter to monitor split locks rate in the system. It can be helpful in split locks monitoring to get a clear sense of which process causing split locks and how many of them have happened by the moment. For instance, it might be used by cloud providers who can't control guest executable code and want to make decisions based on the rate value like ratelimiting or notifing the split lock origins.
To implement this functionality the per-task flag have been transformed into the counter. But procfs interface is used to provide the counter in machine-readable format.
Signed-off-by: Maksim Davydov <davydov-max@yandex-team.ru> --- arch/x86/include/asm/cpu.h | 18 ++++++++++++++++++ arch/x86/kernel/cpu/intel.c | 35 +++++++++++++++++++++++++++++++++-- fs/proc/base.c | 7 +++++++ include/linux/sched.h | 6 +++--- kernel/fork.c | 2 +- 5 files changed, 62 insertions(+), 6 deletions(-)
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index fecc4fe1d68a..1470124e1d63 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -44,6 +44,12 @@ 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_bus_lock(struct pt_regs *regs); u8 get_this_hybrid_cpu_type(void); +extern int proc_pid_split_locks_show(struct seq_file *s, + struct pid_namespace *ns, struct pid *pid, + struct task_struct *tsk); +extern int proc_tgid_split_locks_show(struct seq_file *s, + struct pid_namespace *ns, struct pid *pid, + struct task_struct *tsk); #else static inline void __init sld_setup(struct cpuinfo_x86 *c) {} static inline bool handle_user_split_lock(struct pt_regs *regs, long error_code) @@ -62,6 +68,18 @@ static inline u8 get_this_hybrid_cpu_type(void) { return 0; } +static inline int proc_pid_split_locks_show(struct seq_file *s, + struct pid_namespace *ns, struct pid *pid, + struct task_struct *tsk) +{ + return 0; +} +static inline int proc_tgid_split_locks_show(struct seq_file *s, + struct pid_namespace *ns, struct pid *pid, + struct task_struct *tsk) +{ + return 0; +} #endif #ifdef CONFIG_IA32_FEAT_CTL void init_ia32_feat_ctl(struct cpuinfo_x86 *c); diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index a927a8fc9624..20640a4b9eac 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -1160,10 +1160,10 @@ static void split_lock_warn(unsigned long ip) struct delayed_work *work; int cpu; - if (!current->reported_split_lock) + if (!current->detected_split_locks) pr_warn_ratelimited("#AC: %s/%d took a split_lock trap at address: 0x%lx\n", current->comm, current->pid, ip); - current->reported_split_lock = 1; + current->detected_split_locks++; if (sysctl_sld_mitigate) { /* @@ -1191,6 +1191,37 @@ static void split_lock_warn(unsigned long ip) put_cpu(); } +static int split_locks_show(struct seq_file *s, struct task_struct *tsk, + int whole) +{ + u64 detected_split_locks = tsk->detected_split_locks; + + if (whole) { + struct task_struct *t = tsk; + + while_each_thread(tsk, t) { + detected_split_locks += t->detected_split_locks; + } + } + + seq_put_decimal_ull(s, "", detected_split_locks); + seq_putc(s, '\n'); + + return 0; +} + +int proc_pid_split_locks_show(struct seq_file *s, struct pid_namespace *ns, + struct pid *pid, struct task_struct *tsk) +{ + return split_locks_show(s, tsk, 0); +} + +int proc_tgid_split_locks_show(struct seq_file *s, struct pid_namespace *ns, + struct pid *pid, struct task_struct *tsk) +{ + return split_locks_show(s, tsk, 1); +} + bool handle_guest_split_lock(unsigned long ip) { if (sld_state == sld_warn) { diff --git a/fs/proc/base.c b/fs/proc/base.c index dd31e3b6bf77..3c533312dbbc 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -98,6 +98,7 @@ #include <linux/cn_proc.h> #include <linux/ksm.h> #include <trace/events/oom.h> +#include <asm/cpu.h> #include "internal.h" #include "fd.h" @@ -3360,6 +3361,9 @@ static const struct pid_entry tgid_base_stuff[] = { ONE("ksm_merging_pages", S_IRUSR, proc_pid_ksm_merging_pages), ONE("ksm_stat", S_IRUSR, proc_pid_ksm_stat), #endif +#ifdef CONFIG_CPU_SUP_INTEL + ONE("split_locks", S_IRUGO, proc_tgid_split_locks_show), +#endif }; static int proc_tgid_base_readdir(struct file *file, struct dir_context *ctx) @@ -3699,6 +3703,9 @@ static const struct pid_entry tid_base_stuff[] = { ONE("ksm_merging_pages", S_IRUSR, proc_pid_ksm_merging_pages), ONE("ksm_stat", S_IRUSR, proc_pid_ksm_stat), #endif +#ifdef CONFIG_CPU_SUP_INTEL + ONE("split_locks", S_IRUGO, proc_pid_split_locks_show), +#endif }; static int proc_tid_base_readdir(struct file *file, struct dir_context *ctx) diff --git a/include/linux/sched.h b/include/linux/sched.h index 292c31697248..5b9cd4524405 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -957,9 +957,6 @@ struct task_struct { #ifdef CONFIG_IOMMU_SVA unsigned pasid_activated:1; #endif -#ifdef CONFIG_CPU_SUP_INTEL - unsigned reported_split_lock:1; -#endif #ifdef CONFIG_TASK_DELAY_ACCT /* delay due to memory thrashing */ unsigned in_thrashing:1; @@ -1027,6 +1024,9 @@ struct task_struct { u64 stimescaled; #endif u64 gtime; +#ifdef CONFIG_CPU_SUP_INTEL + u64 detected_split_locks; +#endif struct prev_cputime prev_cputime; #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN struct vtime vtime; diff --git a/kernel/fork.c b/kernel/fork.c index 10917c3e1f03..5a0318010dd5 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1188,7 +1188,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) #endif #ifdef CONFIG_CPU_SUP_INTEL - tsk->reported_split_lock = 0; + tsk->detected_split_locks = 0; #endif #ifdef CONFIG_SCHED_MM_CID -- 2.34.1
| |