summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mm/hugetlb.c29
-rw-r--r--mm/memory-failure.c5
2 files changed, 21 insertions, 13 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index ac843d32b019..ede7e7f5d1ab 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1510,16 +1510,29 @@ static int free_pool_huge_page(struct hstate *h, nodemask_t *nodes_allowed,
1510 1510
1511/* 1511/*
1512 * Dissolve a given free hugepage into free buddy pages. This function does 1512 * Dissolve a given free hugepage into free buddy pages. This function does
1513 * nothing for in-use (including surplus) hugepages. Returns -EBUSY if the 1513 * nothing for in-use hugepages and non-hugepages.
1514 * dissolution fails because a give page is not a free hugepage, or because 1514 * This function returns values like below:
1515 * free hugepages are fully reserved. 1515 *
1516 * -EBUSY: failed to dissolved free hugepages or the hugepage is in-use
1517 * (allocated or reserved.)
1518 * 0: successfully dissolved free hugepages or the page is not a
1519 * hugepage (considered as already dissolved)
1516 */ 1520 */
1517int dissolve_free_huge_page(struct page *page) 1521int dissolve_free_huge_page(struct page *page)
1518{ 1522{
1519 int rc = -EBUSY; 1523 int rc = -EBUSY;
1520 1524
1525 /* Not to disrupt normal path by vainly holding hugetlb_lock */
1526 if (!PageHuge(page))
1527 return 0;
1528
1521 spin_lock(&hugetlb_lock); 1529 spin_lock(&hugetlb_lock);
1522 if (PageHuge(page) && !page_count(page)) { 1530 if (!PageHuge(page)) {
1531 rc = 0;
1532 goto out;
1533 }
1534
1535 if (!page_count(page)) {
1523 struct page *head = compound_head(page); 1536 struct page *head = compound_head(page);
1524 struct hstate *h = page_hstate(head); 1537 struct hstate *h = page_hstate(head);
1525 int nid = page_to_nid(head); 1538 int nid = page_to_nid(head);
@@ -1564,11 +1577,9 @@ int dissolve_free_huge_pages(unsigned long start_pfn, unsigned long end_pfn)
1564 1577
1565 for (pfn = start_pfn; pfn < end_pfn; pfn += 1 << minimum_order) { 1578 for (pfn = start_pfn; pfn < end_pfn; pfn += 1 << minimum_order) {
1566 page = pfn_to_page(pfn); 1579 page = pfn_to_page(pfn);
1567 if (PageHuge(page) && !page_count(page)) { 1580 rc = dissolve_free_huge_page(page);
1568 rc = dissolve_free_huge_page(page); 1581 if (rc)
1569 if (rc) 1582 break;
1570 break;
1571 }
1572 } 1583 }
1573 1584
1574 return rc; 1585 return rc;
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 8ee7b16235ac..d9cc6606f409 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1856,11 +1856,8 @@ static int soft_offline_in_use_page(struct page *page, int flags)
1856 1856
1857static int soft_offline_free_page(struct page *page) 1857static int soft_offline_free_page(struct page *page)
1858{ 1858{
1859 int rc = 0; 1859 int rc = dissolve_free_huge_page(page);
1860 struct page *head = compound_head(page);
1861 1860
1862 if (PageHuge(head))
1863 rc = dissolve_free_huge_page(page);
1864 if (!rc) { 1861 if (!rc) {
1865 if (set_hwpoison_free_buddy_page(page)) 1862 if (set_hwpoison_free_buddy_page(page))
1866 num_poisoned_pages_inc(); 1863 num_poisoned_pages_inc();