Re: BUG_ON() in pfn_swap_entry_to_page()

Matthew Wilcox
2022-03-22T17:42:03Z

On Tue, Mar 22, 2022 at 06:25:02PM +0100, Sebastian Andrzej Siewior wrote:
> Run into
>
> |kernel BUG at include/linux/swapops.h:258!
> |RIP: 0010:migration_entry_wait_on_locked+0x233/0x2c0
> |Call Trace:
> | <TASK>
> | __handle_mm_fault+0x2bf/0x1810
> | handle_mm_fault+0x136/0x3e0
> | exc_page_fault+0x1d2/0x850
> | asm_exc_page_fault+0x22/0x30
>
> This is the BUG_ON() in pfn_swap_entry_to_page(). The box itself has no
> swapspace configured. Is this something known?

It's not been reported before, but it seems obvious why it triggers.
I think it's ffa65753c431 "mm/migrate.c: rework migration_entry_wait()
to not take a pageref".

There's a lot of inlining going on, so let's write this out:

__handle_mm_fault
handle_pte_fault
do_swap_page():

entry = pte_to_swp_entry(vmf->orig_pte);
if (unlikely(non_swap_entry(entry))) {
if (is_migration_entry(entry)) {
migration_entry_wait(vma->vm_mm, vmf->pmd,
vmf->address);

We don't (and can't) have the underlying page locked here. We're just
waiting for it to finish migration.

migration_entry_wait
migration_entry_wait_on_locked():

struct folio *folio = page_folio(pfn_swap_entry_to_page(entry));

pfn_swap_entry_to_page():

struct page *p = pfn_to_page(swp_offset(entry));

/*
* Any use of migration entries may only occur while the
* corresponding page is locked
*/
BUG_ON(is_migration_entry(entry) && !PageLocked(p));

So why did we not hit this earlier? Surely somebody's testing page
migration? I'm not familiar with the migration code, so maybe this
assertion is obsolete and it's now legitimate to use a migration entry
while the page is unlocked.