On Thu, 13 Feb 2025 at 19:45, Heinrich Schuchardt <heinrich.schucha...@canonical.com> wrote: > > On 13.02.25 14:11, Sughosh Ganu wrote: > > 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. > > > > Also add corresponding test cases which checks for overlapping > > reservation requests made through lmb_reserve() and lmb_alloc_addr(). > > > > Signed-off-by: Sughosh Ganu <sughosh.g...@linaro.org> > > --- > > lib/lmb.c | 23 ++++++++++++ > > test/lib/lmb.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++- > > 2 files changed, 122 insertions(+), 1 deletion(-) > > > > diff --git a/lib/lmb.c b/lib/lmb.c > > index 7ca44591e1d..aeaf120f57d 100644 > > --- a/lib/lmb.c > > +++ b/lib/lmb.c > > @@ -595,6 +595,26 @@ static __maybe_unused void lmb_reserve_common_spl(void) > > } > > } > > > > Every new function should get a Sphinx style description.
Okay. Will add. > > > +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; > > +} > > + > > This seems to duplicate code in lmb_resize_regions(). Can we reduce the > code size by using a common function? Okay. Let me check if the common parts can be refactored into a single function for reuse. Thanks. -sughosh > > Best regards > > Heinrich > > > void lmb_add_memory(void) > > { > > int i; > > @@ -667,6 +687,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; > > diff --git a/test/lib/lmb.c b/test/lib/lmb.c > > index fcb5f1af532..6b995c976dd 100644 > > --- a/test/lib/lmb.c > > +++ b/test/lib/lmb.c > > @@ -499,6 +499,32 @@ static int lib_test_lmb_overlapping_reserve(struct > > unit_test_state *uts) > > ASSERT_LMB(mem_lst, used_lst, ram, ram_size, 1, 0x40000000, 0x40000, > > 0, 0, 0, 0); > > > > + /* try to allocate overlapping region with a different flag, should > > fail */ > > + ret = lmb_reserve(0x40008000, 0x1000, LMB_NOOVERWRITE); > > + ut_asserteq(ret, -EEXIST); > > + > > + /* allocate another region at 0x40050000 with a different flag */ > > + ret = lmb_reserve(0x40050000, 0x10000, LMB_NOOVERWRITE); > > + ut_asserteq(ret, 0); > > + ASSERT_LMB(mem_lst, used_lst, ram, ram_size, 2, 0x40000000, 0x40000, > > + 0x40050000, 0x10000, 0, 0); > > + > > + /* > > + * try to allocate a region adjacent to region 1 overlapping the 2nd > > region, > > + * should fail > > + */ > > + ret = lmb_reserve(0x40040000, 0x20000, LMB_NONE); > > + ut_asserteq(ret, -EEXIST); > > + > > + /* > > + * try to allocate a region between the two regions, but without an > > overlap, > > + * should succeed. this added region coalesces with the region 1 > > + */ > > + ret = lmb_reserve(0x40040000, 0x10000, LMB_NONE); > > + ut_asserteq(ret, 0); > > + ASSERT_LMB(mem_lst, used_lst, ram, ram_size, 2, 0x40000000, 0x50000, > > + 0x40050000, 0x10000, 0, 0); > > + > > lmb_pop(&store); > > > > return 0; > > @@ -549,6 +575,78 @@ static int test_alloc_addr(struct unit_test_state > > *uts, const phys_addr_t ram) > > ret = lmb_free(alloc_addr_a, 0x1000); > > ut_asserteq(ret, 0); > > > > + /* > > + * Add two regions with different flags, region1 and region2 with > > + * a gap between them. > > + * Try adding another region, adjacent to region 1 and overlapping > > + * region 2. Should fail. > > + */ > > + a = lmb_alloc_addr(alloc_addr_a, 0x1000, LMB_NONE); > > + ut_asserteq(a, alloc_addr_a); > > + > > + b = lmb_alloc_addr(alloc_addr_a + 0x4000, 0x1000, LMB_NOOVERWRITE); > > + ut_asserteq(b, alloc_addr_a + 0x4000); > > + ASSERT_LMB(mem_lst, used_lst, ram, ram_size, 2, a, 0x1000, > > + b, 0x1000, 0, 0); > > + > > + c = lmb_alloc_addr(alloc_addr_a + 0x1000, 0x5000, LMB_NONE); > > + ut_asserteq(c, 0); > > + ASSERT_LMB(mem_lst, used_lst, ram, ram_size, 2, a, 0x1000, > > + b, 0x1000, 0, 0); > > + > > + ret = lmb_free(a, 0x1000); > > + ut_asserteq(ret, 0); > > + ret = lmb_free(b, 0x1000); > > + ut_asserteq(ret, 0); > > + > > + > > + /* > > + * Add two regions with same flags(LMB_NONE), region1 and region2 > > + * with a gap between them. > > + * Try adding another region, adjacent to region 1 and overlapping > > + * region 2. Should succeed. All regions should coalesce into a > > + * single region. > > + */ > > + a = lmb_alloc_addr(alloc_addr_a, 0x1000, LMB_NONE); > > + ut_asserteq(a, alloc_addr_a); > > + > > + b = lmb_alloc_addr(alloc_addr_a + 0x4000, 0x1000, LMB_NONE); > > + ut_asserteq(b, alloc_addr_a + 0x4000); > > + ASSERT_LMB(mem_lst, used_lst, ram, ram_size, 2, a, 0x1000, > > + b, 0x1000, 0, 0); > > + > > + c = lmb_alloc_addr(alloc_addr_a + 0x1000, 0x5000, LMB_NONE); > > + ut_asserteq(c, alloc_addr_a + 0x1000); > > + ASSERT_LMB(mem_lst, used_lst, ram, ram_size, 1, a, 0x6000, > > + 0, 0, 0, 0); > > + > > + ret = lmb_free(a, 0x6000); > > + ut_asserteq(ret, 0); > > + > > + /* > > + * Add two regions with same flags(LMB_NOOVERWRITE), region1 and > > + * region2 with a gap between them. > > + * Try adding another region, adjacent to region 1 and overlapping > > + * region 2. Should fail. > > + */ > > + a = lmb_alloc_addr(alloc_addr_a, 0x1000, LMB_NOOVERWRITE); > > + ut_asserteq(a, alloc_addr_a); > > + > > + b = lmb_alloc_addr(alloc_addr_a + 0x4000, 0x1000, LMB_NOOVERWRITE); > > + ut_asserteq(b, alloc_addr_a + 0x4000); > > + ASSERT_LMB(mem_lst, used_lst, ram, ram_size, 2, a, 0x1000, > > + b, 0x1000, 0, 0); > > + > > + c = lmb_alloc_addr(alloc_addr_a + 0x1000, 0x5000, LMB_NOOVERWRITE); > > + ut_asserteq(c, 0); > > + ASSERT_LMB(mem_lst, used_lst, ram, ram_size, 2, a, 0x1000, > > + b, 0x1000, 0, 0); > > + > > + ret = lmb_free(a, 0x1000); > > + ut_asserteq(ret, 0); > > + ret = lmb_free(b, 0x1000); > > + ut_asserteq(ret, 0); > > + > > /* reserve 3 blocks */ > > ret = lmb_reserve(alloc_addr_a, 0x10000, LMB_NONE); > > ut_asserteq(ret, 0); > > @@ -760,7 +858,7 @@ static int lib_test_lmb_flags(struct unit_test_state > > *uts) > > > > /* reserve again, new flag */ > > ret = lmb_reserve(0x40010000, 0x10000, LMB_NONE); > > - ut_asserteq(ret, -1); > > + ut_asserteq(ret, -EEXIST); > > ASSERT_LMB(mem_lst, used_lst, ram, ram_size, 1, 0x40010000, 0x10000, > > 0, 0, 0, 0); > > >