Commit a2f3aa02576632cdb60bd3de1f4bf55e9ac65604

Authored by Dave Hansen
Committed by Linus Torvalds
1 parent 47a4d5be7c

[PATCH] Fix sparsemem on Cell

Fix an oops experienced on the Cell architecture when init-time functions,
early_*(), are called at runtime.  It alters the call paths to make sure
that the callers explicitly say whether the call is being made on behalf of
a hotplug even, or happening at boot-time.

It has been compile tested on ppc64, ia64, s390, i386 and x86_64.

Acked-by: Arnd Bergmann <arndb@de.ibm.com>
Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
Cc: Yasunori Goto <y-goto@jp.fujitsu.com>
Acked-by: Andy Whitcroft <apw@shadowen.org>
Cc: Christoph Lameter <clameter@engr.sgi.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 6 changed files with 34 additions and 16 deletions Side-by-side Diff

... ... @@ -543,7 +543,8 @@
543 543  
544 544 if (map_start < map_end)
545 545 memmap_init_zone((unsigned long)(map_end - map_start),
546   - args->nid, args->zone, page_to_pfn(map_start));
  546 + args->nid, args->zone, page_to_pfn(map_start),
  547 + MEMMAP_EARLY);
547 548 return 0;
548 549 }
549 550  
... ... @@ -552,7 +553,7 @@
552 553 unsigned long start_pfn)
553 554 {
554 555 if (!vmem_map)
555   - memmap_init_zone(size, nid, zone, start_pfn);
  556 + memmap_init_zone(size, nid, zone, start_pfn, MEMMAP_EARLY);
556 557 else {
557 558 struct page *start;
558 559 struct memmap_init_callback_data args;
... ... @@ -61,7 +61,8 @@
61 61  
62 62 if (map_start < map_end)
63 63 memmap_init_zone((unsigned long)(map_end - map_start),
64   - nid, zone, page_to_pfn(map_start));
  64 + nid, zone, page_to_pfn(map_start),
  65 + MEMMAP_EARLY);
65 66 }
66 67 }
67 68  
... ... @@ -978,7 +978,8 @@
978 978 #endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */
979 979 #endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
980 980 extern void set_dma_reserve(unsigned long new_dma_reserve);
981   -extern void memmap_init_zone(unsigned long, int, unsigned long, unsigned long);
  981 +extern void memmap_init_zone(unsigned long, int, unsigned long,
  982 + unsigned long, enum memmap_context);
982 983 extern void setup_per_zone_pages_min(void);
983 984 extern void mem_init(void);
984 985 extern void show_mem(void);
include/linux/mmzone.h
... ... @@ -450,9 +450,13 @@
450 450 void wakeup_kswapd(struct zone *zone, int order);
451 451 int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
452 452 int classzone_idx, int alloc_flags);
453   -
  453 +enum memmap_context {
  454 + MEMMAP_EARLY,
  455 + MEMMAP_HOTPLUG,
  456 +};
454 457 extern int init_currently_empty_zone(struct zone *zone, unsigned long start_pfn,
455   - unsigned long size);
  458 + unsigned long size,
  459 + enum memmap_context context);
456 460  
457 461 #ifdef CONFIG_HAVE_MEMORY_PRESENT
458 462 void memory_present(int nid, unsigned long start, unsigned long end);
... ... @@ -67,11 +67,13 @@
67 67 zone_type = zone - pgdat->node_zones;
68 68 if (!populated_zone(zone)) {
69 69 int ret = 0;
70   - ret = init_currently_empty_zone(zone, phys_start_pfn, nr_pages);
  70 + ret = init_currently_empty_zone(zone, phys_start_pfn,
  71 + nr_pages, MEMMAP_HOTPLUG);
71 72 if (ret < 0)
72 73 return ret;
73 74 }
74   - memmap_init_zone(nr_pages, nid, zone_type, phys_start_pfn);
  75 + memmap_init_zone(nr_pages, nid, zone_type,
  76 + phys_start_pfn, MEMMAP_HOTPLUG);
75 77 return 0;
76 78 }
77 79  
... ... @@ -1956,17 +1956,24 @@
1956 1956 * done. Non-atomic initialization, single-pass.
1957 1957 */
1958 1958 void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
1959   - unsigned long start_pfn)
  1959 + unsigned long start_pfn, enum memmap_context context)
1960 1960 {
1961 1961 struct page *page;
1962 1962 unsigned long end_pfn = start_pfn + size;
1963 1963 unsigned long pfn;
1964 1964  
1965 1965 for (pfn = start_pfn; pfn < end_pfn; pfn++) {
1966   - if (!early_pfn_valid(pfn))
1967   - continue;
1968   - if (!early_pfn_in_nid(pfn, nid))
1969   - continue;
  1966 + /*
  1967 + * There can be holes in boot-time mem_map[]s
  1968 + * handed to this function. They do not
  1969 + * exist on hotplugged memory.
  1970 + */
  1971 + if (context == MEMMAP_EARLY) {
  1972 + if (!early_pfn_valid(pfn))
  1973 + continue;
  1974 + if (!early_pfn_in_nid(pfn, nid))
  1975 + continue;
  1976 + }
1970 1977 page = pfn_to_page(pfn);
1971 1978 set_page_links(page, zone, nid, pfn);
1972 1979 init_page_count(page);
... ... @@ -1993,7 +2000,7 @@
1993 2000  
1994 2001 #ifndef __HAVE_ARCH_MEMMAP_INIT
1995 2002 #define memmap_init(size, nid, zone, start_pfn) \
1996   - memmap_init_zone((size), (nid), (zone), (start_pfn))
  2003 + memmap_init_zone((size), (nid), (zone), (start_pfn), MEMMAP_EARLY)
1997 2004 #endif
1998 2005  
1999 2006 static int __cpuinit zone_batchsize(struct zone *zone)
... ... @@ -2239,7 +2246,8 @@
2239 2246  
2240 2247 __meminit int init_currently_empty_zone(struct zone *zone,
2241 2248 unsigned long zone_start_pfn,
2242   - unsigned long size)
  2249 + unsigned long size,
  2250 + enum memmap_context context)
2243 2251 {
2244 2252 struct pglist_data *pgdat = zone->zone_pgdat;
2245 2253 int ret;
... ... @@ -2683,7 +2691,8 @@
2683 2691 if (!size)
2684 2692 continue;
2685 2693  
2686   - ret = init_currently_empty_zone(zone, zone_start_pfn, size);
  2694 + ret = init_currently_empty_zone(zone, zone_start_pfn,
  2695 + size, MEMMAP_EARLY);
2687 2696 BUG_ON(ret);
2688 2697 zone_start_pfn += size;
2689 2698 }