cma_declare_contiguous_multi() uses list_insert_sorted() to keep its candidate ranges sorted by size, largest first (revsizecmp()), and by base address, lowest first (basecmp()). Both comparators return true when the first argument sorts before the second. The helper stops at the first existing entry for which cmp(entry, new) is true and inserts the new range before it, which is the reverse of what is needed. If no entry matches, mlp is left pointing at the last entry and the new range is inserted before it instead of being appended. With revsizecmp(), inserting sizes 1 2 3 4 yields 2 3 4 1 and inserting 4 3 2 1 yields 1 2 3 4. The first range inserted stays at the tail until it is evicted. The caller relies on list_last_entry() being the smallest recorded range when deciding whether to skip or replace a candidate, and on walking the list largest first when picking the final ranges. With the list misordered, a candidate larger than some recorded ranges can be skipped because it is smaller than the first range found, so the function can fail or reserve less than requested where a valid layout exists. For example, free ranges of 4G, 7 x 1G and 2G, in address order, with a request of 12G: the 2G range is dropped instead of replacing a 1G one. Insert before the first entry the new range sorts before, and append when there is none. Found by code inspection with the help of an LLM. No kernel-level reproducer was produced and this was not tested on hardware or in a booted kernel. The example above comes from a userspace copy of the helper and the selection loop, written from the source. Fixes: c009da4258f9 ("mm, cma: support multiple contiguous ranges, if requested") Cc: # 6.15+ Assisted-by: LLM Signed-off-by: Ivy Lopez --- mm/cma.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/mm/cma.c b/mm/cma.c index a10ea37a261d..527b2d894f3e 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -348,16 +348,12 @@ static void __init list_insert_sorted( struct list_head *mp; struct cma_init_memrange *mlp; - if (list_empty(ranges)) - list_add(&mrp->list, ranges); - else { - list_for_each(mp, ranges) { - mlp = list_entry(mp, struct cma_init_memrange, list); - if (cmp(mlp, mrp)) - break; - } - __list_add(&mrp->list, mlp->list.prev, &mlp->list); + list_for_each(mp, ranges) { + mlp = list_entry(mp, struct cma_init_memrange, list); + if (cmp(mrp, mlp)) + break; } + list_add_tail(&mrp->list, mp); } static int __init cma_fixed_reserve(phys_addr_t base, phys_addr_t size) -- 2.56.0