diff options
Diffstat (limited to 'mm/hugetlb.c')
-rw-r--r-- | mm/hugetlb.c | 43 |
1 files changed, 35 insertions, 8 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 89e6286a7f57..dcacc811e70e 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
@@ -71,7 +71,25 @@ static void enqueue_huge_page(struct page *page) | |||
71 | free_huge_pages_node[nid]++; | 71 | free_huge_pages_node[nid]++; |
72 | } | 72 | } |
73 | 73 | ||
74 | static struct page *dequeue_huge_page(struct vm_area_struct *vma, | 74 | static struct page *dequeue_huge_page(void) |
75 | { | ||
76 | int nid; | ||
77 | struct page *page = NULL; | ||
78 | |||
79 | for (nid = 0; nid < MAX_NUMNODES; ++nid) { | ||
80 | if (!list_empty(&hugepage_freelists[nid])) { | ||
81 | page = list_entry(hugepage_freelists[nid].next, | ||
82 | struct page, lru); | ||
83 | list_del(&page->lru); | ||
84 | free_huge_pages--; | ||
85 | free_huge_pages_node[nid]--; | ||
86 | break; | ||
87 | } | ||
88 | } | ||
89 | return page; | ||
90 | } | ||
91 | |||
92 | static struct page *dequeue_huge_page_vma(struct vm_area_struct *vma, | ||
75 | unsigned long address) | 93 | unsigned long address) |
76 | { | 94 | { |
77 | int nid; | 95 | int nid; |
@@ -296,8 +314,10 @@ static int gather_surplus_pages(int delta) | |||
296 | int needed, allocated; | 314 | int needed, allocated; |
297 | 315 | ||
298 | needed = (resv_huge_pages + delta) - free_huge_pages; | 316 | needed = (resv_huge_pages + delta) - free_huge_pages; |
299 | if (needed <= 0) | 317 | if (needed <= 0) { |
318 | resv_huge_pages += delta; | ||
300 | return 0; | 319 | return 0; |
320 | } | ||
301 | 321 | ||
302 | allocated = 0; | 322 | allocated = 0; |
303 | INIT_LIST_HEAD(&surplus_list); | 323 | INIT_LIST_HEAD(&surplus_list); |
@@ -335,9 +355,12 @@ retry: | |||
335 | * The surplus_list now contains _at_least_ the number of extra pages | 355 | * The surplus_list now contains _at_least_ the number of extra pages |
336 | * needed to accomodate the reservation. Add the appropriate number | 356 | * needed to accomodate the reservation. Add the appropriate number |
337 | * of pages to the hugetlb pool and free the extras back to the buddy | 357 | * of pages to the hugetlb pool and free the extras back to the buddy |
338 | * allocator. | 358 | * allocator. Commit the entire reservation here to prevent another |
359 | * process from stealing the pages as they are added to the pool but | ||
360 | * before they are reserved. | ||
339 | */ | 361 | */ |
340 | needed += allocated; | 362 | needed += allocated; |
363 | resv_huge_pages += delta; | ||
341 | ret = 0; | 364 | ret = 0; |
342 | free: | 365 | free: |
343 | list_for_each_entry_safe(page, tmp, &surplus_list, lru) { | 366 | list_for_each_entry_safe(page, tmp, &surplus_list, lru) { |
@@ -371,6 +394,9 @@ static void return_unused_surplus_pages(unsigned long unused_resv_pages) | |||
371 | struct page *page; | 394 | struct page *page; |
372 | unsigned long nr_pages; | 395 | unsigned long nr_pages; |
373 | 396 | ||
397 | /* Uncommit the reservation */ | ||
398 | resv_huge_pages -= unused_resv_pages; | ||
399 | |||
374 | nr_pages = min(unused_resv_pages, surplus_huge_pages); | 400 | nr_pages = min(unused_resv_pages, surplus_huge_pages); |
375 | 401 | ||
376 | while (nr_pages) { | 402 | while (nr_pages) { |
@@ -402,7 +428,7 @@ static struct page *alloc_huge_page_shared(struct vm_area_struct *vma, | |||
402 | struct page *page; | 428 | struct page *page; |
403 | 429 | ||
404 | spin_lock(&hugetlb_lock); | 430 | spin_lock(&hugetlb_lock); |
405 | page = dequeue_huge_page(vma, addr); | 431 | page = dequeue_huge_page_vma(vma, addr); |
406 | spin_unlock(&hugetlb_lock); | 432 | spin_unlock(&hugetlb_lock); |
407 | return page ? page : ERR_PTR(-VM_FAULT_OOM); | 433 | return page ? page : ERR_PTR(-VM_FAULT_OOM); |
408 | } | 434 | } |
@@ -417,7 +443,7 @@ static struct page *alloc_huge_page_private(struct vm_area_struct *vma, | |||
417 | 443 | ||
418 | spin_lock(&hugetlb_lock); | 444 | spin_lock(&hugetlb_lock); |
419 | if (free_huge_pages > resv_huge_pages) | 445 | if (free_huge_pages > resv_huge_pages) |
420 | page = dequeue_huge_page(vma, addr); | 446 | page = dequeue_huge_page_vma(vma, addr); |
421 | spin_unlock(&hugetlb_lock); | 447 | spin_unlock(&hugetlb_lock); |
422 | if (!page) { | 448 | if (!page) { |
423 | page = alloc_buddy_huge_page(vma, addr); | 449 | page = alloc_buddy_huge_page(vma, addr); |
@@ -570,7 +596,7 @@ static unsigned long set_max_huge_pages(unsigned long count) | |||
570 | min_count = max(count, min_count); | 596 | min_count = max(count, min_count); |
571 | try_to_free_low(min_count); | 597 | try_to_free_low(min_count); |
572 | while (min_count < persistent_huge_pages) { | 598 | while (min_count < persistent_huge_pages) { |
573 | struct page *page = dequeue_huge_page(NULL, 0); | 599 | struct page *page = dequeue_huge_page(); |
574 | if (!page) | 600 | if (!page) |
575 | break; | 601 | break; |
576 | update_and_free_page(page); | 602 | update_and_free_page(page); |
@@ -1205,12 +1231,13 @@ static int hugetlb_acct_memory(long delta) | |||
1205 | if (gather_surplus_pages(delta) < 0) | 1231 | if (gather_surplus_pages(delta) < 0) |
1206 | goto out; | 1232 | goto out; |
1207 | 1233 | ||
1208 | if (delta > cpuset_mems_nr(free_huge_pages_node)) | 1234 | if (delta > cpuset_mems_nr(free_huge_pages_node)) { |
1235 | return_unused_surplus_pages(delta); | ||
1209 | goto out; | 1236 | goto out; |
1237 | } | ||
1210 | } | 1238 | } |
1211 | 1239 | ||
1212 | ret = 0; | 1240 | ret = 0; |
1213 | resv_huge_pages += delta; | ||
1214 | if (delta < 0) | 1241 | if (delta < 0) |
1215 | return_unused_surplus_pages((unsigned long) -delta); | 1242 | return_unused_surplus_pages((unsigned long) -delta); |
1216 | 1243 | ||