diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2013-02-22 19:34:32 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-23 20:50:17 -0500 |
commit | 75980e97daccfc6babbac7e180ff118537955f5d (patch) | |
tree | b5721bae11eab21a8ee7c2ba4c7f153a59766dd6 /include/linux | |
parent | bbeae5b05ef6e40bf54db05ceb8635824153b9e2 (diff) |
mm: fold page->_last_nid into page->flags where possible
page->_last_nid fits into page->flags on 64-bit. The unlikely 32-bit
NUMA configuration with NUMA Balancing will still need an extra page
field. As Peter notes "Completely dropping 32bit support for
CONFIG_NUMA_BALANCING would simplify things, but it would also remove
the warning if we grow enough 64bit only page-flags to push the last-cpu
out."
[mgorman@suse.de: minor modifications]
Signed-off-by: Mel Gorman <mgorman@suse.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Simon Jeons <simon.jeons@gmail.com>
Cc: Wanpeng Li <liwanp@linux.vnet.ibm.com>
Cc: Hugh Dickins <hughd@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/linux')
-rw-r--r-- | include/linux/mm.h | 33 | ||||
-rw-r--r-- | include/linux/mm_types.h | 2 | ||||
-rw-r--r-- | include/linux/page-flags-layout.h | 33 |
3 files changed, 58 insertions, 10 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h index c2d7d5993b14..473abbda942e 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -581,10 +581,11 @@ static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma) | |||
581 | * sets it, so none of the operations on it need to be atomic. | 581 | * sets it, so none of the operations on it need to be atomic. |
582 | */ | 582 | */ |
583 | 583 | ||
584 | /* Page flags: | [SECTION] | [NODE] | ZONE | ... | FLAGS | */ | 584 | /* Page flags: | [SECTION] | [NODE] | ZONE | [LAST_NID] | ... | FLAGS | */ |
585 | #define SECTIONS_PGOFF ((sizeof(unsigned long)*8) - SECTIONS_WIDTH) | 585 | #define SECTIONS_PGOFF ((sizeof(unsigned long)*8) - SECTIONS_WIDTH) |
586 | #define NODES_PGOFF (SECTIONS_PGOFF - NODES_WIDTH) | 586 | #define NODES_PGOFF (SECTIONS_PGOFF - NODES_WIDTH) |
587 | #define ZONES_PGOFF (NODES_PGOFF - ZONES_WIDTH) | 587 | #define ZONES_PGOFF (NODES_PGOFF - ZONES_WIDTH) |
588 | #define LAST_NID_PGOFF (ZONES_PGOFF - LAST_NID_WIDTH) | ||
588 | 589 | ||
589 | /* | 590 | /* |
590 | * Define the bit shifts to access each section. For non-existent | 591 | * Define the bit shifts to access each section. For non-existent |
@@ -594,6 +595,7 @@ static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma) | |||
594 | #define SECTIONS_PGSHIFT (SECTIONS_PGOFF * (SECTIONS_WIDTH != 0)) | 595 | #define SECTIONS_PGSHIFT (SECTIONS_PGOFF * (SECTIONS_WIDTH != 0)) |
595 | #define NODES_PGSHIFT (NODES_PGOFF * (NODES_WIDTH != 0)) | 596 | #define NODES_PGSHIFT (NODES_PGOFF * (NODES_WIDTH != 0)) |
596 | #define ZONES_PGSHIFT (ZONES_PGOFF * (ZONES_WIDTH != 0)) | 597 | #define ZONES_PGSHIFT (ZONES_PGOFF * (ZONES_WIDTH != 0)) |
598 | #define LAST_NID_PGSHIFT (LAST_NID_PGOFF * (LAST_NID_WIDTH != 0)) | ||
597 | 599 | ||
598 | /* NODE:ZONE or SECTION:ZONE is used to ID a zone for the buddy allocator */ | 600 | /* NODE:ZONE or SECTION:ZONE is used to ID a zone for the buddy allocator */ |
599 | #ifdef NODE_NOT_IN_PAGE_FLAGS | 601 | #ifdef NODE_NOT_IN_PAGE_FLAGS |
@@ -615,6 +617,7 @@ static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma) | |||
615 | #define ZONES_MASK ((1UL << ZONES_WIDTH) - 1) | 617 | #define ZONES_MASK ((1UL << ZONES_WIDTH) - 1) |
616 | #define NODES_MASK ((1UL << NODES_WIDTH) - 1) | 618 | #define NODES_MASK ((1UL << NODES_WIDTH) - 1) |
617 | #define SECTIONS_MASK ((1UL << SECTIONS_WIDTH) - 1) | 619 | #define SECTIONS_MASK ((1UL << SECTIONS_WIDTH) - 1) |
620 | #define LAST_NID_MASK ((1UL << LAST_NID_WIDTH) - 1) | ||
618 | #define ZONEID_MASK ((1UL << ZONEID_SHIFT) - 1) | 621 | #define ZONEID_MASK ((1UL << ZONEID_SHIFT) - 1) |
619 | 622 | ||
620 | static inline enum zone_type page_zonenum(const struct page *page) | 623 | static inline enum zone_type page_zonenum(const struct page *page) |
@@ -654,6 +657,7 @@ static inline int page_to_nid(const struct page *page) | |||
654 | #endif | 657 | #endif |
655 | 658 | ||
656 | #ifdef CONFIG_NUMA_BALANCING | 659 | #ifdef CONFIG_NUMA_BALANCING |
660 | #ifdef LAST_NID_NOT_IN_PAGE_FLAGS | ||
657 | static inline int page_xchg_last_nid(struct page *page, int nid) | 661 | static inline int page_xchg_last_nid(struct page *page, int nid) |
658 | { | 662 | { |
659 | return xchg(&page->_last_nid, nid); | 663 | return xchg(&page->_last_nid, nid); |
@@ -668,6 +672,33 @@ static inline void reset_page_last_nid(struct page *page) | |||
668 | page->_last_nid = -1; | 672 | page->_last_nid = -1; |
669 | } | 673 | } |
670 | #else | 674 | #else |
675 | static inline int page_last_nid(struct page *page) | ||
676 | { | ||
677 | return (page->flags >> LAST_NID_PGSHIFT) & LAST_NID_MASK; | ||
678 | } | ||
679 | |||
680 | static inline int page_xchg_last_nid(struct page *page, int nid) | ||
681 | { | ||
682 | unsigned long old_flags, flags; | ||
683 | int last_nid; | ||
684 | |||
685 | do { | ||
686 | old_flags = flags = page->flags; | ||
687 | last_nid = page_last_nid(page); | ||
688 | |||
689 | flags &= ~(LAST_NID_MASK << LAST_NID_PGSHIFT); | ||
690 | flags |= (nid & LAST_NID_MASK) << LAST_NID_PGSHIFT; | ||
691 | } while (unlikely(cmpxchg(&page->flags, old_flags, flags) != old_flags)); | ||
692 | |||
693 | return last_nid; | ||
694 | } | ||
695 | |||
696 | static inline void reset_page_last_nid(struct page *page) | ||
697 | { | ||
698 | page_xchg_last_nid(page, (1 << LAST_NID_SHIFT) - 1); | ||
699 | } | ||
700 | #endif /* LAST_NID_NOT_IN_PAGE_FLAGS */ | ||
701 | #else | ||
671 | static inline int page_xchg_last_nid(struct page *page, int nid) | 702 | static inline int page_xchg_last_nid(struct page *page, int nid) |
672 | { | 703 | { |
673 | return page_to_nid(page); | 704 | return page_to_nid(page); |
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index d05d632c716e..ace9a5f01c64 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h | |||
@@ -174,7 +174,7 @@ struct page { | |||
174 | void *shadow; | 174 | void *shadow; |
175 | #endif | 175 | #endif |
176 | 176 | ||
177 | #ifdef CONFIG_NUMA_BALANCING | 177 | #ifdef LAST_NID_NOT_IN_PAGE_FLAGS |
178 | int _last_nid; | 178 | int _last_nid; |
179 | #endif | 179 | #endif |
180 | } | 180 | } |
diff --git a/include/linux/page-flags-layout.h b/include/linux/page-flags-layout.h index 316805d6ba1b..93506a114034 100644 --- a/include/linux/page-flags-layout.h +++ b/include/linux/page-flags-layout.h | |||
@@ -32,15 +32,16 @@ | |||
32 | /* | 32 | /* |
33 | * page->flags layout: | 33 | * page->flags layout: |
34 | * | 34 | * |
35 | * There are three possibilities for how page->flags get | 35 | * There are five possibilities for how page->flags get laid out. The first |
36 | * laid out. The first is for the normal case, without | 36 | * pair is for the normal case without sparsemem. The second pair is for |
37 | * sparsemem. The second is for sparsemem when there is | 37 | * sparsemem when there is plenty of space for node and section information. |
38 | * plenty of space for node and section. The last is when | 38 | * The last is when there is insufficient space in page->flags and a separate |
39 | * we have run out of space and have to fall back to an | 39 | * lookup is necessary. |
40 | * alternate (slower) way of determining the node. | ||
41 | * | 40 | * |
42 | * No sparsemem or sparsemem vmemmap: | NODE | ZONE | ... | FLAGS | | 41 | * No sparsemem or sparsemem vmemmap: | NODE | ZONE | ... | FLAGS | |
43 | * classic sparse with space for node:| SECTION | NODE | ZONE | ... | FLAGS | | 42 | * " plus space for last_nid: | NODE | ZONE | LAST_NID ... | FLAGS | |
43 | * classic sparse with space for node:| SECTION | NODE | ZONE | ... | FLAGS | | ||
44 | * " plus space for last_nid: | SECTION | NODE | ZONE | LAST_NID ... | FLAGS | | ||
44 | * classic sparse no space for node: | SECTION | ZONE | ... | FLAGS | | 45 | * classic sparse no space for node: | SECTION | ZONE | ... | FLAGS | |
45 | */ | 46 | */ |
46 | #if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP) | 47 | #if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP) |
@@ -60,6 +61,18 @@ | |||
60 | #define NODES_WIDTH 0 | 61 | #define NODES_WIDTH 0 |
61 | #endif | 62 | #endif |
62 | 63 | ||
64 | #ifdef CONFIG_NUMA_BALANCING | ||
65 | #define LAST_NID_SHIFT NODES_SHIFT | ||
66 | #else | ||
67 | #define LAST_NID_SHIFT 0 | ||
68 | #endif | ||
69 | |||
70 | #if SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT+LAST_NID_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS | ||
71 | #define LAST_NID_WIDTH LAST_NID_SHIFT | ||
72 | #else | ||
73 | #define LAST_NID_WIDTH 0 | ||
74 | #endif | ||
75 | |||
63 | /* | 76 | /* |
64 | * We are going to use the flags for the page to node mapping if its in | 77 | * We are going to use the flags for the page to node mapping if its in |
65 | * there. This includes the case where there is no node, so it is implicit. | 78 | * there. This includes the case where there is no node, so it is implicit. |
@@ -68,4 +81,8 @@ | |||
68 | #define NODE_NOT_IN_PAGE_FLAGS | 81 | #define NODE_NOT_IN_PAGE_FLAGS |
69 | #endif | 82 | #endif |
70 | 83 | ||
84 | #if defined(CONFIG_NUMA_BALANCING) && LAST_NID_WIDTH == 0 | ||
85 | #define LAST_NID_NOT_IN_PAGE_FLAGS | ||
86 | #endif | ||
87 | |||
71 | #endif /* _LINUX_PAGE_FLAGS_LAYOUT */ | 88 | #endif /* _LINUX_PAGE_FLAGS_LAYOUT */ |