Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / drivers / base / memory.c
index 2840ed4..8272d92 100644 (file)
@@ -223,6 +223,42 @@ int memory_isolate_notify(unsigned long val, void *v)
        return atomic_notifier_call_chain(&memory_isolate_chain, val, v);
 }
 
+/*
+ * The probe routines leave the pages reserved, just as the bootmem code does.
+ * Make sure they're still that way.
+ */
+static bool pages_correctly_reserved(unsigned long start_pfn,
+                                       unsigned long nr_pages)
+{
+       int i, j;
+       struct page *page;
+       unsigned long pfn = start_pfn;
+
+       /*
+        * memmap between sections is not contiguous except with
+        * SPARSEMEM_VMEMMAP. We lookup the page once per section
+        * and assume memmap is contiguous within each section
+        */
+       for (i = 0; i < sections_per_block; i++, pfn += PAGES_PER_SECTION) {
+               if (WARN_ON_ONCE(!pfn_valid(pfn)))
+                       return false;
+               page = pfn_to_page(pfn);
+
+               for (j = 0; j < PAGES_PER_SECTION; j++) {
+                       if (PageReserved(page + j))
+                               continue;
+
+                       printk(KERN_WARNING "section number %ld page number %d "
+                               "not reserved, was it already online?\n",
+                               pfn_to_section_nr(pfn), j);
+
+                       return false;
+               }
+       }
+
+       return true;
+}
+
 /*
  * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is
  * OK to have direct references to sparsemem variables in here.
@@ -230,7 +266,6 @@ int memory_isolate_notify(unsigned long val, void *v)
 static int
 memory_block_action(unsigned long phys_index, unsigned long action)
 {
-       int i;
        unsigned long start_pfn, start_paddr;
        unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
        struct page *first_page;
@@ -238,26 +273,13 @@ memory_block_action(unsigned long phys_index, unsigned long action)
 
        first_page = pfn_to_page(phys_index << PFN_SECTION_SHIFT);
 
-       /*
-        * The probe routines leave the pages reserved, just
-        * as the bootmem code does.  Make sure they're still
-        * that way.
-        */
-       if (action == MEM_ONLINE) {
-               for (i = 0; i < nr_pages; i++) {
-                       if (PageReserved(first_page+i))
-                               continue;
-
-                       printk(KERN_WARNING "section number %ld page number %d "
-                               "not reserved, was it already online?\n",
-                               phys_index, i);
-                       return -EBUSY;
-               }
-       }
-
        switch (action) {
                case MEM_ONLINE:
                        start_pfn = page_to_pfn(first_page);
+
+                       if (!pages_correctly_reserved(start_pfn, nr_pages))
+                               return -EBUSY;
+
                        ret = online_pages(start_pfn, nr_pages);
                        break;
                case MEM_OFFLINE:
@@ -380,9 +402,13 @@ memory_probe_store(struct class *class, struct class_attribute *attr,
        u64 phys_addr;
        int nid;
        int i, ret;
+       unsigned long pages_per_block = PAGES_PER_SECTION * sections_per_block;
 
        phys_addr = simple_strtoull(buf, NULL, 0);
 
+       if (phys_addr & ((pages_per_block << PAGE_SHIFT) - 1))
+               return -EINVAL;
+
        for (i = 0; i < sections_per_block; i++) {
                nid = memory_add_physaddr_to_nid(phys_addr);
                ret = add_memory(nid, phys_addr,