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: Oscar Salvador <osalvador@suse.de> Acked-by: Naoya Horiguchi <naoya.horiguchi@nec.com> Acked-by: Vlastimil Babka <Vbabka@suse.cz> Cc: Qian Cai <qcai@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Родитель
32409cba3f
Коммит
8295d535e2
|
@ -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)) {
|
||||
} else {
|
||||
/*
|
||||
* Try to free it.
|
||||
* A page we cannot handle. Check whether we can turn
|
||||
* it into something we can handle.
|
||||
*/
|
||||
put_page(page);
|
||||
shake_page(page, 1);
|
||||
if (pass++ < 3) {
|
||||
put_page(p);
|
||||
shake_page(p, 1);
|
||||
count_increased = false;
|
||||
goto try_again;
|
||||
}
|
||||
put_page(p);
|
||||
ret = -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Did it turn free?
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче