aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/memory.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/memory.c')
-rw-r--r--drivers/base/memory.c21
1 files changed, 13 insertions, 8 deletions
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index af9c911cd6b5..2804aed3f416 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -219,6 +219,7 @@ static bool pages_correctly_reserved(unsigned long start_pfn)
219/* 219/*
220 * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is 220 * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is
221 * OK to have direct references to sparsemem variables in here. 221 * OK to have direct references to sparsemem variables in here.
222 * Must already be protected by mem_hotplug_begin().
222 */ 223 */
223static int 224static int
224memory_block_action(unsigned long phys_index, unsigned long action, int online_type) 225memory_block_action(unsigned long phys_index, unsigned long action, int online_type)
@@ -228,7 +229,7 @@ memory_block_action(unsigned long phys_index, unsigned long action, int online_t
228 struct page *first_page; 229 struct page *first_page;
229 int ret; 230 int ret;
230 231
231 start_pfn = phys_index << PFN_SECTION_SHIFT; 232 start_pfn = section_nr_to_pfn(phys_index);
232 first_page = pfn_to_page(start_pfn); 233 first_page = pfn_to_page(start_pfn);
233 234
234 switch (action) { 235 switch (action) {
@@ -286,6 +287,7 @@ static int memory_subsys_online(struct device *dev)
286 if (mem->online_type < 0) 287 if (mem->online_type < 0)
287 mem->online_type = MMOP_ONLINE_KEEP; 288 mem->online_type = MMOP_ONLINE_KEEP;
288 289
290 /* Already under protection of mem_hotplug_begin() */
289 ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE); 291 ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE);
290 292
291 /* clear online_type */ 293 /* clear online_type */
@@ -328,17 +330,19 @@ store_mem_state(struct device *dev,
328 goto err; 330 goto err;
329 } 331 }
330 332
333 /*
334 * Memory hotplug needs to hold mem_hotplug_begin() for probe to find
335 * the correct memory block to online before doing device_online(dev),
336 * which will take dev->mutex. Take the lock early to prevent an
337 * inversion, memory_subsys_online() callbacks will be implemented by
338 * assuming it's already protected.
339 */
340 mem_hotplug_begin();
341
331 switch (online_type) { 342 switch (online_type) {
332 case MMOP_ONLINE_KERNEL: 343 case MMOP_ONLINE_KERNEL:
333 case MMOP_ONLINE_MOVABLE: 344 case MMOP_ONLINE_MOVABLE:
334 case MMOP_ONLINE_KEEP: 345 case MMOP_ONLINE_KEEP:
335 /*
336 * mem->online_type is not protected so there can be a
337 * race here. However, when racing online, the first
338 * will succeed and the second will just return as the
339 * block will already be online. The online type
340 * could be either one, but that is expected.
341 */
342 mem->online_type = online_type; 346 mem->online_type = online_type;
343 ret = device_online(&mem->dev); 347 ret = device_online(&mem->dev);
344 break; 348 break;
@@ -349,6 +353,7 @@ store_mem_state(struct device *dev,
349 ret = -EINVAL; /* should never happen */ 353 ret = -EINVAL; /* should never happen */
350 } 354 }
351 355
356 mem_hotplug_done();
352err: 357err:
353 unlock_device_hotplug(); 358 unlock_device_hotplug();
354 359