[PATCH 1/2] cxl/region: fix region leak when attach_target fails in cxl_add_to_region

Gregory Price
2026-02-21T04:30:18Z

cxl_add_to_region() ignores the return value of attach_target(). When
attach_target() fails (e.g. cxl_port_setup_targets() returns -ENXIO),
the auto-discovered region remains registered with its HPA resource
consumed but never reaches COMMIT state. Subsequent region creation
attempts fail with -ENOSPC because the HPA range is already reserved.

Track whether this call to cxl_add_to_region() created the region, and
call drop_region() on attach_target() failure to unregister it and
release the HPA resource. Pre-existing regions are left alone since
other endpoints may already be attached.

Signed-off-by: Gregory Price <gourry@gourry.net>
---
drivers/cxl/core/region.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index 385be9cb44cd..276046d49f88 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -3923,6 +3923,7 @@ int cxl_add_to_region(struct cxl_endpoint_decoder *cxled)
struct cxl_region_context ctx;
struct cxl_region_params *p;
bool attach = false;
+ bool newly_created = false;
int rc;

ctx = (struct cxl_region_context) {
@@ -3946,15 +3947,23 @@ int cxl_add_to_region(struct cxl_endpoint_decoder *cxled)
mutex_lock(&cxlrd->range_lock);
struct cxl_region *cxlr __free(put_cxl_region) =
cxl_find_region_by_range(cxlrd, &ctx.hpa_range);
- if (!cxlr)
+ if (!cxlr) {
cxlr = construct_region(cxlrd, &ctx);
+ newly_created = !IS_ERR(cxlr);
+ }
mutex_unlock(&cxlrd->range_lock);

rc = PTR_ERR_OR_ZERO(cxlr);
if (rc)
return rc;

- attach_target(cxlr, cxled, -1, TASK_UNINTERRUPTIBLE);
+ rc = attach_target(cxlr, cxled, -1, TASK_UNINTERRUPTIBLE);
+ if (rc) {
+ /* If endpoint was just created, tear it down to release HPA */
+ if (newly_created)
+ drop_region(cxlrd, cxlr);
+ return rc;
+ }

scoped_guard(rwsem_read, &cxl_rwsem.region) {
p = &cxlr->params;
@@ -3972,7 +3981,7 @@ int cxl_add_to_region(struct cxl_endpoint_decoder *cxled)
p->res);
}

- return rc;
+ return 0;
}
EXPORT_SYMBOL_NS_GPL(cxl_add_to_region, "CXL");

--
2.47.3