hulk inclusion category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/8787 ------------------------------------------ This patch introduces a mm flag MMF_RAS_CRITICAL to identify processes that have triggered critical RAS (Reliability, Availability, Serviceability) events. When a severe RAS scenario (e.g., unrecoverable memory error) is detected, this flag is set on the mm of the faulting process to indicate its critical context. This is a preparatory patch to enable subsequent changes that will leverage this flag to: - Skip non-essential error handling paths - Avoid redundant diagnostic operations - Reduce latency spikes during critical RAS scenarios Signed-off-by: Wupeng Ma <mawupeng1@huawei.com> --- drivers/acpi/apei/Kconfig | 5 ++++ drivers/acpi/apei/ghes.c | 52 ++++++++++++++++++++++++++++++++-- include/linux/mm.h | 12 ++++++++ include/linux/sched/coredump.h | 6 ++++ 4 files changed, 72 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig index cf799e7b68bf..d090a3171492 100644 --- a/drivers/acpi/apei/Kconfig +++ b/drivers/acpi/apei/Kconfig @@ -43,6 +43,11 @@ config ACPI_APEI_GHES_ARMP_VENDOR_INFO for platform-related fault status to handle system failures. This functionality requires support from both the chip and the firmware. +config ACPI_APEI_RAS_CRITICAL + bool + depends on ACPI_APEI_GHES_ARMP_VENDOR_INFO && NUMA_REMOTE + default y + config ACPI_APEI_GHES_NOTIFY_ALL_RAS_ERR bool "Notify all ras err to driver" depends on ARM64 && ACPI_APEI_GHES diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 925355f156b6..49d3cbe09f2c 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -48,6 +48,7 @@ #include <asm/fixmap.h> #include <asm/tlbflush.h> #include <ras/ras_event.h> +#include <linux/numa_remote.h> #include "apei-internal.h" @@ -461,6 +462,46 @@ static void ghes_clear_estatus(struct ghes *ghes, ghes_ack_error(ghes->generic_v2); } +/* + * This function is utilized in both virtualized and non-virtualized environments. + * + * In standard non-virtualized (bare-metal) mode, it triggers the termination of the + * process accessing the faulty memory. + * + * In virtualized scenarios (KVM): + * - For Synchronous External Aborts (SEA), this function is invoked via + * apei_claim_sea() from within kvm_handle_guest_sea(). + * - If the error is successfully handled by the host, KVM injects the fault into + * the guest OS using kvm_inject_vabt(). + * - In exceptional cases where the guest cannot handle the injected exception, + * terminating the corresponding host process (e.g., the VMM/QEMU task) is the + * expected behavior to ensure system stability. + */ +static void ghes_handle_critical_ras(unsigned long pfn) +{ + struct mm_struct *mm = current->mm; + struct page *p; + int nid; + + if (!IS_ENABLED(CONFIG_ACPI_APEI_RAS_CRITICAL)) + return; + + p = pfn_to_online_page(pfn); + if (!p) + return; + + nid = page_to_nid(p); + if (!numa_is_remote_node(nid)) + return; + + if (test_bit(MMF_CRITICAL_ERR, &mm->flags)) + return; + + set_bit(MMF_CRITICAL_ERR, &mm->flags); + pr_warn_ratelimited(GHES_PFX "detected critical ras on pfn: %#lx, nid: %d, comm: %s, pid: %d, tgid: %d\n", + pfn, nid, current->comm, current->pid, current->tgid); +} + /* * struct sync_task_work - for synchronous RAS event * @@ -494,7 +535,7 @@ static void memory_failure_cb(struct callback_head *twork) gen_pool_free(ghes_estatus_pool, (unsigned long)twcb, sizeof(*twcb)); } -static bool ghes_do_memory_failure(u64 physical_addr, int flags) +static bool ghes_do_memory_failure(u64 physical_addr, int flags, bool critical) { unsigned long pfn; struct sync_task_work *twcb; @@ -511,6 +552,9 @@ static bool ghes_do_memory_failure(u64 physical_addr, int flags) } if (flags == MF_ACTION_REQUIRED && current->mm) { + if (critical) + ghes_handle_critical_ras(pfn); + twcb = (void *)gen_pool_alloc(ghes_estatus_pool, sizeof(*twcb)); if (!twcb) return false; @@ -547,7 +591,7 @@ static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, flags = sync ? MF_ACTION_REQUIRED : 0; if (flags != -1) - return ghes_do_memory_failure(mem_err->physical_addr, flags); + return ghes_do_memory_failure(mem_err->physical_addr, flags, false); return false; } @@ -559,6 +603,7 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, int flags = sync ? MF_ACTION_REQUIRED : 0; bool queued = false; int sec_sev, i; + bool critical; char *p; sec_sev = ghes_severity(gdata->error_severity); @@ -571,6 +616,7 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, return false; p = (char *)(err + 1); + critical = ghes_armp_vendor_critical_error(err, sync); for (i = 0; i < err->err_info_num; i++) { struct cper_arm_err_info *err_info = (struct cper_arm_err_info *)p; bool is_cache = (err_info->type == CPER_ARM_CACHE_ERROR); @@ -584,7 +630,7 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, * and don't filter out 'corrected' error here. */ if (is_cache && has_pa) { - queued = ghes_do_memory_failure(err_info->physical_fault_addr, flags); + queued = ghes_do_memory_failure(err_info->physical_fault_addr, flags, critical); p += err_info->length; continue; } diff --git a/include/linux/mm.h b/include/linux/mm.h index eeb1bf1b36c9..f52ed8b4cf36 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -4455,4 +4455,16 @@ static inline bool vma_is_peer_shared(struct vm_area_struct *vma) } #endif +#ifdef CONFIG_ACPI_APEI_RAS_CRITICAL +static inline bool mm_is_critical_error(struct mm_struct *mm) +{ + return mm && test_bit(MMF_CRITICAL_ERR, &mm->flags); +} +#else +static inline bool mm_is_critical_error(struct mm_struct *mm) +{ + return false; +} +#endif + #endif /* _LINUX_MM_H */ diff --git a/include/linux/sched/coredump.h b/include/linux/sched/coredump.h index 1b37fa8fc723..28d71cc496bc 100644 --- a/include/linux/sched/coredump.h +++ b/include/linux/sched/coredump.h @@ -93,6 +93,12 @@ static inline int get_dumpable(struct mm_struct *mm) #define MMF_VM_MERGE_ANY 29 #define MMF_HAS_MDWE_NO_INHERIT 30 +#ifdef CONFIG_ACPI_APEI_RAS_CRITICAL +#define MMF_CRITICAL_ERR 63 +#else +#define MMF_CRITICAL_ERR 0 +#endif + static inline unsigned long mmf_init_flags(unsigned long flags) { if (flags & (1UL << MMF_HAS_MDWE_NO_INHERIT)) -- 2.43.0