|
@@ -57,6 +57,7 @@
|
|
|
#include <linux/mm_inline.h>
|
|
|
#include <linux/kfifo.h>
|
|
|
#include <linux/ratelimit.h>
|
|
|
+#include <linux/page-isolation.h>
|
|
|
#include "internal.h"
|
|
|
#include "ras/ras_event.h"
|
|
|
|
|
@@ -1697,6 +1698,7 @@ static int __soft_offline_page(struct page *page, int flags)
|
|
|
static int soft_offline_in_use_page(struct page *page, int flags)
|
|
|
{
|
|
|
int ret;
|
|
|
+ int mt;
|
|
|
struct page *hpage = compound_head(page);
|
|
|
|
|
|
if (!PageHuge(page) && PageTransHuge(hpage)) {
|
|
@@ -1715,23 +1717,37 @@ static int soft_offline_in_use_page(struct page *page, int flags)
|
|
|
put_hwpoison_page(hpage);
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * Setting MIGRATE_ISOLATE here ensures that the page will be linked
|
|
|
+ * to free list immediately (not via pcplist) when released after
|
|
|
+ * successful page migration. Otherwise we can't guarantee that the
|
|
|
+ * page is really free after put_page() returns, so
|
|
|
+ * set_hwpoison_free_buddy_page() highly likely fails.
|
|
|
+ */
|
|
|
+ mt = get_pageblock_migratetype(page);
|
|
|
+ set_pageblock_migratetype(page, MIGRATE_ISOLATE);
|
|
|
if (PageHuge(page))
|
|
|
ret = soft_offline_huge_page(page, flags);
|
|
|
else
|
|
|
ret = __soft_offline_page(page, flags);
|
|
|
-
|
|
|
+ set_pageblock_migratetype(page, mt);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static void soft_offline_free_page(struct page *page)
|
|
|
+static int soft_offline_free_page(struct page *page)
|
|
|
{
|
|
|
int rc = 0;
|
|
|
struct page *head = compound_head(page);
|
|
|
|
|
|
if (PageHuge(head))
|
|
|
rc = dissolve_free_huge_page(page);
|
|
|
- if (!rc && !TestSetPageHWPoison(page))
|
|
|
- num_poisoned_pages_inc();
|
|
|
+ if (!rc) {
|
|
|
+ if (set_hwpoison_free_buddy_page(page))
|
|
|
+ num_poisoned_pages_inc();
|
|
|
+ else
|
|
|
+ rc = -EBUSY;
|
|
|
+ }
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1775,7 +1791,7 @@ int soft_offline_page(struct page *page, int flags)
|
|
|
if (ret > 0)
|
|
|
ret = soft_offline_in_use_page(page, flags);
|
|
|
else if (ret == 0)
|
|
|
- soft_offline_free_page(page);
|
|
|
+ ret = soft_offline_free_page(page);
|
|
|
|
|
|
return ret;
|
|
|
}
|