diff options
-rw-r--r-- | mm/hugetlb.c | 37 |
1 files changed, 28 insertions, 9 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 23aec01836aa..b6adedbafaf5 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
@@ -1773,23 +1773,32 @@ free: | |||
1773 | } | 1773 | } |
1774 | 1774 | ||
1775 | /* | 1775 | /* |
1776 | * When releasing a hugetlb pool reservation, any surplus pages that were | 1776 | * This routine has two main purposes: |
1777 | * allocated to satisfy the reservation must be explicitly freed if they were | 1777 | * 1) Decrement the reservation count (resv_huge_pages) by the value passed |
1778 | * never used. | 1778 | * in unused_resv_pages. This corresponds to the prior adjustments made |
1779 | * Called with hugetlb_lock held. | 1779 | * to the associated reservation map. |
1780 | * 2) Free any unused surplus pages that may have been allocated to satisfy | ||
1781 | * the reservation. As many as unused_resv_pages may be freed. | ||
1782 | * | ||
1783 | * Called with hugetlb_lock held. However, the lock could be dropped (and | ||
1784 | * reacquired) during calls to cond_resched_lock. Whenever dropping the lock, | ||
1785 | * we must make sure nobody else can claim pages we are in the process of | ||
1786 | * freeing. Do this by ensuring resv_huge_page always is greater than the | ||
1787 | * number of huge pages we plan to free when dropping the lock. | ||
1780 | */ | 1788 | */ |
1781 | static void return_unused_surplus_pages(struct hstate *h, | 1789 | static void return_unused_surplus_pages(struct hstate *h, |
1782 | unsigned long unused_resv_pages) | 1790 | unsigned long unused_resv_pages) |
1783 | { | 1791 | { |
1784 | unsigned long nr_pages; | 1792 | unsigned long nr_pages; |
1785 | 1793 | ||
1786 | /* Uncommit the reservation */ | ||
1787 | h->resv_huge_pages -= unused_resv_pages; | ||
1788 | |||
1789 | /* Cannot return gigantic pages currently */ | 1794 | /* Cannot return gigantic pages currently */ |
1790 | if (hstate_is_gigantic(h)) | 1795 | if (hstate_is_gigantic(h)) |
1791 | return; | 1796 | goto out; |
1792 | 1797 | ||
1798 | /* | ||
1799 | * Part (or even all) of the reservation could have been backed | ||
1800 | * by pre-allocated pages. Only free surplus pages. | ||
1801 | */ | ||
1793 | nr_pages = min(unused_resv_pages, h->surplus_huge_pages); | 1802 | nr_pages = min(unused_resv_pages, h->surplus_huge_pages); |
1794 | 1803 | ||
1795 | /* | 1804 | /* |
@@ -1799,12 +1808,22 @@ static void return_unused_surplus_pages(struct hstate *h, | |||
1799 | * when the nodes with surplus pages have no free pages. | 1808 | * when the nodes with surplus pages have no free pages. |
1800 | * free_pool_huge_page() will balance the the freed pages across the | 1809 | * free_pool_huge_page() will balance the the freed pages across the |
1801 | * on-line nodes with memory and will handle the hstate accounting. | 1810 | * on-line nodes with memory and will handle the hstate accounting. |
1811 | * | ||
1812 | * Note that we decrement resv_huge_pages as we free the pages. If | ||
1813 | * we drop the lock, resv_huge_pages will still be sufficiently large | ||
1814 | * to cover subsequent pages we may free. | ||
1802 | */ | 1815 | */ |
1803 | while (nr_pages--) { | 1816 | while (nr_pages--) { |
1817 | h->resv_huge_pages--; | ||
1818 | unused_resv_pages--; | ||
1804 | if (!free_pool_huge_page(h, &node_states[N_MEMORY], 1)) | 1819 | if (!free_pool_huge_page(h, &node_states[N_MEMORY], 1)) |
1805 | break; | 1820 | goto out; |
1806 | cond_resched_lock(&hugetlb_lock); | 1821 | cond_resched_lock(&hugetlb_lock); |
1807 | } | 1822 | } |
1823 | |||
1824 | out: | ||
1825 | /* Fully uncommit the reservation */ | ||
1826 | h->resv_huge_pages -= unused_resv_pages; | ||
1808 | } | 1827 | } |
1809 | 1828 | ||
1810 | 1829 | ||