On 2024/12/20 16:50, David Hildenbrand wrote: > On 20.12.24 03:35, Miaohe Lin wrote: >> On 2024/12/19 20:18, David Hildenbrand wrote: >>> On 19.12.24 12:52, Miaohe Lin wrote: >>>> 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 ]--- >>>> >>>> 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 >>>> >>>> Signed-off-by: Miaohe Lin <linmiaohe@xxxxxxxxxx> >>>> --- >>>> v2: Use pfn_to_online_page per David. Thanks. >>>> --- >>>> mm/memory-failure.c | 14 +++++++++++--- >>>> 1 file changed, 11 insertions(+), 3 deletions(-) >>>> >>>> diff --git a/mm/memory-failure.c b/mm/memory-failure.c >>>> index a7b8ccd29b6f..02be0596ce67 100644 >>>> --- a/mm/memory-failure.c >>>> +++ b/mm/memory-failure.c >>>> @@ -2556,10 +2556,18 @@ int unpoison_memory(unsigned long pfn) >>>> static DEFINE_RATELIMIT_STATE(unpoison_rs, DEFAULT_RATELIMIT_INTERVAL, >>>> DEFAULT_RATELIMIT_BURST); >>>> - if (!pfn_valid(pfn)) >>>> - return -ENXIO; >>>> + p = pfn_to_online_page(pfn); >>>> + if (!p) { >>>> + struct dev_pagemap *pgmap; >>>> - p = pfn_to_page(pfn); >>>> + if (!pfn_valid(pfn)) >>>> + return -ENXIO; >>>> + pgmap = get_dev_pagemap(pfn, NULL); >>>> + if (!pgmap) >>>> + return -ENXIO; >>>> + put_dev_pagemap(pgmap); >>>> + p = pfn_to_page(pfn); >>>> + } >>> >>> Hm, I wonder if we can do anything reasonable with ZONE_DEVICE pages here? >> >> All I can see in unpoison_memory() is folio_test_clear_hwpoison() for ZONE_DEVICE pages. > > IIRC, it can only be triggered via debugfs in special kernel configs. So chances are this was never ever actually run against a ZONE_DEVICE page. If ZONE_DEVICE pages are never expected, we can simply filter them out. > >> >>> >>> CCing Dan, maybe he knows if this interface used to do something reasonable with ZONE_DEVICE pages. >>> >>> Also, I'm not sure about using the page after doing the put_dev_pagemap(). Likely we would have to do that at the before exiting from this function. >> >> IMHO, the page can be used after doing put_dev_pagemap(). The page should still be >> available while it has HWPoison set. > > 1) Why do you think it can be used afterwards? :) > > 2) At that point in time you don't even know yet if the page is > HWPoisoned! That check is performed later > > 3) From GUP code, I recall that we must keep the pagemap referenced > until we grabbed a page/folio reference. I think you're right, David. I missed this case. :) Thanks. . > > Or are you worrying about memory offline? That >> might not be the scope of this problem. But I might be miss something. > > I suspect unpoison_memory() doesn't do with ZONE_DEVICE pages what it should be doing. Maybe I'm wrong, it would be great to get feedback from Dan. > >