|
@@ -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
|