From: Tobias Huschle Date: Mon, 12 Aug 2024 11:39:29 +0000 (+0200) Subject: s390/wti: Add wti accounting for missed grace periods X-Git-Tag: v6.12-rc1~113^2~30 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=42419bcdfdcb287918e53500a04aeb532b41ed1f;p=thirdparty%2Fkernel%2Flinux.git s390/wti: Add wti accounting for missed grace periods A virtual CPU that has received a warning-track interrupt may fail to acknowledge the interrupt within the warning-track grace period. While this is usually not a problem, it will become necessary to investigate if there is a large number of such missed warning-track interrupts. Therefore, it is necessary to track these events. The information is tracked through the s390 debug facility and can be found under /sys/kernel/debug/s390dbf/wti/. The hex_ascii output is formatted as: The values pid and current psw are collected when a warning track interrupt is received. Symbol is either the kernel symbol matching the collected psw or redacted to when running in user space. Each line represents the currently executing process when a warning track interrupt was received which was then not acknowledged within its grace period. Acked-by: Heiko Carstens Reviewed-by: Mete Durlu Signed-off-by: Tobias Huschle Signed-off-by: Vasily Gorbik --- diff --git a/arch/s390/kernel/wti.c b/arch/s390/kernel/wti.c index 3abae3908e65f..da8bbffbed9d9 100644 --- a/arch/s390/kernel/wti.c +++ b/arch/s390/kernel/wti.c @@ -5,13 +5,25 @@ * Copyright IBM Corp. 2023 */ +#include #include #include #include +#include #include #include +#define WTI_DBF_LEN 64 + +struct wti_debug { + unsigned long missed; + unsigned long addr; + pid_t pid; +}; + struct wti_state { + /* debug data for s390dbf */ + struct wti_debug dbg; /* * Represents the real-time thread responsible to * acknowledge the warning-track interrupt and trigger @@ -27,6 +39,8 @@ struct wti_state { static DEFINE_PER_CPU(struct wti_state, wti_state); +static debug_info_t *wti_dbg; + /* * During a warning-track grace period, interrupts are disabled * to prevent delays of the warning-track acknowledgment. @@ -61,6 +75,16 @@ static void wti_irq_enable(void) local_irq_restore(flags); } +static void store_debug_data(struct wti_state *st) +{ + struct pt_regs *regs = get_irq_regs(); + + st->dbg.pid = current->pid; + st->dbg.addr = 0; + if (!user_mode(regs)) + st->dbg.addr = regs->psw.addr; +} + static void wti_interrupt(struct ext_code ext_code, unsigned int param32, unsigned long param64) { @@ -68,6 +92,7 @@ static void wti_interrupt(struct ext_code ext_code, inc_irq_stat(IRQEXT_WTI); wti_irq_disable(); + store_debug_data(st); st->pending = true; wake_up_process(st->thread); } @@ -79,6 +104,19 @@ static int wti_pending(unsigned int cpu) return st->pending; } +static void wti_dbf_grace_period(struct wti_state *st) +{ + struct wti_debug *wdi = &st->dbg; + char buf[WTI_DBF_LEN]; + + if (wdi->addr) + snprintf(buf, sizeof(buf), "%d %pS", wdi->pid, (void *)wdi->addr); + else + snprintf(buf, sizeof(buf), "%d ", wdi->pid); + debug_text_event(wti_dbg, 2, buf); + wdi->missed++; +} + static void wti_thread_fn(unsigned int cpu) { struct wti_state *st = per_cpu_ptr(&wti_state, cpu); @@ -89,7 +127,8 @@ static void wti_thread_fn(unsigned int cpu) * resumes when hypervisor decides to dispatch CPU * to this LPAR again. */ - diag49c(DIAG49C_SUBC_ACK); + if (diag49c(DIAG49C_SUBC_ACK)) + wti_dbf_grace_period(st); wti_irq_enable(); } @@ -129,7 +168,17 @@ static int __init wti_init(void) rc = -EOPNOTSUPP; goto out_subclass; } + wti_dbg = debug_register("wti", 1, 1, WTI_DBF_LEN); + if (!wti_dbg) { + rc = -ENOMEM; + goto out_debug_register; + } + rc = debug_register_view(wti_dbg, &debug_hex_ascii_view); + if (rc) + goto out_debug_register; goto out; +out_debug_register: + debug_unregister(wti_dbg); out_subclass: irq_subclass_unregister(IRQ_SUBCLASS_WARNING_TRACK); unregister_external_irq(EXT_IRQ_WARNING_TRACK, wti_interrupt);