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 | ||
