Merge tag 'memblock-v6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rppt...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 27 Feb 2023 17:34:53 +0000 (09:34 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 27 Feb 2023 17:34:53 +0000 (09:34 -0800)
Pull memblock updates from Mike Rapoport:
 "Small optimizations:

   - fix off-by-one in the check whether memblock_add_range() should
     reallocate memory to accommodate newly inserted range

   - check only for relevant regions in memblock_merge_regions() rather
     than swipe over the entire array"

* tag 'memblock-v6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock:
  memblock: Avoid useless checks in memblock_merge_regions().
  memblock: Make a boundary tighter in memblock_add_range().

1  2 
mm/memblock.c

diff --combined mm/memblock.c
index d036c7861310cbfb0efcc36ee36279877978d171,22e48b0f57ad769218caad221f22ad3a99370e08..25fd0626a9e7bcaba3bc677839312584341d95f1
@@@ -500,15 -500,19 +500,19 @@@ static int __init_memblock memblock_dou
  /**
   * memblock_merge_regions - merge neighboring compatible regions
   * @type: memblock type to scan
-  *
-  * Scan @type and merge neighboring compatible regions.
+  * @start_rgn: start scanning from (@start_rgn - 1)
+  * @end_rgn: end scanning at (@end_rgn - 1)
+  * Scan @type and merge neighboring compatible regions in [@start_rgn - 1, @end_rgn)
   */
- static void __init_memblock memblock_merge_regions(struct memblock_type *type)
+ static void __init_memblock memblock_merge_regions(struct memblock_type *type,
+                                                  unsigned long start_rgn,
+                                                  unsigned long end_rgn)
  {
        int i = 0;
-       /* cnt never goes below 1 */
-       while (i < type->cnt - 1) {
+       if (start_rgn)
+               i = start_rgn - 1;
+       end_rgn = min(end_rgn, type->cnt - 1);
+       while (i < end_rgn) {
                struct memblock_region *this = &type->regions[i];
                struct memblock_region *next = &type->regions[i + 1];
  
                /* move forward from next + 1, index of which is i + 2 */
                memmove(next, next + 1, (type->cnt - (i + 2)) * sizeof(*next));
                type->cnt--;
+               end_rgn--;
        }
  }
  
@@@ -581,7 -586,7 +586,7 @@@ static int __init_memblock memblock_add
        bool insert = false;
        phys_addr_t obase = base;
        phys_addr_t end = base + memblock_cap_size(base, &size);
-       int idx, nr_new;
+       int idx, nr_new, start_rgn = -1, end_rgn;
        struct memblock_region *rgn;
  
        if (!size)
        /*
         * The worst case is when new range overlaps all existing regions,
         * then we'll need type->cnt + 1 empty regions in @type. So if
-        * type->cnt * 2 + 1 is less than type->max, we know
+        * type->cnt * 2 + 1 is less than or equal to type->max, we know
         * that there is enough empty regions in @type, and we can insert
         * regions directly.
         */
-       if (type->cnt * 2 + 1 < type->max)
+       if (type->cnt * 2 + 1 <= type->max)
                insert = true;
  
  repeat:
  #endif
                        WARN_ON(flags != rgn->flags);
                        nr_new++;
-                       if (insert)
+                       if (insert) {
+                               if (start_rgn == -1)
+                                       start_rgn = idx;
+                               end_rgn = idx + 1;
                                memblock_insert_region(type, idx++, base,
                                                       rbase - base, nid,
                                                       flags);
+                       }
                }
                /* area below @rend is dealt with, forget about it */
                base = min(rend, end);
        /* insert the remaining portion */
        if (base < end) {
                nr_new++;
-               if (insert)
+               if (insert) {
+                       if (start_rgn == -1)
+                               start_rgn = idx;
+                       end_rgn = idx + 1;
                        memblock_insert_region(type, idx, base, end - base,
                                               nid, flags);
+               }
        }
  
        if (!nr_new)
                insert = true;
                goto repeat;
        } else {
-               memblock_merge_regions(type);
+               memblock_merge_regions(type, start_rgn, end_rgn);
                return 0;
        }
  }
@@@ -902,7 -915,7 +915,7 @@@ static int __init_memblock memblock_set
                        r->flags &= ~flag;
        }
  
-       memblock_merge_regions(type);
+       memblock_merge_regions(type, start_rgn, end_rgn);
        return 0;
  }
  
@@@ -1275,7 -1288,7 +1288,7 @@@ int __init_memblock memblock_set_node(p
        for (i = start_rgn; i < end_rgn; i++)
                memblock_set_region_node(&type->regions[i], nid);
  
-       memblock_merge_regions(type);
+       memblock_merge_regions(type, start_rgn, end_rgn);
  #endif
        return 0;
  }
@@@ -1640,7 -1653,13 +1653,7 @@@ void __init memblock_free_late(phys_add
        end = PFN_DOWN(base + size);
  
        for (; cursor < end; cursor++) {
 -              /*
 -               * Reserved pages are always initialized by the end of
 -               * memblock_free_all() (by memmap_init() and, if deferred
 -               * initialization is enabled, memmap_init_reserved_pages()), so
 -               * these pages can be released directly to the buddy allocator.
 -               */
 -              __free_pages_core(pfn_to_page(cursor), 0);
 +              memblock_free_pages(pfn_to_page(cursor), cursor, 0);
                totalram_pages_inc();
        }
  }