Messages in this thread Patch in this message | | | Date | Wed, 24 Feb 2021 15:16:19 +0800 | From | Aili Yao <> | Subject | [PATCH] mm,hwpoison: return -EBUSY when page already poisoned |
| |
When the page is already poisoned, another memory_failure() call in the same page now return 0, meaning OK. For nested memory mce handling, this behavior may lead real serious problem, Example:
1.When LCME is enabled, and there are two processes A && B running on different core X && Y separately, which will access one same page, then the page corrupted when process A access it, a MCE will be rasied to core X and the error process is just underway.
2.Then B access the page and trigger another MCE to core Y, it will also do error process, it will see TestSetPageHWPoison be true, and 0 is returned.
3.The kill_me_maybe will check the return:
1244 static void kill_me_maybe(struct callback_head *cb) 1245 {
1254 if (!memory_failure(p->mce_addr >> PAGE_SHIFT, flags) && 1255 !(p->mce_kflags & MCE_IN_KERNEL_COPYIN)) { 1256 set_mce_nospec(p->mce_addr >> PAGE_SHIFT, p->mce_whole_page); 1257 sync_core(); 1258 return; 1259 }
1267 }
4. The error process for B will end, and may nothing happened if kill-early is not set, We may let the wrong data go into effect.
For other cases which care the return value of memory_failure() should check why they want to process a memory error which have already been processed. This behavior seems reasonable.
In kill_me_maybe, log the fact about the memory may not recovered, and we will kill the related process.
Signed-off-by: Aili Yao <yaoaili@kingsoft.com> --- arch/x86/kernel/cpu/mce/core.c | 2 ++ mm/memory-failure.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c index e133ce1e562b..db4afc5bf15a 100644 --- a/arch/x86/kernel/cpu/mce/core.c +++ b/arch/x86/kernel/cpu/mce/core.c @@ -1259,6 +1259,8 @@ static void kill_me_maybe(struct callback_head *cb) } if (p->mce_vaddr != (void __user *)-1l) { + pr_err("Memory error may not recovered: %#lx: Sending SIGBUS to %s:%d due to hardware memory corruption\n", + p->mce_addr >> PAGE_SHIFT, p->comm, p->pid); force_sig_mceerr(BUS_MCEERR_AR, p->mce_vaddr, PAGE_SHIFT); } else { pr_err("Memory error not recovered"); diff --git a/mm/memory-failure.c b/mm/memory-failure.c index e9481632fcd1..06f006174b8c 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1224,7 +1224,7 @@ static int memory_failure_hugetlb(unsigned long pfn, int flags) if (TestSetPageHWPoison(head)) { pr_err("Memory failure: %#lx: already hardware poisoned\n", pfn); - return 0; + return -EBUSY; } num_poisoned_pages_inc(); @@ -1420,7 +1420,7 @@ int memory_failure(unsigned long pfn, int flags) if (TestSetPageHWPoison(p)) { pr_err("Memory failure: %#lx: already hardware poisoned\n", pfn); - return 0; + return -EBUSY; } orig_head = hpage = compound_head(p); -- 2.25.1
| |