aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
Diffstat (limited to 'mm')
-rw-r--r--mm/hugetlb.c11
-rw-r--r--mm/memory-failure.c22
-rw-r--r--mm/migrate.c2
3 files changed, 21 insertions, 14 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 47566bb0b4b1..9f1c853f67b5 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1479,22 +1479,20 @@ static int free_pool_huge_page(struct hstate *h, nodemask_t *nodes_allowed,
1479/* 1479/*
1480 * Dissolve a given free hugepage into free buddy pages. This function does 1480 * Dissolve a given free hugepage into free buddy pages. This function does
1481 * nothing for in-use (including surplus) hugepages. Returns -EBUSY if the 1481 * nothing for in-use (including surplus) hugepages. Returns -EBUSY if the
1482 * number of free hugepages would be reduced below the number of reserved 1482 * dissolution fails because a give page is not a free hugepage, or because
1483 * hugepages. 1483 * free hugepages are fully reserved.
1484 */ 1484 */
1485int dissolve_free_huge_page(struct page *page) 1485int dissolve_free_huge_page(struct page *page)
1486{ 1486{
1487 int rc = 0; 1487 int rc = -EBUSY;
1488 1488
1489 spin_lock(&hugetlb_lock); 1489 spin_lock(&hugetlb_lock);
1490 if (PageHuge(page) && !page_count(page)) { 1490 if (PageHuge(page) && !page_count(page)) {
1491 struct page *head = compound_head(page); 1491 struct page *head = compound_head(page);
1492 struct hstate *h = page_hstate(head); 1492 struct hstate *h = page_hstate(head);
1493 int nid = page_to_nid(head); 1493 int nid = page_to_nid(head);
1494 if (h->free_huge_pages - h->resv_huge_pages == 0) { 1494 if (h->free_huge_pages - h->resv_huge_pages == 0)
1495 rc = -EBUSY;
1496 goto out; 1495 goto out;
1497 }
1498 /* 1496 /*
1499 * Move PageHWPoison flag from head page to the raw error page, 1497 * Move PageHWPoison flag from head page to the raw error page,
1500 * which makes any subpages rather than the error page reusable. 1498 * which makes any subpages rather than the error page reusable.
@@ -1508,6 +1506,7 @@ int dissolve_free_huge_page(struct page *page)
1508 h->free_huge_pages_node[nid]--; 1506 h->free_huge_pages_node[nid]--;
1509 h->max_huge_pages--; 1507 h->max_huge_pages--;
1510 update_and_free_page(h, head); 1508 update_and_free_page(h, head);
1509 rc = 0;
1511 } 1510 }
1512out: 1511out:
1513 spin_unlock(&hugetlb_lock); 1512 spin_unlock(&hugetlb_lock);
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index c83a1746812f..49dc32c61137 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1598,8 +1598,18 @@ static int soft_offline_huge_page(struct page *page, int flags)
1598 if (ret > 0) 1598 if (ret > 0)
1599 ret = -EIO; 1599 ret = -EIO;
1600 } else { 1600 } else {
1601 if (PageHuge(page)) 1601 /*
1602 dissolve_free_huge_page(page); 1602 * We set PG_hwpoison only when the migration source hugepage
1603 * was successfully dissolved, because otherwise hwpoisoned
1604 * hugepage remains on free hugepage list, then userspace will
1605 * find it as SIGBUS by allocation failure. That's not expected
1606 * in soft-offlining.
1607 */
1608 ret = dissolve_free_huge_page(page);
1609 if (!ret) {
1610 if (set_hwpoison_free_buddy_page(page))
1611 num_poisoned_pages_inc();
1612 }
1603 } 1613 }
1604 return ret; 1614 return ret;
1605} 1615}
@@ -1715,13 +1725,13 @@ static int soft_offline_in_use_page(struct page *page, int flags)
1715 1725
1716static void soft_offline_free_page(struct page *page) 1726static void soft_offline_free_page(struct page *page)
1717{ 1727{
1728 int rc = 0;
1718 struct page *head = compound_head(page); 1729 struct page *head = compound_head(page);
1719 1730
1720 if (!TestSetPageHWPoison(head)) { 1731 if (PageHuge(head))
1732 rc = dissolve_free_huge_page(page);
1733 if (!rc && !TestSetPageHWPoison(page))
1721 num_poisoned_pages_inc(); 1734 num_poisoned_pages_inc();
1722 if (PageHuge(head))
1723 dissolve_free_huge_page(page);
1724 }
1725} 1735}
1726 1736
1727/** 1737/**
diff --git a/mm/migrate.c b/mm/migrate.c
index c27e97b5b69d..91a99457127c 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -1331,8 +1331,6 @@ put_anon:
1331out: 1331out:
1332 if (rc != -EAGAIN) 1332 if (rc != -EAGAIN)
1333 putback_active_hugepage(hpage); 1333 putback_active_hugepage(hpage);
1334 if (reason == MR_MEMORY_FAILURE && !test_set_page_hwpoison(hpage))
1335 num_poisoned_pages_inc();
1336 1334
1337 /* 1335 /*
1338 * If migration was not successful and there's a freeing callback, use 1336 * If migration was not successful and there's a freeing callback, use