aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMel Gorman <mgorman@suse.de>2011-10-17 10:38:20 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-08-01 15:26:55 -0400
commit1126e70953638f9516b6a0b96385799c708815e4 (patch)
treeec88cddd81bc6d8df8e3172905e7d24a6ad86b7e
parent9116bc4fb2f96d4a3190932bf17088174da04401 (diff)
mm: memory hotplug: Check if pages are correctly reserved on a per-section basis
commit 2bbcb8788311a40714b585fc11b51da6ffa2ab92 upstream. Stable note: Fixes https://bugzilla.novell.com/show_bug.cgi?id=721039 . Without the patch, memory hot-add can fail for kernel configurations that do not set CONFIG_SPARSEMEM_VMEMMAP. (Resending as I am not seeing it in -next so maybe it got lost) mm: memory hotplug: Check if pages are correctly reserved on a per-section basis It is expected that memory being brought online is PageReserved similar to what happens when the page allocator is being brought up. Memory is onlined in "memory blocks" which consist of one or more sections. Unfortunately, the code that verifies PageReserved is currently assuming that the memmap backing all these pages is virtually contiguous which is only the case when CONFIG_SPARSEMEM_VMEMMAP is set. As a result, memory hot-add is failing on those configurations with the message; kernel: section number XXX page number 256 not reserved, was it already online? This patch updates the PageReserved check to lookup struct page once per section to guarantee the correct struct page is being checked. [Check pages within sections properly: rientjes@google.com] [original patch by: nfont@linux.vnet.ibm.com] Signed-off-by: Mel Gorman <mgorman@suse.de> Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Tested-by: Nathan Fontenot <nfont@linux.vnet.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/base/memory.c58
1 files changed, 40 insertions, 18 deletions
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 45d7c8fc73b..5fb6aaed2ad 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -224,13 +224,48 @@ int memory_isolate_notify(unsigned long val, void *v)
224} 224}
225 225
226/* 226/*
227 * The probe routines leave the pages reserved, just as the bootmem code does.
228 * Make sure they're still that way.
229 */
230static bool pages_correctly_reserved(unsigned long start_pfn,
231 unsigned long nr_pages)
232{
233 int i, j;
234 struct page *page;
235 unsigned long pfn = start_pfn;
236
237 /*
238 * memmap between sections is not contiguous except with
239 * SPARSEMEM_VMEMMAP. We lookup the page once per section
240 * and assume memmap is contiguous within each section
241 */
242 for (i = 0; i < sections_per_block; i++, pfn += PAGES_PER_SECTION) {
243 if (WARN_ON_ONCE(!pfn_valid(pfn)))
244 return false;
245 page = pfn_to_page(pfn);
246
247 for (j = 0; j < PAGES_PER_SECTION; j++) {
248 if (PageReserved(page + j))
249 continue;
250
251 printk(KERN_WARNING "section number %ld page number %d "
252 "not reserved, was it already online?\n",
253 pfn_to_section_nr(pfn), j);
254
255 return false;
256 }
257 }
258
259 return true;
260}
261
262/*
227 * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is 263 * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is
228 * OK to have direct references to sparsemem variables in here. 264 * OK to have direct references to sparsemem variables in here.
229 */ 265 */
230static int 266static int
231memory_block_action(unsigned long phys_index, unsigned long action) 267memory_block_action(unsigned long phys_index, unsigned long action)
232{ 268{
233 int i;
234 unsigned long start_pfn, start_paddr; 269 unsigned long start_pfn, start_paddr;
235 unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block; 270 unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
236 struct page *first_page; 271 struct page *first_page;
@@ -238,26 +273,13 @@ memory_block_action(unsigned long phys_index, unsigned long action)
238 273
239 first_page = pfn_to_page(phys_index << PFN_SECTION_SHIFT); 274 first_page = pfn_to_page(phys_index << PFN_SECTION_SHIFT);
240 275
241 /*
242 * The probe routines leave the pages reserved, just
243 * as the bootmem code does. Make sure they're still
244 * that way.
245 */
246 if (action == MEM_ONLINE) {
247 for (i = 0; i < nr_pages; i++) {
248 if (PageReserved(first_page+i))
249 continue;
250
251 printk(KERN_WARNING "section number %ld page number %d "
252 "not reserved, was it already online?\n",
253 phys_index, i);
254 return -EBUSY;
255 }
256 }
257
258 switch (action) { 276 switch (action) {
259 case MEM_ONLINE: 277 case MEM_ONLINE:
260 start_pfn = page_to_pfn(first_page); 278 start_pfn = page_to_pfn(first_page);
279
280 if (!pages_correctly_reserved(start_pfn, nr_pages))
281 return -EBUSY;
282
261 ret = online_pages(start_pfn, nr_pages); 283 ret = online_pages(start_pfn, nr_pages);
262 break; 284 break;
263 case MEM_OFFLINE: 285 case MEM_OFFLINE: