The root decoder and requested granularity are known before region
creation, so cxl create-region can determine whether the request is valid
before sending it to the kernel.
Currently that check happens only after the region device is created,
requiring the failed request to be cleaned up afterward.
Validate encodable values during option parsing and resolve the effective
granularity before creating the region.
Fixes: 21b089025178 ("cxl: add a 'create-region' command")
Assisted-by: LLM
Signed-off-by: Alison Schofield <[email protected]>
---
cxl/region.c | 22 ++++++++++++----------
test/cxl-create-region.sh | 26 ++++++++++++++++++++++++++
2 files changed, 38 insertions(+), 10 deletions(-)
diff --git a/cxl/region.c b/cxl/region.c
index e4fc8bb2942c..2e62e3faace2 100644
--- a/cxl/region.c
+++ b/cxl/region.c
@@ -407,8 +407,11 @@ static int parse_create_options(struct cxl_ctx *ctx, int
count,
p->ways = p->num_memdevs;
if (param.granularity < INT_MAX) {
- if (param.granularity <= 0) {
- log_err(&rl, "Invalid interleave granularity: %d\n",
+ /* HDM granularity is a power of two from 256B through 16KiB. */
+ if (param.granularity < 256 || param.granularity > 16384 ||
+ !is_power_of_2(param.granularity)) {
+ log_err(&rl,
+ "Invalid interleave granularity: %d, expected a
power of 2 from 256 to 16384\n",
param.granularity);
goto err;
}
@@ -670,10 +673,9 @@ do { \
} \
} while (0)
-static int cxl_region_determine_granularity(struct cxl_region *region,
- struct parsed_params *p)
+static int cxl_region_determine_granularity(struct parsed_params *p)
{
- const char *devname = cxl_region_get_devname(region);
+ const char *devname = cxl_decoder_get_devname(p->root_decoder);
int granularity, ways;
/* Default granularity will be the root decoder's granularity */
@@ -769,6 +771,11 @@ static int create_region(struct cxl_ctx *ctx, int *count,
if (size > max_extent)
size = ALIGN_DOWN(max_extent, SZ_256M * p->ways);
+ rc = cxl_region_determine_granularity(p);
+ if (rc < 0)
+ return rc;
+ granularity = rc;
+
if (p->mode == CXL_DECODER_MODE_PMEM) {
region = cxl_decoder_create_pmem_region(p->root_decoder);
if (!region) {
@@ -797,11 +804,6 @@ static int create_region(struct cxl_ctx *ctx, int *count,
goto out;
}
- rc = cxl_region_determine_granularity(region, p);
- if (rc < 0)
- goto out;
- granularity = rc;
-
try(cxl_region, set_interleave_granularity, region, granularity);
try(cxl_region, set_interleave_ways, region, p->ways);
if (p->mode == CXL_DECODER_MODE_PMEM) {
diff --git a/test/cxl-create-region.sh b/test/cxl-create-region.sh
index 02358af7837a..0d98b61a7e13 100644
--- a/test/cxl-create-region.sh
+++ b/test/cxl-create-region.sh
@@ -240,6 +240,16 @@ setup_interleave_shape()
return 1
fi
+ x2_granularity=$($CXL list -b cxl_test -D -d "$x2_decoder" |
+ jq -r ".[0].interleave_granularity")
+
+ # Pick a valid granularity different from the x2 root's.
+ if [[ $x2_granularity -eq 256 ]]; then
+ other_granularity=512
+ else
+ other_granularity=256
+ fi
+
pos0=$(find_memdev "$x2_decoder" 0 0)
pos1=$(find_memdev "$x2_decoder" 1 0)
pos2=$(find_memdev "$x2_decoder" 0 1)
@@ -391,6 +401,21 @@ release_dpa_on_failure()
destroy_regions "$filler"
}
+# Reject invalid encodings and granularities incompatible with the root.
+refuse_bad_granularity()
+{
+ if ! setup_interleave_shape; then
+ echo "skipping granularity refusals"
+ return
+ fi
+
+ create_expect_fail "Invalid interleave granularity: 1000" \
+ -d "$x2_decoder" -m "$pos0 $pos1" -g 1000
+
+ create_expect_fail "only root decoder granularity ($x2_granularity)" \
+ -d "$x2_decoder" -m "$pos0 $pos1" -g "$other_granularity"
+}
+
# test region creation on devices behind a single-port host-bridge
create_single
@@ -407,6 +432,7 @@ done
create_csv_targets
refuse_bad_target_list
release_dpa_on_failure
+refuse_bad_granularity
# Repeat x1/x2/x3/x4 region creation with XOR interleave arithmetic.
load_cxl_test interleave_arithmetic=1
--
2.37.3