- Streamlined memory insertion logic to minimize redundant iterations. - Improved handling of memory insufficiency to avoid excessive reallocations. Signed-off-by: stephen.eta.zhou <stephen.eta.zhou@xxxxxxxxxxx> --- mm/memblock.c | 106 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 36 deletions(-) diff --git a/mm/memblock.c b/mm/memblock.c index 95af35fd1389..75c76b39a364 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -585,16 +585,16 @@ static int __init_memblock memblock_add_range(struct memblock_type *type, â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??phys_addr_t base, phys_addr_t size, â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??int nid, enum memblock_flags flags) { -â??â??â??â??â??bool insert = false; â??â??â??â??â??phys_addr_t obase = base; â??â??â??â??â??phys_addr_t end = base + memblock_cap_size(base, &size); -â??â??â??â??â??int idx, nr_new, start_rgn = -1, end_rgn; +â??â??â??â??â??phys_addr_t rbase, rend; +â??â??â??â??â??int idx, nr_new, start_rgn, end_rgn; â??â??â??â??â??struct memblock_region *rgn; â??â??â??â??â??if (!size) â??â??â??â??â??â??â??â??â??â??â??return 0; -â??â??â??â??â??/* special case for empty array */ +â??â??â??â??â??/* Special case for empty array */ â??â??â??â??â??if (type->regions[0].size == 0) { â??â??â??â??â??â??â??â??â??â??â??WARN_ON(type->cnt != 0 || type->total_size); â??â??â??â??â??â??â??â??â??â??â??type->regions[0].base = base; @@ -606,80 +606,114 @@ static int __init_memblock memblock_add_range(struct memblock_type *type, â??â??â??â??â??â??â??â??â??â??â??return 0; â??â??â??â??â??} + /* Delayed assignment, which is not necessary when the array is empty. */ +â??â??â??â??â??start_rgn = -1; â??â??â??â??â??/* -â??â??â??â??â?? * 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 or equal to type->max, we know -â??â??â??â??â?? * that there is enough empty regions in @type, and we can insert -â??â??â??â??â?? * regions directly. +â??â??â??â??â?? * Originally, `end_rgn` didn't need to be assigned a value, +â??â??â??â??â?? * but due to the use of nested conditional expressions, +â??â??â??â??â?? * the compiler reports a warning that `end_rgn` is uninitialized. +â??â??â??â??â?? * Therefore, it has been given an initial value here +â??â??â??â??â?? * to eliminate the warning. â??â??â??â??â?? */ -â??â??â??â??â??if (type->cnt * 2 + 1 <= type->max) -â??â??â??â??â??â??â??â??â??â??â??insert = true; +â??â??â??â??â??end_rgn = -1; repeat: â??â??â??â??â??/* -â??â??â??â??â?? * The following is executed twice. Once with %false @insert and -â??â??â??â??â?? * then with %true. The first counts the number of regions needed -â??â??â??â??â?? * to accommodate the new area. The second actually inserts them. +â??â??â??â??â?? * It is assumed that insertion is always possible under normal circumstances. +â??â??â??â??â?? * If memory is insufficient during insertion, the operation will record the need, +â??â??â??â??â?? * allocate memory, and then re-execute the insertion for the remaining portion. â??â??â??â??â?? */ â??â??â??â??â??base = obase; â??â??â??â??â??nr_new = 0; â??â??â??â??â??for_each_memblock_type(idx, type, rgn) { -â??â??â??â??â??â??â??â??â??â??â??phys_addr_t rbase = rgn->base; -â??â??â??â??â??â??â??â??â??â??â??phys_addr_t rend = rbase + rgn->size; +â??â??â??â??â??â??â??â??â??â??â??rbase = rgn->base; +â??â??â??â??â??â??â??â??â??â??â??rend = rbase + rgn->size; â??â??â??â??â??â??â??â??â??â??â??if (rbase >= end) â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??break; â??â??â??â??â??â??â??â??â??â??â??if (rend <= base) â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??continue; + â??â??â??â??â??â??â??â??â??â??â??/* -â??â??â??â??â??â??â??â??â??â??â?? * @rgn overlaps. If it separates the lower part of new -â??â??â??â??â??â??â??â??â??â??â?? * area, insert that portion. +â??â??â??â??â??â??â??â??â??â??â?? * @rgn overlaps. If it separates the lower part of new area, insert that portion. â??â??â??â??â??â??â??â??â??â??â?? */ â??â??â??â??â??â??â??â??â??â??â??if (rbase > base) { #ifdef CONFIG_NUMA â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??WARN_ON(nid != memblock_get_region_node(rgn)); #endif â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??WARN_ON(flags != rgn->flags); -â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??nr_new++; -â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??if (insert) { +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??/* +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * If memory is insufficient, the space required will be recorded. +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * If memory is sufficient, the insertion will proceed. +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? */ +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??if (type->cnt >= type->max) { +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??/* +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * Record obase as the address where the +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * overlapping part has not been resolved, +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * so that when repeat restarts, +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * redundant operations of resolving the +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * overlapping addresses are avoided. +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? */ +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??if (nr_new == 0) +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??obase = base; +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??nr_new++; +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??} else { â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??if (start_rgn == -1) â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??start_rgn = idx; â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??end_rgn = idx + 1; -â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??memblock_insert_region(type, idx++, base, -â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? rbase - base, nid, -â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? flags); +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??memblock_insert_region(type, idx++, base, rbase - base, nid, flags); â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??} â??â??â??â??â??â??â??â??â??â??â??} -â??â??â??â??â??â??â??â??â??â??â??/* area below @rend is dealt with, forget about it */ +â??â??â??â??â??â??â??â??â??â??â??/* Area below @rend is dealt with, forget about it */ â??â??â??â??â??â??â??â??â??â??â??base = min(rend, end); â??â??â??â??â??} -â??â??â??â??â??/* insert the remaining portion */ +â??â??â??â??â??/* Insert the remaining portion */ â??â??â??â??â??if (base < end) { -â??â??â??â??â??â??â??â??â??â??â??nr_new++; -â??â??â??â??â??â??â??â??â??â??â??if (insert) { +â??â??â??â??â??â??â??â??â??â??â??/* +â??â??â??â??â??â??â??â??â??â??â?? * Similarly, after handling the overlapping part, +â??â??â??â??â??â??â??â??â??â??â?? * it is still possible that memory is +â??â??â??â??â??â??â??â??â??â??â?? * insufficient. In that case, the space will be recorded once again. +â??â??â??â??â??â??â??â??â??â??â?? */ +â??â??â??â??â??â??â??â??â??â??â??if (type->cnt >= type->max) { +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??/* +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * The address of obase needs to be recorded here as well. The purpose is to +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * handle the situation where, +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * after resolving the overlap, there is still a remaining space to +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * insert but memory is insufficient (i.e., +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * no memory shortage occurred while resolving the overlap). +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * This means that space for +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * N (overlapping parts) + 1 (non-overlapping part) is required. +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * If obase is not recorded, after memory expansion, +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * base might revert to the original address to be +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * inserted (which could be overlapping). +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * This could lead to for_each_memblock_type attempting +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * to resolve the overlap again, causing multiple unnecessary iterations, +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? * even if it's just a simple check. +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? */ +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??if (nr_new == 0) +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??obase = base; +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??nr_new++; +â??â??â??â??â??â??â??â??â??â??â??} else { â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??if (start_rgn == -1) â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??start_rgn = idx; â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??end_rgn = idx + 1; -â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??memblock_insert_region(type, idx, base, end - base, -â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â?? nid, flags); +â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??memblock_insert_region(type, idx, base, end - base, nid, flags); â??â??â??â??â??â??â??â??â??â??â??} â??â??â??â??â??} -â??â??â??â??â??if (!nr_new) -â??â??â??â??â??â??â??â??â??â??â??return 0; - â??â??â??â??â??/* -â??â??â??â??â?? * If this was the first round, resize array and repeat for actual -â??â??â??â??â?? * insertions; otherwise, merge and return. +â??â??â??â??â?? * Finally, check if memory insufficiency occurred during insertion. +â??â??â??â??â?? * If so, the memory will be expanded to an appropriate size, +â??â??â??â??â?? * and the remaining portion will be inserted again. +â??â??â??â??â?? * If not, it means memory is sufficient, and the regions will be merged directly. â??â??â??â??â?? */ -â??â??â??â??â??if (!insert) { -â??â??â??â??â??â??â??â??â??â??â??while (type->cnt + nr_new > type->max) +â??â??â??â??â??if (nr_new > 0) { +â??â??â??â??â??â??â??â??â??â??â??while (type->cnt + nr_new > type->max) { â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??if (memblock_double_array(type, obase, size) < 0) â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??return -ENOMEM; -â??â??â??â??â??â??â??â??â??â??â??insert = true; +â??â??â??â??â??â??â??â??â??â??â??} â??â??â??â??â??â??â??â??â??â??â??goto repeat; â??â??â??â??â??} else { â??â??â??â??â??â??â??â??â??â??â??memblock_merge_regions(type, start_rgn, end_rgn); -- 2.25.1