|
@@ -1437,22 +1437,32 @@ static int free_pool_huge_page(struct hstate *h, nodemask_t *nodes_allowed,
|
|
|
|
|
|
/*
|
|
|
* Dissolve a given free hugepage into free buddy pages. This function does
|
|
|
- * nothing for in-use (including surplus) hugepages.
|
|
|
+ * nothing for in-use (including surplus) hugepages. Returns -EBUSY if the
|
|
|
+ * number of free hugepages would be reduced below the number of reserved
|
|
|
+ * hugepages.
|
|
|
*/
|
|
|
-static void dissolve_free_huge_page(struct page *page)
|
|
|
+static int dissolve_free_huge_page(struct page *page)
|
|
|
{
|
|
|
+ int rc = 0;
|
|
|
+
|
|
|
spin_lock(&hugetlb_lock);
|
|
|
if (PageHuge(page) && !page_count(page)) {
|
|
|
struct page *head = compound_head(page);
|
|
|
struct hstate *h = page_hstate(head);
|
|
|
int nid = page_to_nid(head);
|
|
|
+ if (h->free_huge_pages - h->resv_huge_pages == 0) {
|
|
|
+ rc = -EBUSY;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
list_del(&head->lru);
|
|
|
h->free_huge_pages--;
|
|
|
h->free_huge_pages_node[nid]--;
|
|
|
h->max_huge_pages--;
|
|
|
update_and_free_page(h, head);
|
|
|
}
|
|
|
+out:
|
|
|
spin_unlock(&hugetlb_lock);
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1460,16 +1470,22 @@ static void dissolve_free_huge_page(struct page *page)
|
|
|
* make specified memory blocks removable from the system.
|
|
|
* Note that this will dissolve a free gigantic hugepage completely, if any
|
|
|
* part of it lies within the given range.
|
|
|
+ * Also note that if dissolve_free_huge_page() returns with an error, all
|
|
|
+ * free hugepages that were dissolved before that error are lost.
|
|
|
*/
|
|
|
-void dissolve_free_huge_pages(unsigned long start_pfn, unsigned long end_pfn)
|
|
|
+int dissolve_free_huge_pages(unsigned long start_pfn, unsigned long end_pfn)
|
|
|
{
|
|
|
unsigned long pfn;
|
|
|
+ int rc = 0;
|
|
|
|
|
|
if (!hugepages_supported())
|
|
|
- return;
|
|
|
+ return rc;
|
|
|
|
|
|
for (pfn = start_pfn; pfn < end_pfn; pfn += 1 << minimum_order)
|
|
|
- dissolve_free_huge_page(pfn_to_page(pfn));
|
|
|
+ if (rc = dissolve_free_huge_page(pfn_to_page(pfn)))
|
|
|
+ break;
|
|
|
+
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
/*
|