Commit 8295d535 authored by Oscar Salvador's avatar Oscar Salvador Committed by Linus Torvalds
Browse files

mm,hwpoison: refactor get_any_page

Patch series "HWPoison: Refactor get page interface", v2.

This patch (of 3):

When we want to grab a refcount via get_any_page, we call __get_any_page
that calls get_hwpoison_page to get the actual refcount.

get_any_page() is only there because we have a sort of retry mechanism in
case the page we met is unknown to us or if we raced with an allocation.

Also __get_any_page() prints some messages about the page type in case the
page was a free page or the page type was unknown, but if anything, we
only need to print a message in case the pagetype was unknown, as that is
reporting an error down the chain.

Let us merge get_any_page() and __get_any_page(), and let the message be
printed in soft_offline_page.  While we are it, we can also remove the
'pfn' parameter as it is no longer used.

Link: https://lkml.kernel.org/r/20201204102558.31607-1-osalvador@suse.de
Link: https://lkml.kernel.org/r/20201204102558.31607-2-osalvador@suse.de


Signed-off-by: default avatarOscar Salvador <osalvador@suse.de>
Acked-by: default avatarNaoya Horiguchi <naoya.horiguchi@nec.com>
Acked-by: default avatarVlastimil Babka <Vbabka@suse.cz>
Cc: Qian Cai <qcai@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 32409cba
Loading
Loading
Loading
Loading
+42 −57
Original line number Diff line number Diff line
@@ -1707,70 +1707,51 @@ EXPORT_SYMBOL(unpoison_memory);

/*
 * Safely get reference count of an arbitrary page.
 * Returns 0 for a free page, -EIO for a zero refcount page
 * that is not free, and 1 for any other page type.
 * For 1 the page is returned with increased page count, otherwise not.
 * Returns 0 for a free page, 1 for an in-use page, -EIO for a page-type we
 * cannot handle and -EBUSY if we raced with an allocation.
 * We only incremented refcount in case the page was already in-use and it is
 * a known type we can handle.
 */
static int __get_any_page(struct page *p, unsigned long pfn, int flags)
static int get_any_page(struct page *p, int flags)
{
	int ret;
	int ret = 0, pass = 0;
	bool count_increased = false;

	if (flags & MF_COUNT_INCREASED)
		return 1;
		count_increased = true;

	/*
	 * When the target page is a free hugepage, just remove it
	 * from free hugepage list.
	 */
	if (!get_hwpoison_page(p)) {
		if (PageHuge(p)) {
			pr_info("%s: %#lx free huge page\n", __func__, pfn);
			ret = 0;
		} else if (is_free_buddy_page(p)) {
			pr_info("%s: %#lx free buddy page\n", __func__, pfn);
			ret = 0;
		} else if (page_count(p)) {
			/* raced with allocation */
try_again:
	if (!count_increased && !get_hwpoison_page(p)) {
		if (page_count(p)) {
			/* We raced with an allocation, retry. */
			if (pass++ < 3)
				goto try_again;
			ret = -EBUSY;
		} else {
			pr_info("%s: %#lx: unknown zero refcount page type %lx\n",
				__func__, pfn, p->flags);
		} else if (!PageHuge(p) && !is_free_buddy_page(p)) {
			/* We raced with put_page, retry. */
			if (pass++ < 3)
				goto try_again;
			ret = -EIO;
		}
	} else {
		/* Not a free page */
		if (PageHuge(p) || PageLRU(p) || __PageMovable(p)) {
			ret = 1;
	}
	return ret;
}

static int get_any_page(struct page *page, unsigned long pfn, int flags)
{
	int ret = __get_any_page(page, pfn, flags);

	if (ret == -EBUSY)
		ret = __get_any_page(page, pfn, flags);

	if (ret == 1 && !PageHuge(page) &&
	    !PageLRU(page) && !__PageMovable(page)) {
		/*
		 * Try to free it.
		 */
		put_page(page);
		shake_page(page, 1);

		} else {
			/*
		 * Did it turn free?
			 * A page we cannot handle. Check whether we can turn
			 * it into something we can handle.
			 */
		ret = __get_any_page(page, pfn, 0);
		if (ret == 1 && !PageLRU(page)) {
			/* Drop page reference which is from __get_any_page() */
			put_page(page);
			pr_info("soft_offline: %#lx: unknown non LRU page type %lx (%pGp)\n",
				pfn, page->flags, &page->flags);
			return -EIO;
			if (pass++ < 3) {
				put_page(p);
				shake_page(p, 1);
				count_increased = false;
				goto try_again;
			}
			put_page(p);
			ret = -EIO;
		}
	}

	return ret;
}

@@ -1939,7 +1920,7 @@ int soft_offline_page(unsigned long pfn, int flags)
		return -EIO;

	if (PageHWPoison(page)) {
		pr_info("soft offline: %#lx page already poisoned\n", pfn);
		pr_info("%s: %#lx page already poisoned\n", __func__, pfn);
		if (flags & MF_COUNT_INCREASED)
			put_page(page);
		return 0;
@@ -1947,16 +1928,20 @@ int soft_offline_page(unsigned long pfn, int flags)

retry:
	get_online_mems();
	ret = get_any_page(page, pfn, flags);
	ret = get_any_page(page, flags);
	put_online_mems();

	if (ret > 0)
	if (ret > 0) {
		ret = soft_offline_in_use_page(page);
	else if (ret == 0)
	} else if (ret == 0) {
		if (soft_offline_free_page(page) && try_again) {
			try_again = false;
			goto retry;
		}
	} else if (ret == -EIO) {
		pr_info("%s: %#lx: unknown page type: %lx (%pGP)\n",
			 __func__, pfn, page->flags, &page->flags);
	}

	return ret;
}