lmb: check if a region can be reserved by lmb_reserve()

The logic used in lmb_alloc() takes into consideration the existing
reserved regions, and ensures that the allocated region does not
overlap with any existing allocated regions. The lmb_reserve()
function is not doing any such checks -- the requested region might
overlap with an existing region. This also shows up with
lmb_alloc_addr() as this function ends up calling lmb_reserve().

Add a function which checks if the region requested is overlapping
with an existing reserved region, and allow for the reservation to
happen only if both the regions have LMB_NONE flag, which allows
re-requesting of the region. In any other scenario of an overlap, have
lmb_reserve() return -EEXIST, implying that the requested region is
already reserved.

Add corresponding test cases which check for overlapping reservation
requests made through lmb_reserve() and lmb_alloc_addr(). And while
here, fix some of the comments in the test function being touched.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
Reviewed-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
This commit is contained in:
Sughosh Ganu
2025-03-03 19:02:26 +05:30
committed by Tom Rini
parent 9943015f1b
commit 56f186a68b
2 changed files with 146 additions and 4 deletions

View File

@@ -561,6 +561,39 @@ static __maybe_unused void lmb_reserve_common_spl(void)
}
}
/**
* lmb_can_reserve_region() - check if the region can be reserved
* @base: base address of region to be reserved
* @size: size of region to be reserved
* @flags: flag of the region to be reserved
*
* Go through all the reserved regions and ensure that the requested
* region does not overlap with any existing regions. An overlap is
* allowed only when the flag of the request region and the existing
* region is LMB_NONE.
*
* Return: true if region can be reserved, false otherwise
*/
static bool lmb_can_reserve_region(phys_addr_t base, phys_size_t size,
u32 flags)
{
uint i;
struct lmb_region *lmb_reserved = lmb.used_mem.data;
for (i = 0; i < lmb.used_mem.count; i++) {
u32 rgnflags = lmb_reserved[i].flags;
phys_addr_t rgnbase = lmb_reserved[i].base;
phys_size_t rgnsize = lmb_reserved[i].size;
if (lmb_addrs_overlap(base, size, rgnbase, rgnsize)) {
if (flags != LMB_NONE || flags != rgnflags)
return false;
}
}
return true;
}
void lmb_add_memory(void)
{
int i;
@@ -633,6 +666,9 @@ long lmb_reserve(phys_addr_t base, phys_size_t size, u32 flags)
long ret = 0;
struct alist *lmb_rgn_lst = &lmb.used_mem;
if (!lmb_can_reserve_region(base, size, flags))
return -EEXIST;
ret = lmb_add_region_flags(lmb_rgn_lst, base, size, flags);
if (ret)
return ret;