|
@@ -1773,23 +1773,32 @@ free:
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
- * When releasing a hugetlb pool reservation, any surplus pages that were
|
|
|
|
- * allocated to satisfy the reservation must be explicitly freed if they were
|
|
|
|
- * never used.
|
|
|
|
- * Called with hugetlb_lock held.
|
|
|
|
|
|
+ * This routine has two main purposes:
|
|
|
|
+ * 1) Decrement the reservation count (resv_huge_pages) by the value passed
|
|
|
|
+ * in unused_resv_pages. This corresponds to the prior adjustments made
|
|
|
|
+ * to the associated reservation map.
|
|
|
|
+ * 2) Free any unused surplus pages that may have been allocated to satisfy
|
|
|
|
+ * the reservation. As many as unused_resv_pages may be freed.
|
|
|
|
+ *
|
|
|
|
+ * Called with hugetlb_lock held. However, the lock could be dropped (and
|
|
|
|
+ * reacquired) during calls to cond_resched_lock. Whenever dropping the lock,
|
|
|
|
+ * we must make sure nobody else can claim pages we are in the process of
|
|
|
|
+ * freeing. Do this by ensuring resv_huge_page always is greater than the
|
|
|
|
+ * number of huge pages we plan to free when dropping the lock.
|
|
*/
|
|
*/
|
|
static void return_unused_surplus_pages(struct hstate *h,
|
|
static void return_unused_surplus_pages(struct hstate *h,
|
|
unsigned long unused_resv_pages)
|
|
unsigned long unused_resv_pages)
|
|
{
|
|
{
|
|
unsigned long nr_pages;
|
|
unsigned long nr_pages;
|
|
|
|
|
|
- /* Uncommit the reservation */
|
|
|
|
- h->resv_huge_pages -= unused_resv_pages;
|
|
|
|
-
|
|
|
|
/* Cannot return gigantic pages currently */
|
|
/* Cannot return gigantic pages currently */
|
|
if (hstate_is_gigantic(h))
|
|
if (hstate_is_gigantic(h))
|
|
- return;
|
|
|
|
|
|
+ goto out;
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Part (or even all) of the reservation could have been backed
|
|
|
|
+ * by pre-allocated pages. Only free surplus pages.
|
|
|
|
+ */
|
|
nr_pages = min(unused_resv_pages, h->surplus_huge_pages);
|
|
nr_pages = min(unused_resv_pages, h->surplus_huge_pages);
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -1799,12 +1808,22 @@ static void return_unused_surplus_pages(struct hstate *h,
|
|
* when the nodes with surplus pages have no free pages.
|
|
* when the nodes with surplus pages have no free pages.
|
|
* free_pool_huge_page() will balance the the freed pages across the
|
|
* free_pool_huge_page() will balance the the freed pages across the
|
|
* on-line nodes with memory and will handle the hstate accounting.
|
|
* on-line nodes with memory and will handle the hstate accounting.
|
|
|
|
+ *
|
|
|
|
+ * Note that we decrement resv_huge_pages as we free the pages. If
|
|
|
|
+ * we drop the lock, resv_huge_pages will still be sufficiently large
|
|
|
|
+ * to cover subsequent pages we may free.
|
|
*/
|
|
*/
|
|
while (nr_pages--) {
|
|
while (nr_pages--) {
|
|
|
|
+ h->resv_huge_pages--;
|
|
|
|
+ unused_resv_pages--;
|
|
if (!free_pool_huge_page(h, &node_states[N_MEMORY], 1))
|
|
if (!free_pool_huge_page(h, &node_states[N_MEMORY], 1))
|
|
- break;
|
|
|
|
|
|
+ goto out;
|
|
cond_resched_lock(&hugetlb_lock);
|
|
cond_resched_lock(&hugetlb_lock);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+out:
|
|
|
|
+ /* Fully uncommit the reservation */
|
|
|
|
+ h->resv_huge_pages -= unused_resv_pages;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|