aboutsummaryrefslogtreecommitdiffstats
path: root/mm/page_alloc.c
diff options
context:
space:
mode:
authorAndy Whitcroft <apw@shadowen.org>2005-06-23 03:07:54 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-23 12:45:04 -0400
commitd41dee369bff3b9dcb6328d4d822926c28cc2594 (patch)
treea0405f3b7af3ebca21838a7d427bd75a067bf850 /mm/page_alloc.c
parentaf705362ab6018071310c5fcd436a6b457517d5f (diff)
[PATCH] sparsemem memory model
Sparsemem abstracts the use of discontiguous mem_maps[]. This kind of mem_map[] is needed by discontiguous memory machines (like in the old CONFIG_DISCONTIGMEM case) as well as memory hotplug systems. Sparsemem replaces DISCONTIGMEM when enabled, and it is hoped that it can eventually become a complete replacement. A significant advantage over DISCONTIGMEM is that it's completely separated from CONFIG_NUMA. When producing this patch, it became apparent in that NUMA and DISCONTIG are often confused. Another advantage is that sparse doesn't require each NUMA node's ranges to be contiguous. It can handle overlapping ranges between nodes with no problems, where DISCONTIGMEM currently throws away that memory. Sparsemem uses an array to provide different pfn_to_page() translations for each SECTION_SIZE area of physical memory. This is what allows the mem_map[] to be chopped up. In order to do quick pfn_to_page() operations, the section number of the page is encoded in page->flags. Part of the sparsemem infrastructure enables sharing of these bits more dynamically (at compile-time) between the page_zone() and sparsemem operations. However, on 32-bit architectures, the number of bits is quite limited, and may require growing the size of the page->flags type in certain conditions. Several things might force this to occur: a decrease in the SECTION_SIZE (if you want to hotplug smaller areas of memory), an increase in the physical address space, or an increase in the number of used page->flags. One thing to note is that, once sparsemem is present, the NUMA node information no longer needs to be stored in the page->flags. It might provide speed increases on certain platforms and will be stored there if there is room. But, if out of room, an alternate (theoretically slower) mechanism is used. This patch introduces CONFIG_FLATMEM. It is used in almost all cases where there used to be an #ifndef DISCONTIG, because SPARSEMEM and DISCONTIGMEM often have to compile out the same areas of code. Signed-off-by: Andy Whitcroft <apw@shadowen.org> Signed-off-by: Dave Hansen <haveblue@us.ibm.com> Signed-off-by: Martin Bligh <mbligh@aracnet.com> Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Yasunori Goto <y-goto@jp.fujitsu.com> Signed-off-by: Bob Picco <bob.picco@hp.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r--mm/page_alloc.c39
1 files changed, 30 insertions, 9 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 20e239599db0..5c1b8982a6da 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -68,7 +68,7 @@ EXPORT_SYMBOL(nr_swap_pages);
68 * Used by page_zone() to look up the address of the struct zone whose 68 * Used by page_zone() to look up the address of the struct zone whose
69 * id is encoded in the upper bits of page->flags 69 * id is encoded in the upper bits of page->flags
70 */ 70 */
71struct zone *zone_table[1 << (ZONES_SHIFT + NODES_SHIFT)]; 71struct zone *zone_table[1 << ZONETABLE_SHIFT];
72EXPORT_SYMBOL(zone_table); 72EXPORT_SYMBOL(zone_table);
73 73
74static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" }; 74static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" };
@@ -1649,11 +1649,15 @@ static void __init calculate_zone_totalpages(struct pglist_data *pgdat,
1649void __init memmap_init_zone(unsigned long size, int nid, unsigned long zone, 1649void __init memmap_init_zone(unsigned long size, int nid, unsigned long zone,
1650 unsigned long start_pfn) 1650 unsigned long start_pfn)
1651{ 1651{
1652 struct page *start = pfn_to_page(start_pfn);
1653 struct page *page; 1652 struct page *page;
1653 int end_pfn = start_pfn + size;
1654 int pfn;
1654 1655
1655 for (page = start; page < (start + size); page++) { 1656 for (pfn = start_pfn; pfn < end_pfn; pfn++, page++) {
1656 set_page_links(page, zone, nid); 1657 if (!early_pfn_valid(pfn))
1658 continue;
1659 page = pfn_to_page(pfn);
1660 set_page_links(page, zone, nid, pfn);
1657 set_page_count(page, 0); 1661 set_page_count(page, 0);
1658 reset_page_mapcount(page); 1662 reset_page_mapcount(page);
1659 SetPageReserved(page); 1663 SetPageReserved(page);
@@ -1677,6 +1681,20 @@ void zone_init_free_lists(struct pglist_data *pgdat, struct zone *zone,
1677 } 1681 }
1678} 1682}
1679 1683
1684#define ZONETABLE_INDEX(x, zone_nr) ((x << ZONES_SHIFT) | zone_nr)
1685void zonetable_add(struct zone *zone, int nid, int zid, unsigned long pfn,
1686 unsigned long size)
1687{
1688 unsigned long snum = pfn_to_section_nr(pfn);
1689 unsigned long end = pfn_to_section_nr(pfn + size);
1690
1691 if (FLAGS_HAS_NODE)
1692 zone_table[ZONETABLE_INDEX(nid, zid)] = zone;
1693 else
1694 for (; snum <= end; snum++)
1695 zone_table[ZONETABLE_INDEX(snum, zid)] = zone;
1696}
1697
1680#ifndef __HAVE_ARCH_MEMMAP_INIT 1698#ifndef __HAVE_ARCH_MEMMAP_INIT
1681#define memmap_init(size, nid, zone, start_pfn) \ 1699#define memmap_init(size, nid, zone, start_pfn) \
1682 memmap_init_zone((size), (nid), (zone), (start_pfn)) 1700 memmap_init_zone((size), (nid), (zone), (start_pfn))
@@ -1861,7 +1879,6 @@ static void __init free_area_init_core(struct pglist_data *pgdat,
1861 unsigned long size, realsize; 1879 unsigned long size, realsize;
1862 unsigned long batch; 1880 unsigned long batch;
1863 1881
1864 zone_table[NODEZONE(nid, j)] = zone;
1865 realsize = size = zones_size[j]; 1882 realsize = size = zones_size[j];
1866 if (zholes_size) 1883 if (zholes_size)
1867 realsize -= zholes_size[j]; 1884 realsize -= zholes_size[j];
@@ -1927,6 +1944,8 @@ static void __init free_area_init_core(struct pglist_data *pgdat,
1927 1944
1928 memmap_init(size, nid, j, zone_start_pfn); 1945 memmap_init(size, nid, j, zone_start_pfn);
1929 1946
1947 zonetable_add(zone, nid, j, zone_start_pfn, size);
1948
1930 zone_start_pfn += size; 1949 zone_start_pfn += size;
1931 1950
1932 zone_init_free_lists(pgdat, zone, zone->spanned_pages); 1951 zone_init_free_lists(pgdat, zone, zone->spanned_pages);
@@ -1935,28 +1954,30 @@ static void __init free_area_init_core(struct pglist_data *pgdat,
1935 1954
1936static void __init alloc_node_mem_map(struct pglist_data *pgdat) 1955static void __init alloc_node_mem_map(struct pglist_data *pgdat)
1937{ 1956{
1938 unsigned long size;
1939 struct page *map;
1940
1941 /* Skip empty nodes */ 1957 /* Skip empty nodes */
1942 if (!pgdat->node_spanned_pages) 1958 if (!pgdat->node_spanned_pages)
1943 return; 1959 return;
1944 1960
1961#ifdef CONFIG_FLAT_NODE_MEM_MAP
1945 /* ia64 gets its own node_mem_map, before this, without bootmem */ 1962 /* ia64 gets its own node_mem_map, before this, without bootmem */
1946 if (!pgdat->node_mem_map) { 1963 if (!pgdat->node_mem_map) {
1964 unsigned long size;
1965 struct page *map;
1966
1947 size = (pgdat->node_spanned_pages + 1) * sizeof(struct page); 1967 size = (pgdat->node_spanned_pages + 1) * sizeof(struct page);
1948 map = alloc_remap(pgdat->node_id, size); 1968 map = alloc_remap(pgdat->node_id, size);
1949 if (!map) 1969 if (!map)
1950 map = alloc_bootmem_node(pgdat, size); 1970 map = alloc_bootmem_node(pgdat, size);
1951 pgdat->node_mem_map = map; 1971 pgdat->node_mem_map = map;
1952 } 1972 }
1953#ifndef CONFIG_DISCONTIGMEM 1973#ifdef CONFIG_FLATMEM
1954 /* 1974 /*
1955 * With no DISCONTIG, the global mem_map is just set as node 0's 1975 * With no DISCONTIG, the global mem_map is just set as node 0's
1956 */ 1976 */
1957 if (pgdat == NODE_DATA(0)) 1977 if (pgdat == NODE_DATA(0))
1958 mem_map = NODE_DATA(0)->node_mem_map; 1978 mem_map = NODE_DATA(0)->node_mem_map;
1959#endif 1979#endif
1980#endif /* CONFIG_FLAT_NODE_MEM_MAP */
1960} 1981}
1961 1982
1962void __init free_area_init_node(int nid, struct pglist_data *pgdat, 1983void __init free_area_init_node(int nid, struct pglist_data *pgdat,