aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Hocko <mhocko@suse.com>2018-01-31 19:21:00 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2018-01-31 20:18:40 -0500
commitebd637235890a3fa6a6d4bb57522098f2f59c693 (patch)
tree38d94923e0db467924caa423fa82a5292ac7a4cc
parent0c397daea1d456f304e00413ee9e90a1830868a5 (diff)
hugetlb, mempolicy: fix the mbind hugetlb migration
do_mbind migration code relies on alloc_huge_page_noerr for hugetlb pages. alloc_huge_page_noerr uses alloc_huge_page which is a highlevel allocation function which has to take care of reserves, overcommit or hugetlb cgroup accounting. None of that is really required for the page migration because the new page is only temporal and either will replace the original page or it will be dropped. This is essentially as for other migration call paths and there shouldn't be any reason to handle mbind in a special way. The current implementation is even suboptimal because the migration might fail just because the hugetlb cgroup limit is reached, or the overcommit is saturated. Fix this by making mbind like other hugetlb migration paths. Add a new migration helper alloc_huge_page_vma as a wrapper around alloc_huge_page_nodemask with additional mempolicy handling. alloc_huge_page_noerr has no more users and it can go. Link: http://lkml.kernel.org/r/20180103093213.26329-7-mhocko@kernel.org Signed-off-by: Michal Hocko <mhocko@suse.com> Reviewed-by: Mike Kravetz <mike.kravetz@oracle.com> Reviewed-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> Cc: Andrea Reale <ar@linux.vnet.ibm.com> Cc: Anshuman Khandual <khandual@linux.vnet.ibm.com> Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: Zi Yan <zi.yan@cs.rutgers.edu> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/hugetlb.h5
-rw-r--r--mm/hugetlb.c33
-rw-r--r--mm/mempolicy.c3
3 files changed, 22 insertions, 19 deletions
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 66992348531e..612a29b7f6c6 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -356,10 +356,9 @@ struct huge_bootmem_page {
356struct page *alloc_huge_page(struct vm_area_struct *vma, 356struct page *alloc_huge_page(struct vm_area_struct *vma,
357 unsigned long addr, int avoid_reserve); 357 unsigned long addr, int avoid_reserve);
358struct page *alloc_huge_page_node(struct hstate *h, int nid); 358struct page *alloc_huge_page_node(struct hstate *h, int nid);
359struct page *alloc_huge_page_noerr(struct vm_area_struct *vma,
360 unsigned long addr, int avoid_reserve);
361struct page *alloc_huge_page_nodemask(struct hstate *h, int preferred_nid, 359struct page *alloc_huge_page_nodemask(struct hstate *h, int preferred_nid,
362 nodemask_t *nmask); 360 nodemask_t *nmask);
361struct page *alloc_huge_page_vma(struct vm_area_struct *vma, unsigned long address);
363int huge_add_to_page_cache(struct page *page, struct address_space *mapping, 362int huge_add_to_page_cache(struct page *page, struct address_space *mapping,
364 pgoff_t idx); 363 pgoff_t idx);
365 364
@@ -537,7 +536,7 @@ struct hstate {};
537#define alloc_huge_page(v, a, r) NULL 536#define alloc_huge_page(v, a, r) NULL
538#define alloc_huge_page_node(h, nid) NULL 537#define alloc_huge_page_node(h, nid) NULL
539#define alloc_huge_page_nodemask(h, preferred_nid, nmask) NULL 538#define alloc_huge_page_nodemask(h, preferred_nid, nmask) NULL
540#define alloc_huge_page_noerr(v, a, r) NULL 539#define alloc_huge_page_vma(vma, address) NULL
541#define alloc_bootmem_huge_page(h) NULL 540#define alloc_bootmem_huge_page(h) NULL
542#define hstate_file(f) NULL 541#define hstate_file(f) NULL
543#define hstate_sizelog(s) NULL 542#define hstate_sizelog(s) NULL
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index b55886af82aa..742a929f2311 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1674,6 +1674,25 @@ struct page *alloc_huge_page_nodemask(struct hstate *h, int preferred_nid,
1674 return alloc_migrate_huge_page(h, gfp_mask, preferred_nid, nmask); 1674 return alloc_migrate_huge_page(h, gfp_mask, preferred_nid, nmask);
1675} 1675}
1676 1676
1677/* mempolicy aware migration callback */
1678struct page *alloc_huge_page_vma(struct vm_area_struct *vma, unsigned long address)
1679{
1680 struct mempolicy *mpol;
1681 nodemask_t *nodemask;
1682 struct page *page;
1683 struct hstate *h;
1684 gfp_t gfp_mask;
1685 int node;
1686
1687 h = hstate_vma(vma);
1688 gfp_mask = htlb_alloc_mask(h);
1689 node = huge_node(vma, address, gfp_mask, &mpol, &nodemask);
1690 page = alloc_huge_page_nodemask(h, node, nodemask);
1691 mpol_cond_put(mpol);
1692
1693 return page;
1694}
1695
1677/* 1696/*
1678 * Increase the hugetlb pool such that it can accommodate a reservation 1697 * Increase the hugetlb pool such that it can accommodate a reservation
1679 * of size 'delta'. 1698 * of size 'delta'.
@@ -2079,20 +2098,6 @@ out_subpool_put:
2079 return ERR_PTR(-ENOSPC); 2098 return ERR_PTR(-ENOSPC);
2080} 2099}
2081 2100
2082/*
2083 * alloc_huge_page()'s wrapper which simply returns the page if allocation
2084 * succeeds, otherwise NULL. This function is called from new_vma_page(),
2085 * where no ERR_VALUE is expected to be returned.
2086 */
2087struct page *alloc_huge_page_noerr(struct vm_area_struct *vma,
2088 unsigned long addr, int avoid_reserve)
2089{
2090 struct page *page = alloc_huge_page(vma, addr, avoid_reserve);
2091 if (IS_ERR(page))
2092 page = NULL;
2093 return page;
2094}
2095
2096int alloc_bootmem_huge_page(struct hstate *h) 2101int alloc_bootmem_huge_page(struct hstate *h)
2097 __attribute__ ((weak, alias("__alloc_bootmem_huge_page"))); 2102 __attribute__ ((weak, alias("__alloc_bootmem_huge_page")));
2098int __alloc_bootmem_huge_page(struct hstate *h) 2103int __alloc_bootmem_huge_page(struct hstate *h)
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index f604b22ebb65..96823fa07f38 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -1121,8 +1121,7 @@ static struct page *new_page(struct page *page, unsigned long start, int **x)
1121 } 1121 }
1122 1122
1123 if (PageHuge(page)) { 1123 if (PageHuge(page)) {
1124 BUG_ON(!vma); 1124 return alloc_huge_page_vma(vma, address);
1125 return alloc_huge_page_noerr(vma, address, 1);
1126 } else if (thp_migration_supported() && PageTransHuge(page)) { 1125 } else if (thp_migration_supported() && PageTransHuge(page)) {
1127 struct page *thp; 1126 struct page *thp;
1128 1127