memblock: split checks whether a region should be skipped to a helper function
[linux] / mm / memblock.c
index 022d4cb..f87d3ae 100644 (file)
@@ -125,7 +125,7 @@ static int memblock_can_resize __initdata_memblock;
 static int memblock_memory_in_slab __initdata_memblock = 0;
 static int memblock_reserved_in_slab __initdata_memblock = 0;
 
-enum memblock_flags __init_memblock choose_memblock_flags(void)
+static enum memblock_flags __init_memblock choose_memblock_flags(void)
 {
        return system_has_some_mirror ? MEMBLOCK_MIRROR : MEMBLOCK_NONE;
 }
@@ -254,7 +254,7 @@ __memblock_find_range_top_down(phys_addr_t start, phys_addr_t end,
  * Return:
  * Found address on success, 0 on failure.
  */
-phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size,
+static phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size,
                                        phys_addr_t align, phys_addr_t start,
                                        phys_addr_t end, int nid,
                                        enum memblock_flags flags)
@@ -851,11 +851,14 @@ static int __init_memblock memblock_setclr_flag(phys_addr_t base,
        if (ret)
                return ret;
 
-       for (i = start_rgn; i < end_rgn; i++)
+       for (i = start_rgn; i < end_rgn; i++) {
+               struct memblock_region *r = &type->regions[i];
+
                if (set)
-                       memblock_set_region_flags(&type->regions[i], flag);
+                       r->flags |= flag;
                else
-                       memblock_clear_region_flags(&type->regions[i], flag);
+                       r->flags &= ~flag;
+       }
 
        memblock_merge_regions(type);
        return 0;
@@ -955,6 +958,29 @@ void __init_memblock __next_reserved_mem_region(u64 *idx,
        *idx = ULLONG_MAX;
 }
 
+static bool should_skip_region(struct memblock_region *m, int nid, int flags)
+{
+       int m_nid = memblock_get_region_node(m);
+
+       /* only memory regions are associated with nodes, check it */
+       if (nid != NUMA_NO_NODE && nid != m_nid)
+               return true;
+
+       /* skip hotpluggable memory regions if needed */
+       if (movable_node_is_enabled() && memblock_is_hotpluggable(m))
+               return true;
+
+       /* if we want mirror memory skip non-mirror memory regions */
+       if ((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m))
+               return true;
+
+       /* skip nomap memory unless we were asked for it explicitly */
+       if (!(flags & MEMBLOCK_NOMAP) && memblock_is_nomap(m))
+               return true;
+
+       return false;
+}
+
 /**
  * __next__mem_range - next function for for_each_free_mem_range() etc.
  * @idx: pointer to u64 loop variable
@@ -1002,20 +1028,7 @@ void __init_memblock __next_mem_range(u64 *idx, int nid,
                phys_addr_t m_end = m->base + m->size;
                int         m_nid = memblock_get_region_node(m);
 
-               /* only memory regions are associated with nodes, check it */
-               if (nid != NUMA_NO_NODE && nid != m_nid)
-                       continue;
-
-               /* skip hotpluggable memory regions if needed */
-               if (movable_node_is_enabled() && memblock_is_hotpluggable(m))
-                       continue;
-
-               /* if we want mirror memory skip non-mirror memory regions */
-               if ((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m))
-                       continue;
-
-               /* skip nomap memory unless we were asked for it explicitly */
-               if (!(flags & MEMBLOCK_NOMAP) && memblock_is_nomap(m))
+               if (should_skip_region(m, nid, flags))
                        continue;
 
                if (!type_b) {
@@ -1119,20 +1132,7 @@ void __init_memblock __next_mem_range_rev(u64 *idx, int nid,
                phys_addr_t m_end = m->base + m->size;
                int m_nid = memblock_get_region_node(m);
 
-               /* only memory regions are associated with nodes, check it */
-               if (nid != NUMA_NO_NODE && nid != m_nid)
-                       continue;
-
-               /* skip hotpluggable memory regions if needed */
-               if (movable_node_is_enabled() && memblock_is_hotpluggable(m))
-                       continue;
-
-               /* if we want mirror memory skip non-mirror memory regions */
-               if ((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m))
-                       continue;
-
-               /* skip nomap memory unless we were asked for it explicitly */
-               if (!(flags & MEMBLOCK_NOMAP) && memblock_is_nomap(m))
+               if (should_skip_region(m, nid, flags))
                        continue;
 
                if (!type_b) {
@@ -1247,168 +1247,128 @@ int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size,
        return 0;
 }
 #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
-
-static phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size,
-                                       phys_addr_t align, phys_addr_t start,
-                                       phys_addr_t end, int nid,
-                                       enum memblock_flags flags)
+#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT
+/**
+ * __next_mem_pfn_range_in_zone - iterator for for_each_*_range_in_zone()
+ *
+ * @idx: pointer to u64 loop variable
+ * @zone: zone in which all of the memory blocks reside
+ * @out_spfn: ptr to ulong for start pfn of the range, can be %NULL
+ * @out_epfn: ptr to ulong for end pfn of the range, can be %NULL
+ *
+ * This function is meant to be a zone/pfn specific wrapper for the
+ * for_each_mem_range type iterators. Specifically they are used in the
+ * deferred memory init routines and as such we were duplicating much of
+ * this logic throughout the code. So instead of having it in multiple
+ * locations it seemed like it would make more sense to centralize this to
+ * one new iterator that does everything they need.
+ */
+void __init_memblock
+__next_mem_pfn_range_in_zone(u64 *idx, struct zone *zone,
+                            unsigned long *out_spfn, unsigned long *out_epfn)
 {
-       phys_addr_t found;
+       int zone_nid = zone_to_nid(zone);
+       phys_addr_t spa, epa;
+       int nid;
 
-       if (!align) {
-               /* Can't use WARNs this early in boot on powerpc */
-               dump_stack();
-               align = SMP_CACHE_BYTES;
-       }
+       __next_mem_range(idx, zone_nid, MEMBLOCK_NONE,
+                        &memblock.memory, &memblock.reserved,
+                        &spa, &epa, &nid);
+
+       while (*idx != U64_MAX) {
+               unsigned long epfn = PFN_DOWN(epa);
+               unsigned long spfn = PFN_UP(spa);
 
-       found = memblock_find_in_range_node(size, align, start, end, nid,
-                                           flags);
-       if (found && !memblock_reserve(found, size)) {
                /*
-                * The min_count is set to 0 so that memblock allocations are
-                * never reported as leaks.
+                * Verify the end is at least past the start of the zone and
+                * that we have at least one PFN to initialize.
                 */
-               kmemleak_alloc_phys(found, size, 0, 0);
-               return found;
-       }
-       return 0;
-}
-
-phys_addr_t __init memblock_alloc_range(phys_addr_t size, phys_addr_t align,
-                                       phys_addr_t start, phys_addr_t end,
-                                       enum memblock_flags flags)
-{
-       return memblock_alloc_range_nid(size, align, start, end, NUMA_NO_NODE,
-                                       flags);
-}
-
-phys_addr_t __init memblock_alloc_base_nid(phys_addr_t size,
-                                       phys_addr_t align, phys_addr_t max_addr,
-                                       int nid, enum memblock_flags flags)
-{
-       return memblock_alloc_range_nid(size, align, 0, max_addr, nid, flags);
-}
+               if (zone->zone_start_pfn < epfn && spfn < epfn) {
+                       /* if we went too far just stop searching */
+                       if (zone_end_pfn(zone) <= spfn) {
+                               *idx = U64_MAX;
+                               break;
+                       }
 
-phys_addr_t __init memblock_phys_alloc_nid(phys_addr_t size, phys_addr_t align, int nid)
-{
-       enum memblock_flags flags = choose_memblock_flags();
-       phys_addr_t ret;
+                       if (out_spfn)
+                               *out_spfn = max(zone->zone_start_pfn, spfn);
+                       if (out_epfn)
+                               *out_epfn = min(zone_end_pfn(zone), epfn);
 
-again:
-       ret = memblock_alloc_base_nid(size, align, MEMBLOCK_ALLOC_ACCESSIBLE,
-                                     nid, flags);
+                       return;
+               }
 
-       if (!ret && (flags & MEMBLOCK_MIRROR)) {
-               flags &= ~MEMBLOCK_MIRROR;
-               goto again;
+               __next_mem_range(idx, zone_nid, MEMBLOCK_NONE,
+                                &memblock.memory, &memblock.reserved,
+                                &spa, &epa, &nid);
        }
-       return ret;
-}
-
-phys_addr_t __init __memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr)
-{
-       return memblock_alloc_base_nid(size, align, max_addr, NUMA_NO_NODE,
-                                      MEMBLOCK_NONE);
-}
-
-phys_addr_t __init memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr)
-{
-       phys_addr_t alloc;
-
-       alloc = __memblock_alloc_base(size, align, max_addr);
 
-       if (alloc == 0)
-               panic("ERROR: Failed to allocate %pa bytes below %pa.\n",
-                     &size, &max_addr);
-
-       return alloc;
-}
-
-phys_addr_t __init memblock_phys_alloc(phys_addr_t size, phys_addr_t align)
-{
-       return memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ACCESSIBLE);
+       /* signal end of iteration */
+       if (out_spfn)
+               *out_spfn = ULONG_MAX;
+       if (out_epfn)
+               *out_epfn = 0;
 }
 
-phys_addr_t __init memblock_phys_alloc_try_nid(phys_addr_t size, phys_addr_t align, int nid)
-{
-       phys_addr_t res = memblock_phys_alloc_nid(size, align, nid);
-
-       if (res)
-               return res;
-       return memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ACCESSIBLE);
-}
+#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */
 
 /**
- * memblock_alloc_internal - allocate boot memory block
+ * memblock_alloc_range_nid - allocate boot memory block
  * @size: size of memory block to be allocated in bytes
  * @align: alignment of the region and block's size
- * @min_addr: the lower bound of the memory region to allocate (phys address)
- * @max_addr: the upper bound of the memory region to allocate (phys address)
+ * @start: the lower bound of the memory region to allocate (phys address)
+ * @end: the upper bound of the memory region to allocate (phys address)
  * @nid: nid of the free area to find, %NUMA_NO_NODE for any node
  *
- * The @min_addr limit is dropped if it can not be satisfied and the allocation
- * will fall back to memory below @min_addr. Also, allocation may fall back
- * to any node in the system if the specified node can not
- * hold the requested memory.
- *
  * The allocation is performed from memory region limited by
  * memblock.current_limit if @max_addr == %MEMBLOCK_ALLOC_ACCESSIBLE.
  *
- * The phys address of allocated boot memory block is converted to virtual and
- * allocated memory is reset to 0.
+ * If the specified node can not hold the requested memory the
+ * allocation falls back to any node in the system
+ *
+ * For systems with memory mirroring, the allocation is attempted first
+ * from the regions with mirroring enabled and then retried from any
+ * memory region.
  *
- * In addition, function sets the min_count to 0 using kmemleak_alloc for
+ * In addition, function sets the min_count to 0 using kmemleak_alloc_phys for
  * allocated boot memory block, so that it is never reported as leaks.
  *
  * Return:
- * Virtual address of allocated memory block on success, NULL on failure.
+ * Physical address of allocated memory block on success, %0 on failure.
  */
-static void * __init memblock_alloc_internal(
-                               phys_addr_t size, phys_addr_t align,
-                               phys_addr_t min_addr, phys_addr_t max_addr,
-                               int nid)
+static phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size,
+                                       phys_addr_t align, phys_addr_t start,
+                                       phys_addr_t end, int nid)
 {
-       phys_addr_t alloc;
-       void *ptr;
        enum memblock_flags flags = choose_memblock_flags();
+       phys_addr_t found;
 
        if (WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n"))
                nid = NUMA_NO_NODE;
 
-       /*
-        * Detect any accidental use of these APIs after slab is ready, as at
-        * this moment memblock may be deinitialized already and its
-        * internal data may be destroyed (after execution of memblock_free_all)
-        */
-       if (WARN_ON_ONCE(slab_is_available()))
-               return kzalloc_node(size, GFP_NOWAIT, nid);
-
        if (!align) {
+               /* Can't use WARNs this early in boot on powerpc */
                dump_stack();
                align = SMP_CACHE_BYTES;
        }
 
-       if (max_addr > memblock.current_limit)
-               max_addr = memblock.current_limit;
+       if (end > memblock.current_limit)
+               end = memblock.current_limit;
+
 again:
-       alloc = memblock_find_in_range_node(size, align, min_addr, max_addr,
-                                           nid, flags);
-       if (alloc && !memblock_reserve(alloc, size))
+       found = memblock_find_in_range_node(size, align, start, end, nid,
+                                           flags);
+       if (found && !memblock_reserve(found, size))
                goto done;
 
        if (nid != NUMA_NO_NODE) {
-               alloc = memblock_find_in_range_node(size, align, min_addr,
-                                                   max_addr, NUMA_NO_NODE,
+               found = memblock_find_in_range_node(size, align, start,
+                                                   end, NUMA_NO_NODE,
                                                    flags);
-               if (alloc && !memblock_reserve(alloc, size))
+               if (found && !memblock_reserve(found, size))
                        goto done;
        }
 
-       if (min_addr) {
-               min_addr = 0;
-               goto again;
-       }
-
        if (flags & MEMBLOCK_MIRROR) {
                flags &= ~MEMBLOCK_MIRROR;
                pr_warn("Could not allocate %pap bytes of mirrored memory\n",
@@ -1416,63 +1376,85 @@ again:
                goto again;
        }
 
-       return NULL;
-done:
-       ptr = phys_to_virt(alloc);
+       return 0;
 
+done:
        /* Skip kmemleak for kasan_init() due to high volume. */
-       if (max_addr != MEMBLOCK_ALLOC_KASAN)
+       if (end != MEMBLOCK_ALLOC_KASAN)
                /*
-                * The min_count is set to 0 so that bootmem allocated
+                * The min_count is set to 0 so that memblock allocated
                 * blocks are never reported as leaks. This is because many
                 * of these blocks are only referred via the physical
                 * address which is not looked up by kmemleak.
                 */
-               kmemleak_alloc(ptr, size, 0, 0);
+               kmemleak_alloc_phys(found, size, 0, 0);
 
-       return ptr;
+       return found;
+}
+
+phys_addr_t __init memblock_phys_alloc_range(phys_addr_t size,
+                                            phys_addr_t align,
+                                            phys_addr_t start,
+                                            phys_addr_t end)
+{
+       return memblock_alloc_range_nid(size, align, start, end, NUMA_NO_NODE);
+}
+
+phys_addr_t __init memblock_phys_alloc_try_nid(phys_addr_t size, phys_addr_t align, int nid)
+{
+       return memblock_alloc_range_nid(size, align, 0,
+                                       MEMBLOCK_ALLOC_ACCESSIBLE, nid);
 }
 
 /**
- * memblock_alloc_try_nid_raw - allocate boot memory block without zeroing
- * memory and without panicking
+ * memblock_alloc_internal - allocate boot memory block
  * @size: size of memory block to be allocated in bytes
  * @align: alignment of the region and block's size
- * @min_addr: the lower bound of the memory region from where the allocation
- *       is preferred (phys address)
- * @max_addr: the upper bound of the memory region from where the allocation
- *           is preferred (phys address), or %MEMBLOCK_ALLOC_ACCESSIBLE to
- *           allocate only from memory limited by memblock.current_limit value
+ * @min_addr: the lower bound of the memory region to allocate (phys address)
+ * @max_addr: the upper bound of the memory region to allocate (phys address)
  * @nid: nid of the free area to find, %NUMA_NO_NODE for any node
  *
- * Public function, provides additional debug information (including caller
- * info), if enabled. Does not zero allocated memory, does not panic if request
- * cannot be satisfied.
+ * Allocates memory block using memblock_alloc_range_nid() and
+ * converts the returned physical address to virtual.
+ *
+ * The @min_addr limit is dropped if it can not be satisfied and the allocation
+ * will fall back to memory below @min_addr. Other constraints, such
+ * as node and mirrored memory will be handled again in
+ * memblock_alloc_range_nid().
  *
  * Return:
  * Virtual address of allocated memory block on success, NULL on failure.
  */
-void * __init memblock_alloc_try_nid_raw(
-                       phys_addr_t size, phys_addr_t align,
-                       phys_addr_t min_addr, phys_addr_t max_addr,
-                       int nid)
+static void * __init memblock_alloc_internal(
+                               phys_addr_t size, phys_addr_t align,
+                               phys_addr_t min_addr, phys_addr_t max_addr,
+                               int nid)
 {
-       void *ptr;
+       phys_addr_t alloc;
 
-       memblock_dbg("%s: %llu bytes align=0x%llx nid=%d from=%pa max_addr=%pa %pF\n",
-                    __func__, (u64)size, (u64)align, nid, &min_addr,
-                    &max_addr, (void *)_RET_IP_);
+       /*
+        * Detect any accidental use of these APIs after slab is ready, as at
+        * this moment memblock may be deinitialized already and its
+        * internal data may be destroyed (after execution of memblock_free_all)
+        */
+       if (WARN_ON_ONCE(slab_is_available()))
+               return kzalloc_node(size, GFP_NOWAIT, nid);
 
-       ptr = memblock_alloc_internal(size, align,
-                                          min_addr, max_addr, nid);
-       if (ptr && size > 0)
-               page_init_poison(ptr, size);
+       alloc = memblock_alloc_range_nid(size, align, min_addr, max_addr, nid);
 
-       return ptr;
+       /* retry allocation without lower limit */
+       if (!alloc && min_addr)
+               alloc = memblock_alloc_range_nid(size, align, 0, max_addr, nid);
+
+       if (!alloc)
+               return NULL;
+
+       return phys_to_virt(alloc);
 }
 
 /**
- * memblock_alloc_try_nid_nopanic - allocate boot memory block
+ * memblock_alloc_try_nid_raw - allocate boot memory block without zeroing
+ * memory and without panicking
  * @size: size of memory block to be allocated in bytes
  * @align: alignment of the region and block's size
  * @min_addr: the lower bound of the memory region from where the allocation
@@ -1483,15 +1465,16 @@ void * __init memblock_alloc_try_nid_raw(
  * @nid: nid of the free area to find, %NUMA_NO_NODE for any node
  *
  * Public function, provides additional debug information (including caller
- * info), if enabled. This function zeroes the allocated memory.
+ * info), if enabled. Does not zero allocated memory, does not panic if request
+ * cannot be satisfied.
  *
  * Return:
  * Virtual address of allocated memory block on success, NULL on failure.
  */
-void * __init memblock_alloc_try_nid_nopanic(
-                               phys_addr_t size, phys_addr_t align,
-                               phys_addr_t min_addr, phys_addr_t max_addr,
-                               int nid)
+void * __init memblock_alloc_try_nid_raw(
+                       phys_addr_t size, phys_addr_t align,
+                       phys_addr_t min_addr, phys_addr_t max_addr,
+                       int nid)
 {
        void *ptr;
 
@@ -1501,13 +1484,14 @@ void * __init memblock_alloc_try_nid_nopanic(
 
        ptr = memblock_alloc_internal(size, align,
                                           min_addr, max_addr, nid);
-       if (ptr)
-               memset(ptr, 0, size);
+       if (ptr && size > 0)
+               page_init_poison(ptr, size);
+
        return ptr;
 }
 
 /**
- * memblock_alloc_try_nid - allocate boot memory block with panicking
+ * memblock_alloc_try_nid - allocate boot memory block
  * @size: size of memory block to be allocated in bytes
  * @align: alignment of the region and block's size
  * @min_addr: the lower bound of the memory region from where the allocation
@@ -1517,9 +1501,8 @@ void * __init memblock_alloc_try_nid_nopanic(
  *           allocate only from memory limited by memblock.current_limit value
  * @nid: nid of the free area to find, %NUMA_NO_NODE for any node
  *
- * Public panicking version of memblock_alloc_try_nid_nopanic()
- * which provides debug information (including caller info), if enabled,
- * and panics if the request can not be satisfied.
+ * Public function, provides additional debug information (including caller
+ * info), if enabled. This function zeroes the allocated memory.
  *
  * Return:
  * Virtual address of allocated memory block on success, NULL on failure.
@@ -1536,14 +1519,10 @@ void * __init memblock_alloc_try_nid(
                     &max_addr, (void *)_RET_IP_);
        ptr = memblock_alloc_internal(size, align,
                                           min_addr, max_addr, nid);
-       if (ptr) {
+       if (ptr)
                memset(ptr, 0, size);
-               return ptr;
-       }
 
-       panic("%s: Failed to allocate %llu bytes align=0x%llx nid=%d from=%pa max_addr=%pa\n",
-             __func__, (u64)size, (u64)align, nid, &min_addr, &max_addr);
-       return NULL;
+       return ptr;
 }
 
 /**
@@ -1998,8 +1977,7 @@ DEFINE_SHOW_ATTRIBUTE(memblock_debug);
 static int __init memblock_init_debugfs(void)
 {
        struct dentry *root = debugfs_create_dir("memblock", NULL);
-       if (!root)
-               return -ENXIO;
+
        debugfs_create_file("memory", 0444, root,
                            &memblock.memory, &memblock_debug_fops);
        debugfs_create_file("reserved", 0444, root,