[PATCH v3 OLK-6.6 0/8] arm64: Add memory poison recovery support for various paths
This series enhances the arm64 kernel's ability to recover from memory poison (hardware memory errors) encountered during common I/O and data copy operations. The work extends the existing RAS error handling framework to gracefully handle poison in scenarios that previously could lead to kernel panics or silent data corruption. Memory errors are increasingly common in large-scale deployments; recovering from them where possible improves system reliability and availability. The patches implement recovery in key paths such as copy_{from/to}_user, iov_iter, __kernel_read, and shmem_file_read_iter, ensuring that when poison is consumed, the kernel can either complete the operation safely (by returning an error) or deliver the appropriate signal to the affected user process. Additionally, the series refines the SEA (Synchronous External Abort) handling path: it moves siaddr extraction earlier for accurate signal info, adds RAS logging for better diagnostics, and ensures a SIGBUS is sent to user tasks when APEI claims fail. The series has been tested on ARM64 platforms with RAS capabilities, using error injection to verify that poison is correctly handled and that appropriate errors or signals are delivered. Feedback and review are appreciated. Changelog since v1: - use correct issue Changelog since v2: - fix compile error on arm Linus Torvalds (1): iov_iter: get rid of 'copy_mc' flag Wupeng Ma (7): arm64: mm: support recovery from copy_{from/to}_user_page() iov_iter: add mc support for copy_page_to_iter arm64: fs: support poison recovery from __kernel_read() arm64: mm: shmem: support poison recovery from shmem_file_read_iter() arm64: move getting valid siaddr to the top of do_sea arm64: add ras log during do_sea arm64: send sig fault for user task when apei_claim_sea fails arch/arm/include/asm/cacheflush.h | 2 ++ arch/arm64/include/asm/cacheflush.h | 7 +++++ arch/arm64/kernel/acpi.c | 2 ++ arch/arm64/mm/extable.c | 5 +++- arch/arm64/mm/fault.c | 46 ++++++++++++++++++++++------- arch/arm64/mm/flush.c | 11 +++++++ fs/coredump.c | 45 ++++++++++++++++++++++++++-- include/asm-generic/cacheflush.h | 24 +++++++++++++++ lib/iov_iter.c | 16 ++++++++-- mm/filemap.c | 3 ++ mm/memory.c | 15 +++++++--- mm/shmem.c | 4 +++ 12 files changed, 160 insertions(+), 20 deletions(-) -- 2.43.0
From: Linus Torvalds <torvalds@linux-foundation.org> mainline inclusion from mainline-v6.8-rc0 commit a50026bdb867c8caf9d29e18f9fe9e1390312619 category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/8386 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- This flag is only set by one single user: the magical core dumping code that looks up user pages one by one, and then writes them out using their kernel addresses (by using a BVEC_ITER). That actually ends up being a huge problem, because while we do use copy_mc_to_kernel() for this case and it is able to handle the possible machine checks involved, nothing else is really ready to handle the failures caused by the machine check. In particular, as reported by Tong Tiangen, we don't actually support fault_in_iov_iter_readable() on a machine check area. As a result, the usual logic for writing things to a file under a filesystem lock, which involves doing a copy with page faults disabled and then if that fails trying to fault pages in without holding the locks with fault_in_iov_iter_readable() does not work at all. We could decide to always just make the MC copy "succeed" (and filling the destination with zeroes), and that would then create a core dump file that just ignores any machine checks. But honestly, this single special case has been problematic before, and means that all the normal iov_iter code ends up slightly more complex and slower. See for example commit c9eec08bac96 ("iov_iter: Don't deal with iter->copy_mc in memcpy_from_iter_mc()") where David Howells re-organized the code just to avoid having to check the 'copy_mc' flags inside the inner iov_iter loops. So considering that we have exactly one user, and that one user is a non-critical special case that doesn't actually ever trigger in real life (Tong found this with manual error injection), the sane solution is to just decide that the onus on handling the machine check lines on that user instead. Ergo, do the copy_mc_to_kernel() in the core dump logic itself, copying the user data to a stable kernel page before writing it out. Fixes: f1982740f5e7 ("iov_iter: Convert iterate*() to inline funcs") Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Tong Tiangen <tongtiangen@huawei.com> Link: https://lore.kernel.org/r/20240305133336.3804360-1-tongtiangen@huawei.com Link: https://lore.kernel.org/all/4e80924d-9c85-f13a-722a-6a5d2b1c225a@huawei.com/ Tested-by: David Howells <dhowells@redhat.com> Reviewed-by: David Howells <dhowells@redhat.com> Reviewed-by: Jens Axboe <axboe@kernel.dk> Reported-by: Tong Tiangen <tongtiangen@huawei.com> Signed-off-by: Christian Brauner <brauner@kernel.org> Conflicts: include/linux/uio.h lib/iov_iter.c [Ma Wupeng: keep copy_mc related code since its need and only backport new mcs for dump_user_range to break out if one page failred] Signed-off-by: Wupeng Ma <mawupeng1@huawei.com> --- fs/coredump.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/fs/coredump.c b/fs/coredump.c index 737fff8a930e6..68cef59bf022e 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -875,6 +875,9 @@ static int dump_emit_page(struct coredump_params *cprm, struct page *page) loff_t pos; ssize_t n; + if (!page) + return 0; + if (cprm->to_skip) { if (!__dump_skip(cprm, cprm->to_skip)) return 0; @@ -887,7 +890,6 @@ static int dump_emit_page(struct coredump_params *cprm, struct page *page) pos = file->f_pos; bvec_set_page(&bvec, page, PAGE_SIZE, 0); iov_iter_bvec(&iter, ITER_SOURCE, &bvec, 1, PAGE_SIZE); - iov_iter_set_copy_mc(&iter); n = __kernel_write_iter(cprm->file, &iter, &pos); if (n != PAGE_SIZE) return 0; @@ -898,10 +900,44 @@ static int dump_emit_page(struct coredump_params *cprm, struct page *page) return 1; } +/* + * If we might get machine checks from kernel accesses during the + * core dump, let's get those errors early rather than during the + * IO. This is not performance-critical enough to warrant having + * all the machine check logic in the iovec paths. + */ +#ifdef copy_mc_to_kernel + +#define dump_page_alloc() alloc_page(GFP_KERNEL) +#define dump_page_free(x) __free_page(x) +static struct page *dump_page_copy(struct page *src, struct page *dst) +{ + void *buf = kmap_local_page(src); + size_t left = copy_mc_to_kernel(page_address(dst), buf, PAGE_SIZE); + kunmap_local(buf); + return left ? NULL : dst; +} + +#else + +/* We just want to return non-NULL; it's never used. */ +#define dump_page_alloc() ERR_PTR(-EINVAL) +#define dump_page_free(x) ((void)(x)) +static inline struct page *dump_page_copy(struct page *src, struct page *dst) +{ + return src; +} +#endif + int dump_user_range(struct coredump_params *cprm, unsigned long start, unsigned long len) { unsigned long addr; + struct page *dump_page; + + dump_page = dump_page_alloc(); + if (!dump_page) + return 0; for (addr = start; addr < start + len; addr += PAGE_SIZE) { struct page *page; @@ -915,14 +951,17 @@ int dump_user_range(struct coredump_params *cprm, unsigned long start, */ page = get_dump_page(addr); if (page) { - int stop = !dump_emit_page(cprm, page); + int stop = !dump_emit_page(cprm, dump_page_copy(page, dump_page)); put_page(page); - if (stop) + if (stop) { + dump_page_free(dump_page); return 0; + } } else { dump_skip(cprm, PAGE_SIZE); } } + dump_page_free(dump_page); return 1; } #endif -- 2.43.0
hulk inclusion category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/8386 ------------------------------------------ During our test. kernel panic with the following trace: Internal error: synchronous external abort: 0000000096000410 [#1] SMP pc : __memcpy+0x70/0x230 lr : __access_remote_vm+0x1ac/0x390 Call trace: __memcpy+0x70/0x230 access_remote_vm+0x18/0x30 proc_pid_cmdline_read+0x1ac/0x490 vfs_read+0xcc/0x2b8 ksys_read+0x78/0x118 __arm64_sys_read+0x24/0x38 Kernel panic due to UCE happens during page copy. Similar to other poison recovery, use memcpy_mc() to avoid potentially kernel panic during copy page in access_remote_vm(). Signed-off-by: Wupeng Ma <mawupeng1@huawei.com> --- arch/arm/include/asm/cacheflush.h | 2 ++ arch/arm64/include/asm/cacheflush.h | 7 +++++++ arch/arm64/mm/flush.c | 11 +++++++++++ include/asm-generic/cacheflush.h | 24 ++++++++++++++++++++++++ mm/memory.c | 15 +++++++++++---- 5 files changed, 55 insertions(+), 4 deletions(-) diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 1075534b0a2ee..d6901be1c2490 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -473,4 +473,6 @@ void check_cpu_icache_size(int cpuid); static inline void check_cpu_icache_size(int cpuid) { } #endif +#include <asm-generic/cacheflush.h> + #endif diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h index d115451ed263d..722faacae055d 100644 --- a/arch/arm64/include/asm/cacheflush.h +++ b/arch/arm64/include/asm/cacheflush.h @@ -113,6 +113,13 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *, unsigned long, void *, const void *, unsigned long); #define copy_to_user_page copy_to_user_page +extern int copy_mc_to_user_page(struct vm_area_struct *, struct page *, + unsigned long, void *, const void *, unsigned long); +#define copy_mc_to_user_page copy_mc_to_user_page + +#define copy_mc_from_user_page(vma, page, vaddr, dst, src, len) \ + memcpy_mc(dst, src, len) + /* * flush_dcache_folio is used when the kernel has written to the page * cache page at virtual address page->virtual. diff --git a/arch/arm64/mm/flush.c b/arch/arm64/mm/flush.c index 013eead9b6950..cbb3cf20fc7c5 100644 --- a/arch/arm64/mm/flush.c +++ b/arch/arm64/mm/flush.c @@ -49,6 +49,17 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page, flush_ptrace_access(vma, (unsigned long)dst, (unsigned long)dst + len); } +int copy_mc_to_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long uaddr, void *dst, const void *src, + unsigned long len) +{ + if (memcpy_mc(dst, src, len)) + return -EHWPOISON; + + flush_ptrace_access(vma, (unsigned long)dst, (unsigned long)dst + len); + return 0; +} + void __sync_icache_dcache(pte_t pte) { struct folio *folio = page_folio(pte_page(pte)); diff --git a/include/asm-generic/cacheflush.h b/include/asm-generic/cacheflush.h index 7ee8a179d1036..2a20f4ed6a316 100644 --- a/include/asm-generic/cacheflush.h +++ b/include/asm-generic/cacheflush.h @@ -124,4 +124,28 @@ static inline void flush_cache_vunmap(unsigned long start, unsigned long end) } while (0) #endif +#ifndef copy_mc_to_user_page +static inline int copy_mc_to_user_page(struct vm_area_struct *vma, + struct page *page, unsigned long vaddr, + void *dst, const void *src, + unsigned long len) +{ + copy_to_user_page(vma, page, vaddr, dst, src, len); + return 0; +} +#define copy_mc_to_user_page copy_mc_to_user_page +#endif + +#ifndef copy_mc_from_user_page +static inline int copy_mc_from_user_page(struct vm_area_struct *vma, + struct page *page, unsigned long vaddr, + void *dst, const void *src, + unsigned long len) +{ + copy_from_user_page(vma, page, vaddr, dst, src, len); + return 0; +} +#define copy_mc_from_user_page copy_mc_from_user_page +#endif + #endif /* _ASM_GENERIC_CACHEFLUSH_H */ diff --git a/mm/memory.c b/mm/memory.c index b1e9745ae085f..70f979d82ed5d 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -6657,6 +6657,7 @@ int __access_remote_vm(struct mm_struct *mm, unsigned long addr, void *buf, if (bytes <= 0) break; } else { + int ret = 0; bytes = len; offset = addr & (PAGE_SIZE-1); if (bytes > PAGE_SIZE-offset) @@ -6664,15 +6665,21 @@ int __access_remote_vm(struct mm_struct *mm, unsigned long addr, void *buf, maddr = kmap(page); if (write) { - copy_to_user_page(vma, page, addr, - maddr + offset, buf, bytes); - set_page_dirty_lock(page); + ret = copy_mc_to_user_page(vma, page, addr, + maddr + offset, + buf, bytes); + if (!ret) + set_page_dirty_lock(page); } else { - copy_from_user_page(vma, page, addr, + ret = copy_mc_from_user_page(vma, page, addr, buf, maddr + offset, bytes); } kunmap(page); put_page(page); + if (ret) { + mmap_read_unlock(mm); + return 0; + } } len -= bytes; buf += bytes; -- 2.43.0
hulk inclusion category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/8386 ------------------------------------------ Introduce machine check safe support for copy_page_to_iter. Compare to vanila copy_page_to_iter, it will return short copy for ITER_KVEC & ITER_BVEC as _copy_mc_to_iter explained. Signed-off-by: Wupeng Ma <mawupeng1@huawei.com> --- lib/iov_iter.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/iov_iter.c b/lib/iov_iter.c index d6620eaa95153..0b8fc9831225e 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -465,10 +465,15 @@ static inline bool page_copy_sane(struct page *page, size_t offset, size_t n) return true; } +/* + * return short copy for ITER_KVEC & ITER_BVEC as _copy_mc_to_iter + * explained for iov_iter_is_copy_mc. + */ size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, struct iov_iter *i) { size_t res = 0; + const bool mc = iov_iter_is_copy_mc(i); if (!page_copy_sane(page, offset, bytes)) return 0; if (WARN_ON_ONCE(i->data_source)) @@ -477,13 +482,20 @@ size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, offset %= PAGE_SIZE; while (1) { void *kaddr = kmap_local_page(page); - size_t n = min(bytes, (size_t)PAGE_SIZE - offset); - n = _copy_to_iter(kaddr + offset, n, i); + size_t need_copied = min(bytes, (size_t)PAGE_SIZE - offset); + size_t n; + + if (!mc) + n = _copy_to_iter(kaddr + offset, need_copied, i); + else + n = _copy_mc_to_iter(kaddr + offset, need_copied, i); kunmap_local(kaddr); res += n; bytes -= n; if (!bytes || !n) break; + if (mc && (n != need_copied)) + break; offset += n; if (offset == PAGE_SIZE) { page++; -- 2.43.0
hulk inclusion category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/8386 ------------------------------------------ During our test. kernel panic with the following trace: Internal error: synchronous external abort: 0000000096000410 [#1] SMP pc : __memcpy+0x110/0x240 lr : _copy_to_iter+0x3c4/0x4d0 Call trace: __memcpy+0x110/0x240 copy_page_to_iter+0xbc/0x160 filemap_read+0x1b0/0x390 generic_file_read_iter+0xdc/0x158 ext4_file_read_iter+0x5c/0x230 [ext4] __kernel_read+0xc0/0x250 kernel_read+0x70/0xc0 search_binary_handler+0x5c/0x318 exec_binprm+0x58/0x1b8 bprm_execve+0xc0/0x140 do_execveat_common.isra.0+0x19c/0x240 __arm64_sys_execve+0x48/0x68 invoke_syscall+0x50/0x128 el0_svc_common.constprop.0+0xc8/0xf0 do_el0_svc+0x24/0x38 Kernel panic due to UCE happens during page copy. Similar to other poison recovery, use iov_iter_set_copy_mc() to avoid potentially kernel panic during copy page in filemap_read(). As copy page/folio will return short if copy failed, this kind of error can be properly handled after and EFAULT will be return to the caller. Signed-off-by: Wupeng Ma <mawupeng1@huawei.com> --- mm/filemap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm/filemap.c b/mm/filemap.c index a94d7dd3f0ff4..739e1fcd7d72f 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2730,6 +2730,9 @@ ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *iter, if (writably_mapped) flush_dcache_folio(folio); + if (IS_ENABLED(CONFIG_ARM64) && iov_iter_is_kvec(iter)) + iov_iter_set_copy_mc(iter); + copied = copy_folio_to_iter(folio, offset, bytes, iter); already_read += copied; -- 2.43.0
hulk inclusion category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/8386 ------------------------------------------ During our test. kernel panic with the following trace: Internal error: synchronous external abort: ffffffff96000410 [#1] SMP CPU: 0 PID: 3785 Comm: kworker/u2:4 Not tainted 5.10.0 #21 pstate: 20400009 (nzCv daif +PAN -UAO -TCO BTYPE=--) pc : __memcpy+0x100/0x180 lr : _copy_to_iter+0x308/0x3a0 Call trace: __memcpy+0x100/0x180 copy_page_to_iter+0x148/0x200 shmem_file_read_iter+0x1ec/0x460 __kernel_read+0xfc/0x2b0 kernel_read+0x5c/0x80 search_binary_handler+0x58/0x354 exec_binprm+0x58/0x1d0 bprm_execve.part.0+0xe4/0x16c bprm_execve+0x74/0xc0 kernel_execve+0x138/0x1a0 call_usermodehelper_exec_async+0x13c/0x250 ret_from_fork+0x10/0x18 Kernel panic due to UCE happens during page copy. Similar to other poison recovery, use iov_iter_set_copy_mc() to avoid potentially kernel panic during copy page in shmem_file_read_iter(). As copy page/folio will return short if copy failed, this kind of error can be properly handled after and EFAULT will be return to the caller. Signed-off-by: Wupeng Ma <mawupeng1@huawei.com> --- mm/shmem.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mm/shmem.c b/mm/shmem.c index 918f28f64b69d..f3fa118d0d5d1 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -3330,6 +3330,10 @@ static ssize_t shmem_file_read_iter(struct kiocb *iocb, struct iov_iter *to) */ if (!offset) folio_mark_accessed(folio); + + if (IS_ENABLED(CONFIG_ARM64) && iov_iter_is_kvec(to)) + iov_iter_set_copy_mc(to); + /* * Ok, we have the page, and it's up-to-date, so * now we can copy it to user space... -- 2.43.0
hulk inclusion category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/8386 ------------------------------------------ Move getting valid siaddr to the top of do_sea in preparation for dump valid siaddr if apei_claim_sea failed. Signed-off-by: Wupeng Ma <mawupeng1@huawei.com> --- arch/arm64/mm/fault.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 7ed7cb7bf1dfe..0211836229839 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -866,9 +866,6 @@ static int do_sea(unsigned long far, unsigned long esr, struct pt_regs *regs) const struct fault_info *inf; unsigned long siaddr; - if (do_apei_claim_sea(regs)) - return 0; - inf = esr_to_fault_info(esr); if (esr & ESR_ELx_FnV) { siaddr = 0; @@ -881,6 +878,10 @@ static int do_sea(unsigned long far, unsigned long esr, struct pt_regs *regs) siaddr = untagged_addr(far); } add_taint(TAINT_MACHINE_CHECK, LOCKDEP_STILL_OK); + + if (do_apei_claim_sea(regs)) + return 0; + arm64_notify_die(inf->name, regs, inf->sig, inf->code, siaddr, esr); return 0; -- 2.43.0
hulk inclusion category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/8386 ------------------------------------------ Enhance the logging within the do_sea by adding more locatable log entries to facilitate issue diagnosis and troubleshooting within that specific function. Fixes: 9c72f69e011e ("arm64: add support for ARCH_HAS_COPY_MC") Signed-off-by: Wupeng Ma <mawupeng1@huawei.com> --- arch/arm64/kernel/acpi.c | 2 ++ arch/arm64/mm/extable.c | 5 ++++- arch/arm64/mm/fault.c | 26 +++++++++++++++++++------- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index dba8fcec7f33d..68860df660af2 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -405,6 +405,8 @@ int apei_claim_sea(struct pt_regs *regs) local_daif_restore(current_flags); + if (err) + pr_warn_ratelimited("ghes_notify_sea failed, err: %d\n", err); return err; } diff --git a/arch/arm64/mm/extable.c b/arch/arm64/mm/extable.c index 8c690ae619445..f6ca49ae79378 100644 --- a/arch/arm64/mm/extable.c +++ b/arch/arm64/mm/extable.c @@ -84,8 +84,10 @@ bool fixup_exception_me(struct pt_regs *regs) const struct exception_table_entry *ex; ex = search_exception_tables(instruction_pointer(regs)); - if (!ex) + if (!ex) { + pr_warn_ratelimited("fixup search failed\n"); return false; + } switch (ex->type) { case EX_TYPE_UACCESS_ERR_ZERO: @@ -93,5 +95,6 @@ bool fixup_exception_me(struct pt_regs *regs) return ex_handler_uaccess_err_zero(ex, regs); } + pr_warn_ratelimited("fixup type: %d invalid\n", ex->type); return false; } diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 0211836229839..69c8138f3e7ac 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -846,18 +846,30 @@ static int do_bad(unsigned long far, unsigned long esr, struct pt_regs *regs) * APEI claimed this as a firmware-first notification. * Some processing deferred to task_work before ret_to_user(). */ -static bool do_apei_claim_sea(struct pt_regs *regs) +static bool do_apei_claim_sea(unsigned long esr, struct pt_regs *regs, + unsigned long siaddr) { if (user_mode(regs)) { if (!apei_claim_sea(regs)) return true; - } else if (IS_ENABLED(CONFIG_ARCH_HAS_COPY_MC)) { - if (sysctl_machine_check_safe && - fixup_exception_me(regs) && - !apei_claim_sea(regs)) - return true; + + return false; } + if (!IS_ENABLED(CONFIG_ARCH_HAS_COPY_MC) || !sysctl_machine_check_safe) + return false; + + pr_warn_ratelimited("%s, addr: %#lx comm: %.20s tgid: %d pid: %d cpu: %d\n", + user_mode(regs) ? "userspace" : "kernelspace", siaddr, + current->comm, current->tgid, current->pid, + raw_smp_processor_id()); + + if (!fixup_exception_me(regs)) + return false; + + if (apei_claim_sea(regs)) + return true; + return false; } @@ -879,7 +891,7 @@ static int do_sea(unsigned long far, unsigned long esr, struct pt_regs *regs) } add_taint(TAINT_MACHINE_CHECK, LOCKDEP_STILL_OK); - if (do_apei_claim_sea(regs)) + if (do_apei_claim_sea(esr, regs, siaddr)) return 0; arm64_notify_die(inf->name, regs, inf->sig, inf->code, siaddr, esr); -- 2.43.0
hulk inclusion category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/8386 ------------------------------------------ During do_sea, kernel will panic if no info is reported to kernel since apei_claim_sea failed. However, for user task, sig fault can be send to which can avoid kernel panic. Signed-off-by: Wupeng Ma <mawupeng1@huawei.com> --- arch/arm64/mm/fault.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 69c8138f3e7ac..e1a54a195d7a1 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -847,8 +847,10 @@ static int do_bad(unsigned long far, unsigned long esr, struct pt_regs *regs) * Some processing deferred to task_work before ret_to_user(). */ static bool do_apei_claim_sea(unsigned long esr, struct pt_regs *regs, - unsigned long siaddr) + unsigned long siaddr, int sig, int code) { + int err; + if (user_mode(regs)) { if (!apei_claim_sea(regs)) return true; @@ -867,10 +869,21 @@ static bool do_apei_claim_sea(unsigned long esr, struct pt_regs *regs, if (!fixup_exception_me(regs)) return false; - if (apei_claim_sea(regs)) + err = apei_claim_sea(regs); + if (!err) return true; - return false; + pr_emerg("comm: %s pid: %d apei claim sea failed. addr: %#lx, esr: %#lx\n", + current->comm, current->pid, siaddr, esr); + + if (!current->mm) + return true; + + set_thread_esr(0, esr); + arm64_force_sig_fault(sig, code, siaddr, + "Uncorrected memory error on access to user memory\n"); + + return true; } static int do_sea(unsigned long far, unsigned long esr, struct pt_regs *regs) @@ -891,7 +904,7 @@ static int do_sea(unsigned long far, unsigned long esr, struct pt_regs *regs) } add_taint(TAINT_MACHINE_CHECK, LOCKDEP_STILL_OK); - if (do_apei_claim_sea(esr, regs, siaddr)) + if (do_apei_claim_sea(esr, regs, siaddr, inf->sig, inf->code)) return 0; arm64_notify_die(inf->name, regs, inf->sig, inf->code, siaddr, esr); -- 2.43.0
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://atomgit.com/openeuler/kernel/merge_requests/20939 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/RT4... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://atomgit.com/openeuler/kernel/merge_requests/20939 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/RT4...
participants (2)
-
patchwork bot -
Wupeng Ma