mm/thp: allocate transparent hugepages on local node

This make sure that we try to allocate hugepages from local node if
allowed by mempolicy.  If we can't, we fallback to small page allocation
based on mempolicy.  This is based on the observation that allocating
pages on local node is more beneficial than allocating hugepages on remote
node.

With this patch applied we may find transparent huge page allocation
failures if the current node doesn't have enough freee hugepages.  Before
this patch such failures result in us retrying the allocation on other
nodes in the numa node mask.

[[email protected]: fix comment, add CONFIG_TRANSPARENT_HUGEPAGE dependency]
Signed-off-by: Aneesh Kumar K.V <[email protected]>
Acked-by: Kirill A. Shutemov <[email protected]>
Acked-by: Vlastimil Babka <[email protected]>
Cc: David Rientjes <[email protected]>
Cc: Andrea Arcangeli <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
Aneesh Kumar K.V 2015-02-11 15:27:12 -08:00 • committed by Linus Torvalds
commit 077fcf116c
3 changed files with 85 additions and 15 deletions

View file

@ -2030,6 +2030,78 @@ retry_cpuset:
return page;
}
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
/**
* alloc_hugepage_vma: Allocate a hugepage for a VMA
* @gfp:
* %GFP_USER user allocation.
* %GFP_KERNEL kernel allocations,
* %GFP_HIGHMEM highmem/user allocations,
* %GFP_FS allocation should not call back into a file system.
* %GFP_ATOMIC don't sleep.
*
* @vma: Pointer to VMA or NULL if not available.
* @addr: Virtual Address of the allocation. Must be inside the VMA.
* @order: Order of the hugepage for gfp allocation.
*
* This functions allocate a huge page from the kernel page pool and applies
* a NUMA policy associated with the VMA or the current process.
* For policy other than %MPOL_INTERLEAVE, we make sure we allocate hugepage
* only from the current node if the current node is part of the node mask.
* If we can't allocate a hugepage we fail the allocation and don' try to fallback
* to other nodes in the node mask. If the current node is not part of node mask
* or if the NUMA policy is MPOL_INTERLEAVE we use the allocator that can
* fallback to nodes in the policy node mask.
*
* When VMA is not NULL caller must hold down_read on the mmap_sem of the
* mm_struct of the VMA to prevent it from going away. Should be used for
* all allocations for pages that will be mapped into
* user space. Returns NULL when no page can be allocated.
*
* Should be called with vma->vm_mm->mmap_sem held.
*
*/
struct page *alloc_hugepage_vma(gfp_t gfp, struct vm_area_struct *vma,
unsigned long addr, int order)
{
struct page *page;
nodemask_t *nmask;
struct mempolicy *pol;
int node = numa_node_id();
unsigned int cpuset_mems_cookie;
retry_cpuset:
pol = get_vma_policy(vma, addr);
cpuset_mems_cookie = read_mems_allowed_begin();
/*
* For interleave policy, we don't worry about
* current node. Otherwise if current node is
* in nodemask, try to allocate hugepage from
* the current node. Don't fall back to other nodes
* for THP.
*/
if (unlikely(pol->mode == MPOL_INTERLEAVE))
goto alloc_with_fallback;
nmask = policy_nodemask(gfp, pol);
if (!nmask || node_isset(node, *nmask)) {
mpol_cond_put(pol);
page = alloc_pages_exact_node(node, gfp, order);
if (unlikely(!page &&
read_mems_allowed_retry(cpuset_mems_cookie)))
goto retry_cpuset;
return page;
}
alloc_with_fallback:
mpol_cond_put(pol);
/*
* if current node is not part of node mask, try
* the allocation from any node, and we can do retry
* in that case.
*/
return alloc_pages_vma(gfp, order, vma, addr, node);
}
#endif
/**
* alloc_pages_current - Allocate pages.
*