]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.4.44/mm-hugetlb.c-fix-reservation-race-when-freeing-surplus-pages.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.4.44 / mm-hugetlb.c-fix-reservation-race-when-freeing-surplus-pages.patch
1 From e5bbc8a6c992901058bc09e2ce01d16c111ff047 Mon Sep 17 00:00:00 2001
2 From: Mike Kravetz <mike.kravetz@oracle.com>
3 Date: Tue, 10 Jan 2017 16:58:27 -0800
4 Subject: mm/hugetlb.c: fix reservation race when freeing surplus pages
5
6 From: Mike Kravetz <mike.kravetz@oracle.com>
7
8 commit e5bbc8a6c992901058bc09e2ce01d16c111ff047 upstream.
9
10 return_unused_surplus_pages() decrements the global reservation count,
11 and frees any unused surplus pages that were backing the reservation.
12
13 Commit 7848a4bf51b3 ("mm/hugetlb.c: add cond_resched_lock() in
14 return_unused_surplus_pages()") added a call to cond_resched_lock in the
15 loop freeing the pages.
16
17 As a result, the hugetlb_lock could be dropped, and someone else could
18 use the pages that will be freed in subsequent iterations of the loop.
19 This could result in inconsistent global hugetlb page state, application
20 api failures (such as mmap) failures or application crashes.
21
22 When dropping the lock in return_unused_surplus_pages, make sure that
23 the global reservation count (resv_huge_pages) remains sufficiently
24 large to prevent someone else from claiming pages about to be freed.
25
26 Analyzed by Paul Cassella.
27
28 Fixes: 7848a4bf51b3 ("mm/hugetlb.c: add cond_resched_lock() in return_unused_surplus_pages()")
29 Link: http://lkml.kernel.org/r/1483991767-6879-1-git-send-email-mike.kravetz@oracle.com
30 Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com>
31 Reported-by: Paul Cassella <cassella@cray.com>
32 Suggested-by: Michal Hocko <mhocko@kernel.org>
33 Cc: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
34 Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
35 Cc: Aneesh Kumar <aneesh.kumar@linux.vnet.ibm.com>
36 Cc: Hillf Danton <hillf.zj@alibaba-inc.com>
37 Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
38 Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
39 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
40
41 ---
42 mm/hugetlb.c | 37 ++++++++++++++++++++++++++++---------
43 1 file changed, 28 insertions(+), 9 deletions(-)
44
45 --- a/mm/hugetlb.c
46 +++ b/mm/hugetlb.c
47 @@ -1723,23 +1723,32 @@ free:
48 }
49
50 /*
51 - * When releasing a hugetlb pool reservation, any surplus pages that were
52 - * allocated to satisfy the reservation must be explicitly freed if they were
53 - * never used.
54 - * Called with hugetlb_lock held.
55 + * This routine has two main purposes:
56 + * 1) Decrement the reservation count (resv_huge_pages) by the value passed
57 + * in unused_resv_pages. This corresponds to the prior adjustments made
58 + * to the associated reservation map.
59 + * 2) Free any unused surplus pages that may have been allocated to satisfy
60 + * the reservation. As many as unused_resv_pages may be freed.
61 + *
62 + * Called with hugetlb_lock held. However, the lock could be dropped (and
63 + * reacquired) during calls to cond_resched_lock. Whenever dropping the lock,
64 + * we must make sure nobody else can claim pages we are in the process of
65 + * freeing. Do this by ensuring resv_huge_page always is greater than the
66 + * number of huge pages we plan to free when dropping the lock.
67 */
68 static void return_unused_surplus_pages(struct hstate *h,
69 unsigned long unused_resv_pages)
70 {
71 unsigned long nr_pages;
72
73 - /* Uncommit the reservation */
74 - h->resv_huge_pages -= unused_resv_pages;
75 -
76 /* Cannot return gigantic pages currently */
77 if (hstate_is_gigantic(h))
78 - return;
79 + goto out;
80
81 + /*
82 + * Part (or even all) of the reservation could have been backed
83 + * by pre-allocated pages. Only free surplus pages.
84 + */
85 nr_pages = min(unused_resv_pages, h->surplus_huge_pages);
86
87 /*
88 @@ -1749,12 +1758,22 @@ static void return_unused_surplus_pages(
89 * when the nodes with surplus pages have no free pages.
90 * free_pool_huge_page() will balance the the freed pages across the
91 * on-line nodes with memory and will handle the hstate accounting.
92 + *
93 + * Note that we decrement resv_huge_pages as we free the pages. If
94 + * we drop the lock, resv_huge_pages will still be sufficiently large
95 + * to cover subsequent pages we may free.
96 */
97 while (nr_pages--) {
98 + h->resv_huge_pages--;
99 + unused_resv_pages--;
100 if (!free_pool_huge_page(h, &node_states[N_MEMORY], 1))
101 - break;
102 + goto out;
103 cond_resched_lock(&hugetlb_lock);
104 }
105 +
106 +out:
107 + /* Fully uncommit the reservation */
108 + h->resv_huge_pages -= unused_resv_pages;
109 }
110
111