Skip to content

Commit 75980e9

Browse files
Peter Zijlstratorvalds
authored andcommitted
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." [[email protected]: minor modifications] Signed-off-by: Mel Gorman <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Simon Jeons <[email protected]> Cc: Wanpeng Li <[email protected]> Cc: Hugh Dickins <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent bbeae5b commit 75980e9

File tree

4 files changed

+62
-10
lines changed

4 files changed

+62
-10
lines changed

include/linux/mm.h

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,10 +581,11 @@ static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma)
581581
* sets it, so none of the operations on it need to be atomic.
582582
*/
583583

584-
/* Page flags: | [SECTION] | [NODE] | ZONE | ... | FLAGS | */
584+
/* Page flags: | [SECTION] | [NODE] | ZONE | [LAST_NID] | ... | FLAGS | */
585585
#define SECTIONS_PGOFF ((sizeof(unsigned long)*8) - SECTIONS_WIDTH)
586586
#define NODES_PGOFF (SECTIONS_PGOFF - NODES_WIDTH)
587587
#define ZONES_PGOFF (NODES_PGOFF - ZONES_WIDTH)
588+
#define LAST_NID_PGOFF (ZONES_PGOFF - LAST_NID_WIDTH)
588589

589590
/*
590591
* 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)
594595
#define SECTIONS_PGSHIFT (SECTIONS_PGOFF * (SECTIONS_WIDTH != 0))
595596
#define NODES_PGSHIFT (NODES_PGOFF * (NODES_WIDTH != 0))
596597
#define ZONES_PGSHIFT (ZONES_PGOFF * (ZONES_WIDTH != 0))
598+
#define LAST_NID_PGSHIFT (LAST_NID_PGOFF * (LAST_NID_WIDTH != 0))
597599

598600
/* NODE:ZONE or SECTION:ZONE is used to ID a zone for the buddy allocator */
599601
#ifdef NODE_NOT_IN_PAGE_FLAGS
@@ -615,6 +617,7 @@ static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma)
615617
#define ZONES_MASK ((1UL << ZONES_WIDTH) - 1)
616618
#define NODES_MASK ((1UL << NODES_WIDTH) - 1)
617619
#define SECTIONS_MASK ((1UL << SECTIONS_WIDTH) - 1)
620+
#define LAST_NID_MASK ((1UL << LAST_NID_WIDTH) - 1)
618621
#define ZONEID_MASK ((1UL << ZONEID_SHIFT) - 1)
619622

620623
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)
654657
#endif
655658

656659
#ifdef CONFIG_NUMA_BALANCING
660+
#ifdef LAST_NID_NOT_IN_PAGE_FLAGS
657661
static inline int page_xchg_last_nid(struct page *page, int nid)
658662
{
659663
return xchg(&page->_last_nid, nid);
@@ -668,6 +672,33 @@ static inline void reset_page_last_nid(struct page *page)
668672
page->_last_nid = -1;
669673
}
670674
#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
671702
static inline int page_xchg_last_nid(struct page *page, int nid)
672703
{
673704
return page_to_nid(page);

include/linux/mm_types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ struct page {
174174
void *shadow;
175175
#endif
176176

177-
#ifdef CONFIG_NUMA_BALANCING
177+
#ifdef LAST_NID_NOT_IN_PAGE_FLAGS
178178
int _last_nid;
179179
#endif
180180
}

include/linux/page-flags-layout.h

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,16 @@
3232
/*
3333
* page->flags layout:
3434
*
35-
* There are three possibilities for how page->flags get
36-
* laid out. The first is for the normal case, without
37-
* sparsemem. The second is for sparsemem when there is
38-
* plenty of space for node and section. The last is when
39-
* we have run out of space and have to fall back to an
40-
* alternate (slower) way of determining the node.
35+
* There are five possibilities for how page->flags get laid out. The first
36+
* pair is for the normal case without sparsemem. The second pair is for
37+
* sparsemem when there is plenty of space for node and section information.
38+
* The last is when there is insufficient space in page->flags and a separate
39+
* lookup is necessary.
4140
*
42-
* No sparsemem or sparsemem vmemmap: | NODE | ZONE | ... | FLAGS |
43-
* classic sparse with space for node:| SECTION | NODE | ZONE | ... | FLAGS |
41+
* No sparsemem or sparsemem vmemmap: | 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 |
4445
* classic sparse no space for node: | SECTION | ZONE | ... | FLAGS |
4546
*/
4647
#if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
@@ -60,6 +61,18 @@
6061
#define NODES_WIDTH 0
6162
#endif
6263

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+
6376
/*
6477
* We are going to use the flags for the page to node mapping if its in
6578
* there. This includes the case where there is no node, so it is implicit.
@@ -68,4 +81,8 @@
6881
#define NODE_NOT_IN_PAGE_FLAGS
6982
#endif
7083

84+
#if defined(CONFIG_NUMA_BALANCING) && LAST_NID_WIDTH == 0
85+
#define LAST_NID_NOT_IN_PAGE_FLAGS
86+
#endif
87+
7188
#endif /* _LINUX_PAGE_FLAGS_LAYOUT */

mm/memory.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@
6969

7070
#include "internal.h"
7171

72+
#ifdef LAST_NID_NOT_IN_PAGE_FLAGS
73+
#warning Unfortunate NUMA and NUMA Balancing config, growing page-frame for last_nid.
74+
#endif
75+
7276
#ifndef CONFIG_NEED_MULTIPLE_NODES
7377
/* use the per-pgdat data instead for discontigmem - mbligh */
7478
unsigned long max_mapnr;

0 commit comments

Comments
 (0)