Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 2863
b: refs/heads/master
c: d41dee3
h: refs/heads/master
i:
  2861: 7e1bc9f
  2859: f7e3763
  2855: 5f2c008
  2847: 8bcad39
v: v3
  • Loading branch information
Andy Whitcroft authored and Linus Torvalds committed Jun 23, 2005
1 parent 44130ff commit 0aea3aa
Show file tree
Hide file tree
Showing 11 changed files with 333 additions and 34 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: af705362ab6018071310c5fcd436a6b457517d5f
refs/heads/master: d41dee369bff3b9dcb6328d4d822926c28cc2594
1 change: 1 addition & 0 deletions trunk/arch/i386/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,7 @@ source "mm/Kconfig"
config HAVE_ARCH_EARLY_PFN_TO_NID
bool
default y
depends on NUMA

config HIGHPTE
bool "Allocate 3rd-level pagetables from highmem"
Expand Down
92 changes: 75 additions & 17 deletions trunk/include/linux/mm.h
Original file line number Diff line number Diff line change
Expand Up @@ -397,40 +397,80 @@ static inline void put_page(struct page *page)
* sets it, so none of the operations on it need to be atomic.
*/

/* Page flags: | NODE | ZONE | ... | FLAGS | */
#define NODES_PGOFF ((sizeof(page_flags_t)*8) - NODES_SHIFT)
#define ZONES_PGOFF (NODES_PGOFF - ZONES_SHIFT)

/*
* page->flags layout:
*
* There are three possibilities for how page->flags get
* laid out. The first is for the normal case, without
* sparsemem. The second is for sparsemem when there is
* plenty of space for node and section. The last is when
* we have run out of space and have to fall back to an
* alternate (slower) way of determining the node.
*
* No sparsemem: | NODE | ZONE | ... | FLAGS |
* with space for node: | SECTION | NODE | ZONE | ... | FLAGS |
* no space for node: | SECTION | ZONE | ... | FLAGS |
*/
#ifdef CONFIG_SPARSEMEM
#define SECTIONS_WIDTH SECTIONS_SHIFT
#else
#define SECTIONS_WIDTH 0
#endif

#define ZONES_WIDTH ZONES_SHIFT

#if SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT <= FLAGS_RESERVED
#define NODES_WIDTH NODES_SHIFT
#else
#define NODES_WIDTH 0
#endif

/* Page flags: | [SECTION] | [NODE] | ZONE | ... | FLAGS | */
#define SECTIONS_PGOFF ((sizeof(page_flags_t)*8) - SECTIONS_WIDTH)
#define NODES_PGOFF (SECTIONS_PGOFF - NODES_WIDTH)
#define ZONES_PGOFF (NODES_PGOFF - ZONES_WIDTH)

/*
* We are going to use the flags for the page to node mapping if its in
* there. This includes the case where there is no node, so it is implicit.
*/
#define FLAGS_HAS_NODE (NODES_WIDTH > 0 || NODES_SHIFT == 0)

#ifndef PFN_SECTION_SHIFT
#define PFN_SECTION_SHIFT 0
#endif

/*
* Define the bit shifts to access each section. For non-existant
* sections we define the shift as 0; that plus a 0 mask ensures
* the compiler will optimise away reference to them.
*/
#define NODES_PGSHIFT (NODES_PGOFF * (NODES_SHIFT != 0))
#define ZONES_PGSHIFT (ZONES_PGOFF * (ZONES_SHIFT != 0))
#define SECTIONS_PGSHIFT (SECTIONS_PGOFF * (SECTIONS_WIDTH != 0))
#define NODES_PGSHIFT (NODES_PGOFF * (NODES_WIDTH != 0))
#define ZONES_PGSHIFT (ZONES_PGOFF * (ZONES_WIDTH != 0))

/* NODE:ZONE is used to lookup the zone from a page. */
/* NODE:ZONE or SECTION:ZONE is used to lookup the zone from a page. */
#if FLAGS_HAS_NODE
#define ZONETABLE_SHIFT (NODES_SHIFT + ZONES_SHIFT)
#else
#define ZONETABLE_SHIFT (SECTIONS_SHIFT + ZONES_SHIFT)
#endif
#define ZONETABLE_PGSHIFT ZONES_PGSHIFT

#if NODES_SHIFT+ZONES_SHIFT > FLAGS_RESERVED
#error NODES_SHIFT+ZONES_SHIFT > FLAGS_RESERVED
#if SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
#error SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
#endif

#define NODEZONE(node, zone) ((node << ZONES_SHIFT) | zone)

#define ZONES_MASK ((1UL << ZONES_SHIFT) - 1)
#define NODES_MASK ((1UL << NODES_SHIFT) - 1)
#define ZONES_MASK ((1UL << ZONES_WIDTH) - 1)
#define NODES_MASK ((1UL << NODES_WIDTH) - 1)
#define SECTIONS_MASK ((1UL << SECTIONS_WIDTH) - 1)
#define ZONETABLE_MASK ((1UL << ZONETABLE_SHIFT) - 1)

static inline unsigned long page_zonenum(struct page *page)
{
return (page->flags >> ZONES_PGSHIFT) & ZONES_MASK;
}
static inline unsigned long page_to_nid(struct page *page)
{
return (page->flags >> NODES_PGSHIFT) & NODES_MASK;
}

struct zone;
extern struct zone *zone_table[];
Expand All @@ -441,6 +481,18 @@ static inline struct zone *page_zone(struct page *page)
ZONETABLE_MASK];
}

static inline unsigned long page_to_nid(struct page *page)
{
if (FLAGS_HAS_NODE)
return (page->flags >> NODES_PGSHIFT) & NODES_MASK;
else
return page_zone(page)->zone_pgdat->node_id;
}
static inline unsigned long page_to_section(struct page *page)
{
return (page->flags >> SECTIONS_PGSHIFT) & SECTIONS_MASK;
}

static inline void set_page_zone(struct page *page, unsigned long zone)
{
page->flags &= ~(ZONES_MASK << ZONES_PGSHIFT);
Expand All @@ -451,12 +503,18 @@ static inline void set_page_node(struct page *page, unsigned long node)
page->flags &= ~(NODES_MASK << NODES_PGSHIFT);
page->flags |= (node & NODES_MASK) << NODES_PGSHIFT;
}
static inline void set_page_section(struct page *page, unsigned long section)
{
page->flags &= ~(SECTIONS_MASK << SECTIONS_PGSHIFT);
page->flags |= (section & SECTIONS_MASK) << SECTIONS_PGSHIFT;
}

static inline void set_page_links(struct page *page, unsigned long zone,
unsigned long node)
unsigned long node, unsigned long pfn)
{
set_page_zone(page, zone);
set_page_node(page, node);
set_page_section(page, pfn_to_section_nr(pfn));
}

#ifndef CONFIG_DISCONTIGMEM
Expand Down
96 changes: 96 additions & 0 deletions trunk/include/linux/mmzone.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,9 @@ typedef struct pglist_data {
struct zone node_zones[MAX_NR_ZONES];
struct zonelist node_zonelists[GFP_ZONETYPES];
int nr_zones;
#ifdef CONFIG_FLAT_NODE_MEM_MAP
struct page *node_mem_map;
#endif
struct bootmem_data *bdata;
unsigned long node_start_pfn;
unsigned long node_present_pages; /* total number of physical pages */
Expand All @@ -284,7 +286,11 @@ typedef struct pglist_data {

#define node_present_pages(nid) (NODE_DATA(nid)->node_present_pages)
#define node_spanned_pages(nid) (NODE_DATA(nid)->node_spanned_pages)
#ifdef CONFIG_FLAT_NODE_MEM_MAP
#define pgdat_page_nr(pgdat, pagenr) ((pgdat)->node_mem_map + (pagenr))
#else
#define pgdat_page_nr(pgdat, pagenr) pfn_to_page((pgdat)->node_start_pfn + (pagenr))
#endif
#define nid_page_nr(nid, pagenr) pgdat_page_nr(NODE_DATA(nid),(pagenr))

extern struct pglist_data *pgdat_list;
Expand Down Expand Up @@ -416,6 +422,10 @@ extern struct pglist_data contig_page_data;

#endif /* !CONFIG_NEED_MULTIPLE_NODES */

#ifdef CONFIG_SPARSEMEM
#include <asm/sparsemem.h>
#endif

#if BITS_PER_LONG == 32 || defined(ARCH_HAS_ATOMIC_UNSIGNED)
/*
* with 32 bit page->flags field, we reserve 8 bits for node/zone info.
Expand All @@ -439,6 +449,92 @@ extern struct pglist_data contig_page_data;
#define early_pfn_to_nid(nid) (0UL)
#endif

#define pfn_to_section_nr(pfn) ((pfn) >> PFN_SECTION_SHIFT)
#define section_nr_to_pfn(sec) ((sec) << PFN_SECTION_SHIFT)

#ifdef CONFIG_SPARSEMEM

/*
* SECTION_SHIFT #bits space required to store a section #
*
* PA_SECTION_SHIFT physical address to/from section number
* PFN_SECTION_SHIFT pfn to/from section number
*/
#define SECTIONS_SHIFT (MAX_PHYSMEM_BITS - SECTION_SIZE_BITS)

#define PA_SECTION_SHIFT (SECTION_SIZE_BITS)
#define PFN_SECTION_SHIFT (SECTION_SIZE_BITS - PAGE_SHIFT)

#define NR_MEM_SECTIONS (1UL << SECTIONS_SHIFT)

#define PAGES_PER_SECTION (1UL << PFN_SECTION_SHIFT)
#define PAGE_SECTION_MASK (~(PAGES_PER_SECTION-1))

#if (MAX_ORDER - 1 + PAGE_SHIFT) > SECTION_SIZE_BITS
#error Allocator MAX_ORDER exceeds SECTION_SIZE
#endif

struct page;
struct mem_section {
struct page *section_mem_map;
};

extern struct mem_section mem_section[NR_MEM_SECTIONS];

/*
* Given a kernel address, find the home node of the underlying memory.
*/
#define kvaddr_to_nid(kaddr) pfn_to_nid(__pa(kaddr) >> PAGE_SHIFT)

static inline struct mem_section *__pfn_to_section(unsigned long pfn)
{
return &mem_section[pfn_to_section_nr(pfn)];
}

#define pfn_to_page(pfn) \
({ \
unsigned long __pfn = (pfn); \
__pfn_to_section(__pfn)->section_mem_map + __pfn; \
})
#define page_to_pfn(page) \
({ \
page - mem_section[page_to_section(page)].section_mem_map; \
})

static inline int pfn_valid(unsigned long pfn)
{
if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
return 0;
return mem_section[pfn_to_section_nr(pfn)].section_mem_map != 0;
}

/*
* These are _only_ used during initialisation, therefore they
* can use __initdata ... They could have names to indicate
* this restriction.
*/
#ifdef CONFIG_NUMA
#define pfn_to_nid early_pfn_to_nid
#endif

#define pfn_to_pgdat(pfn) \
({ \
NODE_DATA(pfn_to_nid(pfn)); \
})

#define early_pfn_valid(pfn) pfn_valid(pfn)
void sparse_init(void);
#else
#define sparse_init() do {} while (0)
#endif /* CONFIG_SPARSEMEM */

#ifndef early_pfn_valid
#define early_pfn_valid(pfn) (1)
#endif

void memory_present(int nid, unsigned long start, unsigned long end);
unsigned long __init node_memmap_size_bytes(int, unsigned long, unsigned long);

#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* _LINUX_MMZONE_H */
2 changes: 1 addition & 1 deletion trunk/include/linux/numa.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#include <linux/config.h>

#ifdef CONFIG_DISCONTIGMEM
#ifndef CONFIG_FLATMEM
#include <asm/numnodes.h>
#endif

Expand Down
38 changes: 35 additions & 3 deletions trunk/mm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ choice
prompt "Memory model"
depends on SELECT_MEMORY_MODEL
default DISCONTIGMEM_MANUAL if ARCH_DISCONTIGMEM_DEFAULT
default SPARSEMEM_MANUAL if ARCH_SPARSEMEM_DEFAULT
default FLATMEM_MANUAL

config FLATMEM_MANUAL
Expand All @@ -17,7 +18,15 @@ config FLATMEM_MANUAL
only have one option here: FLATMEM. This is normal
and a correct option.

If unsure, choose this option over any other.
Some users of more advanced features like NUMA and
memory hotplug may have different options here.
DISCONTIGMEM is an more mature, better tested system,
but is incompatible with memory hotplug and may suffer
decreased performance over SPARSEMEM. If unsure between
"Sparse Memory" and "Discontiguous Memory", choose
"Discontiguous Memory".

If unsure, choose this option (Flat Memory) over any other.

config DISCONTIGMEM_MANUAL
bool "Discontigious Memory"
Expand All @@ -35,15 +44,38 @@ config DISCONTIGMEM_MANUAL

If unsure, choose "Flat Memory" over this option.

config SPARSEMEM_MANUAL
bool "Sparse Memory"
depends on ARCH_SPARSEMEM_ENABLE
help
This will be the only option for some systems, including
memory hotplug systems. This is normal.

For many other systems, this will be an alternative to
"Discontigious Memory". This option provides some potential
performance benefits, along with decreased code complexity,
but it is newer, and more experimental.

If unsure, choose "Discontiguous Memory" or "Flat Memory"
over this option.

endchoice

config DISCONTIGMEM
def_bool y
depends on (!SELECT_MEMORY_MODEL && ARCH_DISCONTIGMEM_ENABLE) || DISCONTIGMEM_MANUAL

config SPARSEMEM
def_bool y
depends on SPARSEMEM_MANUAL

config FLATMEM
def_bool y
depends on !DISCONTIGMEM || FLATMEM_MANUAL
depends on (!DISCONTIGMEM && !SPARSEMEM) || FLATMEM_MANUAL

config FLAT_NODE_MEM_MAP
def_bool y
depends on !SPARSEMEM

#
# Both the NUMA code and DISCONTIGMEM use arrays of pg_data_t's
Expand All @@ -56,4 +88,4 @@ config NEED_MULTIPLE_NODES

config HAVE_MEMORY_PRESENT
def_bool y
depends on ARCH_HAVE_MEMORY_PRESENT
depends on ARCH_HAVE_MEMORY_PRESENT || SPARSEMEM
1 change: 1 addition & 0 deletions trunk/mm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o thrash.o
obj-$(CONFIG_HUGETLBFS) += hugetlb.o
obj-$(CONFIG_NUMA) += mempolicy.o
obj-$(CONFIG_SPARSEMEM) += sparse.o
obj-$(CONFIG_SHMEM) += shmem.o
obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o

Loading

0 comments on commit 0aea3aa

Please sign in to comment.