From: Alison Schofield alison.schofield@intel.com
stable inclusion from stable-v6.6.11 commit e4a5b2f60e0697ad6f4844a76b142764cad3d745 bugzilla: https://gitee.com/openeuler/kernel/issues/I99TJK
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
[ Upstream commit 659aa050a53817157b7459529538598a6449c1d3 ]
Currently get_free_mem_region() searches for available capacity in increments equal to the region size being requested. This can cause the search to take giant steps through the resource leaving needless gaps and missing available space.
Specifically 'cxl create-region' fails with ERANGE even though capacity of the given size and CXL's expected 256M x InterleaveWays alignment can be satisfied.
Replace the total-request-size increment with a next alignment increment so that the next possible address is always examined for availability.
Fixes: 14b80582c43e ("resource: Introduce alloc_free_mem_region()") Reported-by: Dmytro Adamenko dmytro.adamenko@intel.com Reported-by: Dan Williams dan.j.williams@intel.com Signed-off-by: Alison Schofield alison.schofield@intel.com Reviewed-by: Dave Jiang dave.jiang@intel.com Link: https://lore.kernel.org/r/20231113221324.1118092-1-alison.schofield@intel.co... Cc: Jason Gunthorpe jgg@nvidia.com Reviewed-by: Christoph Hellwig hch@lst.de Signed-off-by: Dan Williams dan.j.williams@intel.com Signed-off-by: Sasha Levin sashal@kernel.org Signed-off-by: ZhangPeng zhangpeng362@huawei.com --- kernel/resource.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/kernel/resource.c b/kernel/resource.c index b1763b2fd7ef..e3f5680a564c 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -1847,8 +1847,8 @@ get_free_mem_region(struct device *dev, struct resource *base,
write_lock(&resource_lock); for (addr = gfr_start(base, size, align, flags); - gfr_continue(base, addr, size, flags); - addr = gfr_next(addr, size, flags)) { + gfr_continue(base, addr, align, flags); + addr = gfr_next(addr, align, flags)) { if (__region_intersects(base, addr, size, 0, IORES_DESC_NONE) != REGION_DISJOINT) continue;