memory-hotplug: check whether all memory blocks are offlined or not when removing...
[linux-2.6-block.git] / mm / memory_hotplug.c
index 6a82972aeae59e2c23700b4e88951a29fb521746..5d350f5c68e50e15717e8c1f68ae7ff22b2a2df2 100644 (file)
@@ -1429,6 +1429,54 @@ repeat:
                goto repeat;
        }
 
+       lock_memory_hotplug();
+
+       /*
+        * we have offlined all memory blocks like this:
+        *   1. lock memory hotplug
+        *   2. offline a memory block
+        *   3. unlock memory hotplug
+        *
+        * repeat step1-3 to offline the memory block. All memory blocks
+        * must be offlined before removing memory. But we don't hold the
+        * lock in the whole operation. So we should check whether all
+        * memory blocks are offlined.
+        */
+
+       mem = NULL;
+       for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
+               section_nr = pfn_to_section_nr(pfn);
+               if (!present_section_nr(section_nr))
+                       continue;
+
+               section = __nr_to_section(section_nr);
+               /* same memblock? */
+               if (mem)
+                       if ((section_nr >= mem->start_section_nr) &&
+                           (section_nr <= mem->end_section_nr))
+                               continue;
+
+               mem = find_memory_block_hinted(section, mem);
+               if (!mem)
+                       continue;
+
+               ret = is_memblock_offlined(mem);
+               if (!ret) {
+                       pr_warn("removing memory fails, because memory "
+                               "[%#010llx-%#010llx] is onlined\n",
+                               PFN_PHYS(section_nr_to_pfn(mem->start_section_nr)),
+                               PFN_PHYS(section_nr_to_pfn(mem->end_section_nr + 1)) - 1);
+
+                       kobject_put(&mem->dev.kobj);
+                       unlock_memory_hotplug();
+                       return ret;
+               }
+       }
+
+       if (mem)
+               kobject_put(&mem->dev.kobj);
+       unlock_memory_hotplug();
+
        return 0;
 }
 #else