mm/memory-failure: fix VM_BUG_ON_PAGE(PagePoisoned(page)) when unpoison memory
When I did memory failure tests recently, below panic occurs:
page dumped because: VM_BUG_ON_PAGE(PagePoisoned(page))
kernel BUG at include/linux/page-flags.h:616!
Oops: invalid opcode: 0000 [#1] PREEMPT SMP NOPTI
CPU: 3 PID: 720 Comm: bash Not tainted
6.10.0-rc1-00195-g148743902568 #40
RIP: 0010:unpoison_memory+0x2f3/0x590
RSP: 0018:
ffffa57fc8787d60 EFLAGS:
00000246
RAX:
0000000000000037 RBX:
0000000000000009 RCX:
ffff9be25fcdc9c8
RDX:
0000000000000000 RSI:
0000000000000027 RDI:
ffff9be25fcdc9c0
RBP:
0000000000300000 R08:
ffffffffb4956f88 R09:
0000000000009ffb
R10:
0000000000000284 R11:
ffffffffb4926fa0 R12:
ffffe6b00c000000
R13:
ffff9bdb453dfd00 R14:
0000000000000000 R15:
fffffffffffffffe
FS:
00007f08f04e4740(0000) GS:
ffff9be25fcc0000(0000) knlGS:
0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0:
0000000080050033
CR2:
0000564787a30410 CR3:
000000010d4e2000 CR4:
00000000000006f0
Call Trace:
<TASK>
unpoison_memory+0x2f3/0x590
simple_attr_write_xsigned.constprop.0.isra.0+0xb3/0x110
debugfs_attr_write+0x42/0x60
full_proxy_write+0x5b/0x80
vfs_write+0xd5/0x540
ksys_write+0x64/0xe0
do_syscall_64+0xb9/0x1d0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f08f0314887
RSP: 002b:
00007ffece710078 EFLAGS:
00000246 ORIG_RAX:
0000000000000001
RAX:
ffffffffffffffda RBX:
0000000000000009 RCX:
00007f08f0314887
RDX:
0000000000000009 RSI:
0000564787a30410 RDI:
0000000000000001
RBP:
0000564787a30410 R08:
000000000000fefe R09:
000000007fffffff
R10:
0000000000000000 R11:
0000000000000246 R12:
0000000000000009
R13:
00007f08f041b780 R14:
00007f08f0417600 R15:
00007f08f0416a00
</TASK>
Modules linked in: hwpoison_inject
---[ end trace
0000000000000000 ]---
RIP: 0010:unpoison_memory+0x2f3/0x590
RSP: 0018:
ffffa57fc8787d60 EFLAGS:
00000246
RAX:
0000000000000037 RBX:
0000000000000009 RCX:
ffff9be25fcdc9c8
RDX:
0000000000000000 RSI:
0000000000000027 RDI:
ffff9be25fcdc9c0
RBP:
0000000000300000 R08:
ffffffffb4956f88 R09:
0000000000009ffb
R10:
0000000000000284 R11:
ffffffffb4926fa0 R12:
ffffe6b00c000000
R13:
ffff9bdb453dfd00 R14:
0000000000000000 R15:
fffffffffffffffe
FS:
00007f08f04e4740(0000) GS:
ffff9be25fcc0000(0000) knlGS:
0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0:
0000000080050033
CR2:
0000564787a30410 CR3:
000000010d4e2000 CR4:
00000000000006f0
Kernel panic - not syncing: Fatal exception
Kernel Offset: 0x31c00000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
---[ end Kernel panic - not syncing: Fatal exception ]---
We're hitting a BUG_ON in PF_ANY():
PAGEFLAG(HWPoison, hwpoison, PF_ANY)
#define PF_ANY(page, enforce) PF_POISONED_CHECK(page)
#define PF_POISONED_CHECK(page) ({ \
VM_BUG_ON_PGFLAGS(PagePoisoned(page), page); \
page; })
#define PAGE_POISON_PATTERN -1l
static inline int PagePoisoned(const struct page *page)
{
return READ_ONCE(page->flags) == PAGE_POISON_PATTERN;
}
The offlined pages will have page->flags set to PAGE_POISON_PATTERN
while pfn is still valid:
offline_pages
remove_pfn_range_from_zone
page_init_poison
memset(page, PAGE_POISON_PATTERN, size);
The root cause is that unpoison_memory() tries to check the PG_HWPoison
flags of an uninitialized page. So VM_BUG_ON_PAGE(PagePoisoned(page)) is
triggered. This can be reproduced by below steps:
1.Offline memory block:
echo offline > /sys/devices/system/memory/memory12/state
2.Get offlined memory pfn:
page-types -b n -rlN
3.Write pfn to unpoison-pfn
echo <pfn> > /sys/kernel/debug/hwpoison/unpoison-pfn
Link: https://lkml.kernel.org/r/20240712064249.3882707-1-linmiaohe@huawei.com
Fixes: f165b378bbdf ("mm: uninitialized struct page poisoning sanity checking")
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>