Commit 769848c03895b63e5662eb7e4ec8c4866f7d0183

Authored by Mel Gorman
Committed by Linus Torvalds
1 parent a32ea1e1f9

Add __GFP_MOVABLE for callers to flag allocations from high memory that may be migrated

It is often known at allocation time whether a page may be migrated or not.
This patch adds a flag called __GFP_MOVABLE and a new mask called
GFP_HIGH_MOVABLE.  Allocations using the __GFP_MOVABLE can be either migrated
using the page migration mechanism or reclaimed by syncing with backing
storage and discarding.

An API function very similar to alloc_zeroed_user_highpage() is added for
__GFP_MOVABLE allocations called alloc_zeroed_user_highpage_movable().  The
flags used by alloc_zeroed_user_highpage() are not changed because it would
change the semantics of an existing API.  After this patch is applied there
are no in-kernel users of alloc_zeroed_user_highpage() so it probably should
be marked deprecated if this patch is merged.

Note that this patch includes a minor cleanup to the use of __GFP_ZERO in
shmem.c to keep all flag modifications to inode->mapping in the
shmem_dir_alloc() helper function.  This clean-up suggestion is courtesy of
Hugh Dickens.

Additional credit goes to Christoph Lameter and Linus Torvalds for shaping the
concept.  Credit to Hugh Dickens for catching issues with shmem swap vector
and ramfs allocations.

[akpm@linux-foundation.org: build fix]
[hugh@veritas.com: __GFP_ZERO cleanup]
Signed-off-by: Mel Gorman <mel@csn.ul.ie>
Cc: Andy Whitcroft <apw@shadowen.org>
Cc: Christoph Lameter <clameter@sgi.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 19 changed files with 114 additions and 30 deletions Side-by-side Diff

... ... @@ -982,7 +982,7 @@
982 982 struct buffer_head *bh;
983 983  
984 984 page = find_or_create_page(inode->i_mapping, index,
985   - mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
  985 + (mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS)|__GFP_MOVABLE);
986 986 if (!page)
987 987 return NULL;
988 988  
... ... @@ -145,7 +145,7 @@
145 145 mapping->a_ops = &empty_aops;
146 146 mapping->host = inode;
147 147 mapping->flags = 0;
148   - mapping_set_gfp_mask(mapping, GFP_HIGHUSER);
  148 + mapping_set_gfp_mask(mapping, GFP_HIGHUSER_PAGECACHE);
149 149 mapping->assoc_mapping = NULL;
150 150 mapping->backing_dev_info = &default_backing_dev_info;
151 151  
... ... @@ -519,7 +519,13 @@
519 519 * new_inode - obtain an inode
520 520 * @sb: superblock
521 521 *
522   - * Allocates a new inode for given superblock.
  522 + * Allocates a new inode for given superblock. The default gfp_mask
  523 + * for allocations related to inode->i_mapping is GFP_HIGHUSER_PAGECACHE.
  524 + * If HIGHMEM pages are unsuitable or it is known that pages allocated
  525 + * for the page cache are not reclaimable or migratable,
  526 + * mapping_set_gfp_mask() must be called with suitable flags on the
  527 + * newly created inode's mapping
  528 + *
523 529 */
524 530 struct inode *new_inode(struct super_block *sb)
525 531 {
... ... @@ -60,6 +60,7 @@
60 60 inode->i_blocks = 0;
61 61 inode->i_mapping->a_ops = &ramfs_aops;
62 62 inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
  63 + mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
63 64 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
64 65 switch (mode & S_IFMT) {
65 66 default:
include/asm-alpha/page.h
... ... @@ -17,7 +17,8 @@
17 17 extern void clear_page(void *page);
18 18 #define clear_user_page(page, vaddr, pg) clear_page(page)
19 19  
20   -#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vmaddr)
  20 +#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
  21 + alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vmaddr)
21 22 #define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
22 23  
23 24 extern void copy_page(void * _to, void * _from);
include/asm-cris/page.h
... ... @@ -20,7 +20,8 @@
20 20 #define clear_user_page(page, vaddr, pg) clear_page(page)
21 21 #define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
22 22  
23   -#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
  23 +#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
  24 + alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
24 25 #define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
25 26  
26 27 /*
include/asm-h8300/page.h
... ... @@ -22,7 +22,8 @@
22 22 #define clear_user_page(page, vaddr, pg) clear_page(page)
23 23 #define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
24 24  
25   -#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
  25 +#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
  26 + alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
26 27 #define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
27 28  
28 29 /*
include/asm-i386/page.h
... ... @@ -34,7 +34,8 @@
34 34 #define clear_user_page(page, vaddr, pg) clear_page(page)
35 35 #define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
36 36  
37   -#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
  37 +#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
  38 + alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
38 39 #define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
39 40  
40 41 /*
include/asm-ia64/page.h
... ... @@ -87,12 +87,13 @@
87 87 } while (0)
88 88  
89 89  
90   -#define alloc_zeroed_user_highpage(vma, vaddr) \
91   -({ \
92   - struct page *page = alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr); \
93   - if (page) \
94   - flush_dcache_page(page); \
95   - page; \
  90 +#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
  91 +({ \
  92 + struct page *page = alloc_page_vma( \
  93 + GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr); \
  94 + if (page) \
  95 + flush_dcache_page(page); \
  96 + page; \
96 97 })
97 98  
98 99 #define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
include/asm-m32r/page.h
... ... @@ -15,7 +15,8 @@
15 15 #define clear_user_page(page, vaddr, pg) clear_page(page)
16 16 #define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
17 17  
18   -#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
  18 +#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
  19 + alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
19 20 #define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
20 21  
21 22 /*
include/asm-m68knommu/page.h
... ... @@ -22,7 +22,8 @@
22 22 #define clear_user_page(page, vaddr, pg) clear_page(page)
23 23 #define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
24 24  
25   -#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
  25 +#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
  26 + alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
26 27 #define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
27 28  
28 29 /*
include/asm-s390/page.h
... ... @@ -64,7 +64,8 @@
64 64 #define clear_user_page(page, vaddr, pg) clear_page(page)
65 65 #define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
66 66  
67   -#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
  67 +#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
  68 + alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
68 69 #define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
69 70  
70 71 /*
include/asm-x86_64/page.h
... ... @@ -48,7 +48,8 @@
48 48 #define clear_user_page(page, vaddr, pg) clear_page(page)
49 49 #define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
50 50  
51   -#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
  51 +#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
  52 + alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
52 53 #define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
53 54 /*
54 55 * These are used to make use of C type-checking..
... ... @@ -30,6 +30,9 @@
30 30 * cannot handle allocation failures.
31 31 *
32 32 * __GFP_NORETRY: The VM implementation must not retry indefinitely.
  33 + *
  34 + * __GFP_MOVABLE: Flag that this page will be movable by the page migration
  35 + * mechanism or reclaimed
33 36 */
34 37 #define __GFP_WAIT ((__force gfp_t)0x10u) /* Can wait and reschedule? */
35 38 #define __GFP_HIGH ((__force gfp_t)0x20u) /* Should access emergency pools? */
... ... @@ -45,6 +48,7 @@
45 48 #define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */
46 49 #define __GFP_HARDWALL ((__force gfp_t)0x20000u) /* Enforce hardwall cpuset memory allocs */
47 50 #define __GFP_THISNODE ((__force gfp_t)0x40000u)/* No fallback, no policies */
  51 +#define __GFP_MOVABLE ((__force gfp_t)0x80000u) /* Page is movable */
48 52  
49 53 #define __GFP_BITS_SHIFT 20 /* Room for 20 __GFP_FOO bits */
50 54 #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
... ... @@ -53,7 +57,8 @@
53 57 #define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \
54 58 __GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| \
55 59 __GFP_NOFAIL|__GFP_NORETRY|__GFP_COMP| \
56   - __GFP_NOMEMALLOC|__GFP_HARDWALL|__GFP_THISNODE)
  60 + __GFP_NOMEMALLOC|__GFP_HARDWALL|__GFP_THISNODE| \
  61 + __GFP_MOVABLE)
57 62  
58 63 /* This equals 0, but use constants in case they ever change */
59 64 #define GFP_NOWAIT (GFP_ATOMIC & ~__GFP_HIGH)
... ... @@ -65,6 +70,15 @@
65 70 #define GFP_USER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL)
66 71 #define GFP_HIGHUSER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL | \
67 72 __GFP_HIGHMEM)
  73 +#define GFP_HIGHUSER_MOVABLE (__GFP_WAIT | __GFP_IO | __GFP_FS | \
  74 + __GFP_HARDWALL | __GFP_HIGHMEM | \
  75 + __GFP_MOVABLE)
  76 +#define GFP_NOFS_PAGECACHE (__GFP_WAIT | __GFP_IO | __GFP_MOVABLE)
  77 +#define GFP_USER_PAGECACHE (__GFP_WAIT | __GFP_IO | __GFP_FS | \
  78 + __GFP_HARDWALL | __GFP_MOVABLE)
  79 +#define GFP_HIGHUSER_PAGECACHE (__GFP_WAIT | __GFP_IO | __GFP_FS | \
  80 + __GFP_HARDWALL | __GFP_HIGHMEM | \
  81 + __GFP_MOVABLE)
68 82  
69 83 #ifdef CONFIG_NUMA
70 84 #define GFP_THISNODE (__GFP_THISNODE | __GFP_NOWARN | __GFP_NORETRY)
include/linux/highmem.h
... ... @@ -73,10 +73,27 @@
73 73 }
74 74  
75 75 #ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
  76 +/**
  77 + * __alloc_zeroed_user_highpage - Allocate a zeroed HIGHMEM page for a VMA with caller-specified movable GFP flags
  78 + * @movableflags: The GFP flags related to the pages future ability to move like __GFP_MOVABLE
  79 + * @vma: The VMA the page is to be allocated for
  80 + * @vaddr: The virtual address the page will be inserted into
  81 + *
  82 + * This function will allocate a page for a VMA but the caller is expected
  83 + * to specify via movableflags whether the page will be movable in the
  84 + * future or not
  85 + *
  86 + * An architecture may override this function by defining
  87 + * __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE and providing their own
  88 + * implementation.
  89 + */
76 90 static inline struct page *
77   -alloc_zeroed_user_highpage(struct vm_area_struct *vma, unsigned long vaddr)
  91 +__alloc_zeroed_user_highpage(gfp_t movableflags,
  92 + struct vm_area_struct *vma,
  93 + unsigned long vaddr)
78 94 {
79   - struct page *page = alloc_page_vma(GFP_HIGHUSER, vma, vaddr);
  95 + struct page *page = alloc_page_vma(GFP_HIGHUSER | movableflags,
  96 + vma, vaddr);
80 97  
81 98 if (page)
82 99 clear_user_highpage(page, vaddr);
... ... @@ -84,6 +101,36 @@
84 101 return page;
85 102 }
86 103 #endif
  104 +
  105 +/**
  106 + * alloc_zeroed_user_highpage - Allocate a zeroed HIGHMEM page for a VMA
  107 + * @vma: The VMA the page is to be allocated for
  108 + * @vaddr: The virtual address the page will be inserted into
  109 + *
  110 + * This function will allocate a page for a VMA that the caller knows will
  111 + * not be able to move in the future using move_pages() or reclaim. If it
  112 + * is known that the page can move, use alloc_zeroed_user_highpage_movable
  113 + */
  114 +static inline struct page *
  115 +alloc_zeroed_user_highpage(struct vm_area_struct *vma, unsigned long vaddr)
  116 +{
  117 + return __alloc_zeroed_user_highpage(0, vma, vaddr);
  118 +}
  119 +
  120 +/**
  121 + * alloc_zeroed_user_highpage_movable - Allocate a zeroed HIGHMEM page for a VMA that the caller knows can move
  122 + * @vma: The VMA the page is to be allocated for
  123 + * @vaddr: The virtual address the page will be inserted into
  124 + *
  125 + * This function will allocate a page for a VMA that the caller knows will
  126 + * be able to migrate in the future using move_pages() or reclaimed
  127 + */
  128 +static inline struct page *
  129 +alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
  130 + unsigned long vaddr)
  131 +{
  132 + return __alloc_zeroed_user_highpage(__GFP_MOVABLE, vma, vaddr);
  133 +}
87 134  
88 135 static inline void clear_highpage(struct page *page)
89 136 {
... ... @@ -1715,11 +1715,11 @@
1715 1715 if (unlikely(anon_vma_prepare(vma)))
1716 1716 goto oom;
1717 1717 if (old_page == ZERO_PAGE(address)) {
1718   - new_page = alloc_zeroed_user_highpage(vma, address);
  1718 + new_page = alloc_zeroed_user_highpage_movable(vma, address);
1719 1719 if (!new_page)
1720 1720 goto oom;
1721 1721 } else {
1722   - new_page = alloc_page_vma(GFP_HIGHUSER, vma, address);
  1722 + new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);
1723 1723 if (!new_page)
1724 1724 goto oom;
1725 1725 cow_user_page(new_page, old_page, address, vma);
... ... @@ -2237,7 +2237,7 @@
2237 2237  
2238 2238 if (unlikely(anon_vma_prepare(vma)))
2239 2239 goto oom;
2240   - page = alloc_zeroed_user_highpage(vma, address);
  2240 + page = alloc_zeroed_user_highpage_movable(vma, address);
2241 2241 if (!page)
2242 2242 goto oom;
2243 2243  
... ... @@ -2340,7 +2340,8 @@
2340 2340  
2341 2341 if (unlikely(anon_vma_prepare(vma)))
2342 2342 goto oom;
2343   - page = alloc_page_vma(GFP_HIGHUSER, vma, address);
  2343 + page = alloc_page_vma(GFP_HIGHUSER_MOVABLE,
  2344 + vma, address);
2344 2345 if (!page)
2345 2346 goto oom;
2346 2347 copy_user_highpage(page, new_page, address, vma);
... ... @@ -594,7 +594,7 @@
594 594  
595 595 static struct page *new_node_page(struct page *page, unsigned long node, int **x)
596 596 {
597   - return alloc_pages_node(node, GFP_HIGHUSER, 0);
  597 + return alloc_pages_node(node, GFP_HIGHUSER_MOVABLE, 0);
598 598 }
599 599  
600 600 /*
... ... @@ -710,7 +710,8 @@
710 710 {
711 711 struct vm_area_struct *vma = (struct vm_area_struct *)private;
712 712  
713   - return alloc_page_vma(GFP_HIGHUSER, vma, page_address_in_vma(page, vma));
  713 + return alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma,
  714 + page_address_in_vma(page, vma));
714 715 }
715 716 #else
716 717  
... ... @@ -761,7 +761,8 @@
761 761  
762 762 *result = &pm->status;
763 763  
764   - return alloc_pages_node(pm->node, GFP_HIGHUSER | GFP_THISNODE, 0);
  764 + return alloc_pages_node(pm->node,
  765 + GFP_HIGHUSER_MOVABLE | GFP_THISNODE, 0);
765 766 }
766 767  
767 768 /*
... ... @@ -93,8 +93,11 @@
93 93 * The above definition of ENTRIES_PER_PAGE, and the use of
94 94 * BLOCKS_PER_PAGE on indirect pages, assume PAGE_CACHE_SIZE:
95 95 * might be reconsidered if it ever diverges from PAGE_SIZE.
  96 + *
  97 + * __GFP_MOVABLE is masked out as swap vectors cannot move
96 98 */
97   - return alloc_pages(gfp_mask, PAGE_CACHE_SHIFT-PAGE_SHIFT);
  99 + return alloc_pages((gfp_mask & ~__GFP_MOVABLE) | __GFP_ZERO,
  100 + PAGE_CACHE_SHIFT-PAGE_SHIFT);
98 101 }
99 102  
100 103 static inline void shmem_dir_free(struct page *page)
... ... @@ -372,7 +375,7 @@
372 375 }
373 376  
374 377 spin_unlock(&info->lock);
375   - page = shmem_dir_alloc(mapping_gfp_mask(inode->i_mapping) | __GFP_ZERO);
  378 + page = shmem_dir_alloc(mapping_gfp_mask(inode->i_mapping));
376 379 if (page)
377 380 set_page_private(page, 0);
378 381 spin_lock(&info->lock);
... ... @@ -334,7 +334,8 @@
334 334 * Get a new page to read into from swap.
335 335 */
336 336 if (!new_page) {
337   - new_page = alloc_page_vma(GFP_HIGHUSER, vma, addr);
  337 + new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE,
  338 + vma, addr);
338 339 if (!new_page)
339 340 break; /* Out of memory */
340 341 }