Commit 396faf0303d273219db5d7eb4a2879ad977ed185

Authored by Mel Gorman
Committed by Linus Torvalds
1 parent 2a1e274acf

Allow huge page allocations to use GFP_HIGH_MOVABLE

Huge pages are not movable so are not allocated from ZONE_MOVABLE.  However,
as ZONE_MOVABLE will always have pages that can be migrated or reclaimed, it
can be used to satisfy hugepage allocations even when the system has been
running a long time.  This allows an administrator to resize the hugepage pool
at runtime depending on the size of ZONE_MOVABLE.

This patch adds a new sysctl called hugepages_treat_as_movable.  When a
non-zero value is written to it, future allocations for the huge page pool
will use ZONE_MOVABLE.  Despite huge pages being non-movable, we do not
introduce additional external fragmentation of note as huge pages are always
the largest contiguous block we care about.

[akpm@linux-foundation.org: various fixes]
Signed-off-by: Mel Gorman <mel@csn.ul.ie>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 5 changed files with 36 additions and 8 deletions Side-by-side Diff

include/linux/hugetlb.h
... ... @@ -15,6 +15,7 @@
15 15 }
16 16  
17 17 int hugetlb_sysctl_handler(struct ctl_table *, int, struct file *, void __user *, size_t *, loff_t *);
  18 +int hugetlb_treat_movable_handler(struct ctl_table *, int, struct file *, void __user *, size_t *, loff_t *);
18 19 int copy_hugetlb_page_range(struct mm_struct *, struct mm_struct *, struct vm_area_struct *);
19 20 int follow_hugetlb_page(struct mm_struct *, struct vm_area_struct *, struct page **, struct vm_area_struct **, unsigned long *, int *, int);
20 21 void unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned long);
... ... @@ -29,6 +30,7 @@
29 30 void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed);
30 31  
31 32 extern unsigned long max_huge_pages;
  33 +extern unsigned long hugepages_treat_as_movable;
32 34 extern const unsigned long hugetlb_zero, hugetlb_infinity;
33 35 extern int sysctl_hugetlb_shm_group;
34 36  
include/linux/mempolicy.h
... ... @@ -159,7 +159,7 @@
159 159  
160 160 extern struct mempolicy default_policy;
161 161 extern struct zonelist *huge_zonelist(struct vm_area_struct *vma,
162   - unsigned long addr);
  162 + unsigned long addr, gfp_t gfp_flags);
163 163 extern unsigned slab_node(struct mempolicy *policy);
164 164  
165 165 extern enum zone_type policy_zone;
166 166  
... ... @@ -256,9 +256,9 @@
256 256 #define set_cpuset_being_rebound(x) do {} while (0)
257 257  
258 258 static inline struct zonelist *huge_zonelist(struct vm_area_struct *vma,
259   - unsigned long addr)
  259 + unsigned long addr, gfp_t gfp_flags)
260 260 {
261   - return NODE_DATA(0)->node_zonelists + gfp_zone(GFP_HIGHUSER);
  261 + return NODE_DATA(0)->node_zonelists + gfp_zone(gfp_flags);
262 262 }
263 263  
264 264 static inline int do_migrate_pages(struct mm_struct *mm,
... ... @@ -826,6 +826,14 @@
826 826 .mode = 0644,
827 827 .proc_handler = &proc_dointvec,
828 828 },
  829 + {
  830 + .ctl_name = CTL_UNNUMBERED,
  831 + .procname = "hugepages_treat_as_movable",
  832 + .data = &hugepages_treat_as_movable,
  833 + .maxlen = sizeof(int),
  834 + .mode = 0644,
  835 + .proc_handler = &hugetlb_treat_movable_handler,
  836 + },
829 837 #endif
830 838 {
831 839 .ctl_name = VM_LOWMEM_RESERVE_RATIO,
... ... @@ -27,6 +27,9 @@
27 27 static struct list_head hugepage_freelists[MAX_NUMNODES];
28 28 static unsigned int nr_huge_pages_node[MAX_NUMNODES];
29 29 static unsigned int free_huge_pages_node[MAX_NUMNODES];
  30 +static gfp_t htlb_alloc_mask = GFP_HIGHUSER;
  31 +unsigned long hugepages_treat_as_movable;
  32 +
30 33 /*
31 34 * Protects updates to hugepage_freelists, nr_huge_pages, and free_huge_pages
32 35 */
33 36  
... ... @@ -68,12 +71,13 @@
68 71 {
69 72 int nid;
70 73 struct page *page = NULL;
71   - struct zonelist *zonelist = huge_zonelist(vma, address);
  74 + struct zonelist *zonelist = huge_zonelist(vma, address,
  75 + htlb_alloc_mask);
72 76 struct zone **z;
73 77  
74 78 for (z = zonelist->zones; *z; z++) {
75 79 nid = zone_to_nid(*z);
76   - if (cpuset_zone_allowed_softwall(*z, GFP_HIGHUSER) &&
  80 + if (cpuset_zone_allowed_softwall(*z, htlb_alloc_mask) &&
77 81 !list_empty(&hugepage_freelists[nid]))
78 82 break;
79 83 }
... ... @@ -113,7 +117,7 @@
113 117 prev_nid = nid;
114 118 spin_unlock(&nid_lock);
115 119  
116   - page = alloc_pages_node(nid, GFP_HIGHUSER|__GFP_COMP|__GFP_NOWARN,
  120 + page = alloc_pages_node(nid, htlb_alloc_mask|__GFP_COMP|__GFP_NOWARN,
117 121 HUGETLB_PAGE_ORDER);
118 122 if (page) {
119 123 set_compound_page_dtor(page, free_huge_page);
... ... @@ -263,6 +267,19 @@
263 267 max_huge_pages = set_max_huge_pages(max_huge_pages);
264 268 return 0;
265 269 }
  270 +
  271 +int hugetlb_treat_movable_handler(struct ctl_table *table, int write,
  272 + struct file *file, void __user *buffer,
  273 + size_t *length, loff_t *ppos)
  274 +{
  275 + proc_dointvec(table, write, file, buffer, length, ppos);
  276 + if (hugepages_treat_as_movable)
  277 + htlb_alloc_mask = GFP_HIGHUSER_MOVABLE;
  278 + else
  279 + htlb_alloc_mask = GFP_HIGHUSER;
  280 + return 0;
  281 +}
  282 +
266 283 #endif /* CONFIG_SYSCTL */
267 284  
268 285 int hugetlb_report_meminfo(char *buf)
... ... @@ -1203,7 +1203,8 @@
1203 1203  
1204 1204 #ifdef CONFIG_HUGETLBFS
1205 1205 /* Return a zonelist suitable for a huge page allocation. */
1206   -struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr)
  1206 +struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr,
  1207 + gfp_t gfp_flags)
1207 1208 {
1208 1209 struct mempolicy *pol = get_vma_policy(current, vma, addr);
1209 1210  
... ... @@ -1211,7 +1212,7 @@
1211 1212 unsigned nid;
1212 1213  
1213 1214 nid = interleave_nid(pol, vma, addr, HPAGE_SHIFT);
1214   - return NODE_DATA(nid)->node_zonelists + gfp_zone(GFP_HIGHUSER);
  1215 + return NODE_DATA(nid)->node_zonelists + gfp_zone(gfp_flags);
1215 1216 }
1216 1217 return zonelist_policy(GFP_HIGHUSER, pol);
1217 1218 }