FAILED: patch "[PATCH] mm: numa: avoid waiting on freed migrated pages" failed to apply to 3.18-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 3.18-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
Quoted 1 line
From
3c226c637b69104f6b9f1c6ec5b08d7b741b3229Mon Sep 17 00:00:00 2001
From: Mark Rutland <[email protected]>
Date: Fri, 16 Jun 2017 14:02:34 -0700
Subject: [PATCH] mm: numa: avoid waiting on freed migrated pages
In do_huge_pmd_numa_page(), we attempt to handle a migrating thp pmd by waiting until the pmd is unlocked before we return and retry. However, we can race with migrate_misplaced_transhuge_page():
// do_huge_pmd_numa_page // migrate_misplaced_transhuge_page()
// Holds 0 refs on page // Holds 2 refs on page
vmf->ptl = pmd_lock(vma->vm_mm, vmf->pmd);
/* ... */
if (pmd_trans_migrating(*vmf->pmd)) {
page = pmd_page(*vmf->pmd);
spin_unlock(vmf->ptl);
ptl = pmd_lock(mm, pmd);
if (page_count(page) != 2)) {
/* roll back */
}
/* ... */
mlock_migrate_page(new_page, page);
/* ... */
spin_unlock(ptl);
put_page(page);
put_page(page); // page freed here
wait_on_page_locked(page);
goto out;
}This can result in the freed page having its waiters flag set unexpectedly, which trips the PAGE_FLAGS_CHECK_AT_PREP checks in the page alloc/free functions. This has been observed on arm64 KVM guests.
We can avoid this by having do_huge_pmd_numa_page() take a reference on the page before dropping the pmd lock, mirroring what we do in __migration_entry_wait().
When we hit the race, migrate_misplaced_transhuge_page() will see the reference and abort the migration, as it may do today in other cases.
mm/huge_memory.c +7 -1
@@ -1426,8 +1426,11 @@ int do_huge_pmd_numa_page(struct vm_fault *vmf, pmd_t pmd)*/ if (unlikely (pmd_trans_migrating (*vmf->pmd))) { page =pmd_page (*vmf->pmd); +if (!get_page_unless_zero (page)) + goto out_unlock;spin_unlock (vmf->ptl);wait_on_page_locked (page); +put_page (page); goto out; }
@@ -1459,9 +1462,12 @@ int do_huge_pmd_numa_page(struct vm_fault *vmf, pmd_t pmd)/* Migration could have started since the pmd_trans_migrating check */ if (!page_locked) { + page_nid =-1 ; +if (!get_page_unless_zero (page)) + goto out_unlock;spin_unlock (vmf->ptl);wait_on_page_locked (page); - page_nid =-1 ; +put_page (page); goto out; }