]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/base/memory.c
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney...
[karo-tx-linux.git] / drivers / base / memory.c
index af9c911cd6b5433fac09b013ad7927e9a7ede18d..2804aed3f416aea878efde04937937e238ff4e5e 100644 (file)
@@ -219,6 +219,7 @@ static bool pages_correctly_reserved(unsigned long start_pfn)
 /*
  * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is
  * OK to have direct references to sparsemem variables in here.
+ * Must already be protected by mem_hotplug_begin().
  */
 static int
 memory_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
        struct page *first_page;
        int ret;
 
-       start_pfn = phys_index << PFN_SECTION_SHIFT;
+       start_pfn = section_nr_to_pfn(phys_index);
        first_page = pfn_to_page(start_pfn);
 
        switch (action) {
@@ -286,6 +287,7 @@ static int memory_subsys_online(struct device *dev)
        if (mem->online_type < 0)
                mem->online_type = MMOP_ONLINE_KEEP;
 
+       /* Already under protection of mem_hotplug_begin() */
        ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE);
 
        /* clear online_type */
@@ -328,17 +330,19 @@ store_mem_state(struct device *dev,
                goto err;
        }
 
+       /*
+        * Memory hotplug needs to hold mem_hotplug_begin() for probe to find
+        * the correct memory block to online before doing device_online(dev),
+        * which will take dev->mutex.  Take the lock early to prevent an
+        * inversion, memory_subsys_online() callbacks will be implemented by
+        * assuming it's already protected.
+        */
+       mem_hotplug_begin();
+
        switch (online_type) {
        case MMOP_ONLINE_KERNEL:
        case MMOP_ONLINE_MOVABLE:
        case MMOP_ONLINE_KEEP:
-               /*
-                * mem->online_type is not protected so there can be a
-                * race here.  However, when racing online, the first
-                * will succeed and the second will just return as the
-                * block will already be online.  The online type
-                * could be either one, but that is expected.
-                */
                mem->online_type = online_type;
                ret = device_online(&mem->dev);
                break;
@@ -349,6 +353,7 @@ store_mem_state(struct device *dev,
                ret = -EINVAL; /* should never happen */
        }
 
+       mem_hotplug_done();
 err:
        unlock_device_hotplug();