diff options
Diffstat (limited to 'arch/x86/mm/pageattr.c')
-rw-r--r-- | arch/x86/mm/pageattr.c | 35 |
1 files changed, 25 insertions, 10 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 831462c3bc35..e5d29a112d00 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -411,20 +411,29 @@ void __init cpa_init(void) | |||
411 | static int split_large_page(pte_t *kpte, unsigned long address) | 411 | static int split_large_page(pte_t *kpte, unsigned long address) |
412 | { | 412 | { |
413 | unsigned long flags, pfn, pfninc = 1; | 413 | unsigned long flags, pfn, pfninc = 1; |
414 | gfp_t gfp_flags = GFP_KERNEL; | ||
415 | unsigned int i, level; | 414 | unsigned int i, level; |
416 | pte_t *pbase, *tmp; | 415 | pte_t *pbase, *tmp; |
417 | pgprot_t ref_prot; | 416 | pgprot_t ref_prot; |
418 | struct page *base; | 417 | struct page *base; |
419 | 418 | ||
420 | #ifdef CONFIG_DEBUG_PAGEALLOC | 419 | /* |
421 | gfp_flags = GFP_ATOMIC | __GFP_NOWARN; | 420 | * Get a page from the pool. The pool list is protected by the |
422 | #endif | 421 | * pgd_lock, which we have to take anyway for the split |
423 | base = alloc_pages(gfp_flags, 0); | 422 | * operation: |
424 | if (!base) | 423 | */ |
424 | spin_lock_irqsave(&pgd_lock, flags); | ||
425 | if (list_empty(&page_pool)) { | ||
426 | spin_unlock_irqrestore(&pgd_lock, flags); | ||
425 | return -ENOMEM; | 427 | return -ENOMEM; |
428 | } | ||
429 | |||
430 | base = list_first_entry(&page_pool, struct page, lru); | ||
431 | list_del(&base->lru); | ||
432 | pool_pages--; | ||
433 | |||
434 | if (pool_pages < pool_low) | ||
435 | pool_low = pool_pages; | ||
426 | 436 | ||
427 | spin_lock_irqsave(&pgd_lock, flags); | ||
428 | /* | 437 | /* |
429 | * Check for races, another CPU might have split this page | 438 | * Check for races, another CPU might have split this page |
430 | * up for us already: | 439 | * up for us already: |
@@ -469,11 +478,17 @@ static int split_large_page(pte_t *kpte, unsigned long address) | |||
469 | base = NULL; | 478 | base = NULL; |
470 | 479 | ||
471 | out_unlock: | 480 | out_unlock: |
481 | /* | ||
482 | * If we dropped out via the lookup_address check under | ||
483 | * pgd_lock then stick the page back into the pool: | ||
484 | */ | ||
485 | if (base) { | ||
486 | list_add(&base->lru, &page_pool); | ||
487 | pool_pages++; | ||
488 | } else | ||
489 | pool_used++; | ||
472 | spin_unlock_irqrestore(&pgd_lock, flags); | 490 | spin_unlock_irqrestore(&pgd_lock, flags); |
473 | 491 | ||
474 | if (base) | ||
475 | __free_pages(base, 0); | ||
476 | |||
477 | return 0; | 492 | return 0; |
478 | } | 493 | } |
479 | 494 | ||