Skip to content

Commit dad4e5b

Browse files
djbwtorvalds
authored andcommitted
mm: fix page reference leak in soft_offline_page()
The conversion to move pfn_to_online_page() internal to soft_offline_page() missed that the get_user_pages() reference taken by the madvise() path needs to be dropped when pfn_to_online_page() fails. Note the direct sysfs-path to soft_offline_page() does not perform a get_user_pages() lookup. When soft_offline_page() is handed a pfn_valid() && !pfn_to_online_page() pfn the kernel hangs at dax-device shutdown due to a leaked reference. Link: https://lkml.kernel.org/r/161058501210.1840162.8108917599181157327.stgit@dwillia2-desk3.amr.corp.intel.com Fixes: feec24a ("mm, soft-offline: convert parameter to pfn") Signed-off-by: Dan Williams <dan.j.williams@intel.com> Reviewed-by: David Hildenbrand <david@redhat.com> Reviewed-by: Oscar Salvador <osalvador@suse.de> Reviewed-by: Naoya Horiguchi <naoya.horiguchi@nec.com> Cc: Michal Hocko <mhocko@suse.com> Cc: Qian Cai <cai@lca.pw> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 251b549 commit dad4e5b

1 file changed

Lines changed: 16 additions & 4 deletions

File tree

mm/memory-failure.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1885,6 +1885,12 @@ static int soft_offline_free_page(struct page *page)
18851885
return rc;
18861886
}
18871887

1888+
static void put_ref_page(struct page *page)
1889+
{
1890+
if (page)
1891+
put_page(page);
1892+
}
1893+
18881894
/**
18891895
* soft_offline_page - Soft offline a page.
18901896
* @pfn: pfn to soft-offline
@@ -1910,20 +1916,26 @@ static int soft_offline_free_page(struct page *page)
19101916
int soft_offline_page(unsigned long pfn, int flags)
19111917
{
19121918
int ret;
1913-
struct page *page;
19141919
bool try_again = true;
1920+
struct page *page, *ref_page = NULL;
1921+
1922+
WARN_ON_ONCE(!pfn_valid(pfn) && (flags & MF_COUNT_INCREASED));
19151923

19161924
if (!pfn_valid(pfn))
19171925
return -ENXIO;
1926+
if (flags & MF_COUNT_INCREASED)
1927+
ref_page = pfn_to_page(pfn);
1928+
19181929
/* Only online pages can be soft-offlined (esp., not ZONE_DEVICE). */
19191930
page = pfn_to_online_page(pfn);
1920-
if (!page)
1931+
if (!page) {
1932+
put_ref_page(ref_page);
19211933
return -EIO;
1934+
}
19221935

19231936
if (PageHWPoison(page)) {
19241937
pr_info("%s: %#lx page already poisoned\n", __func__, pfn);
1925-
if (flags & MF_COUNT_INCREASED)
1926-
put_page(page);
1938+
put_ref_page(ref_page);
19271939
return 0;
19281940
}
19291941

0 commit comments

Comments
 (0)