Re: [PATCH v11 16/31] cxl/extent: Validate DC extent partition
Dave Jiang <[email protected]>
| Newsgroups | dev.linux.lists.nvdimm,org.kernel.vger.linux-cxl,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On 6/25/26 4:04 AM, Anisa Su wrote: > From: Ira Weiny <[email protected]> > > Extend cxl_validate_extent() — the per-extent check of the add pipeline > to check partition membership. > > Resolves an extent's DPA to its containing DC partition. Sharability is > a property of the partition (part->shareable), taken from its CDAT DSMAS > entry. > > An extent from a sharable partition must carry a non-null tag, since hosts > sharing the allocation key on that tag. A null tag there is a device > firmware bug; reject the extent. > > shared_extn_seq validation is checked in cxl_check_group_seq() once the > whole tag group is collected. > > Based on patches by John Groves. > > Signed-off-by: Ira Weiny <[email protected]> > Signed-off-by: John Groves <[email protected]> > Signed-off-by: Anisa Su <[email protected]> Reviewed-by: Dave Jiang <[email protected]> > > --- > Changes: > 1. cxl_extent_dc_partition() declared static — it is only called > from extent.c at this point. A subsequent commit ("cxl/mem: Enforce > tag-group semantics") drops static and adds the declaration to core.h > when mbox.c starts calling it. > 2. In cxl_validate_extent(), declare the local uuid as a struct > (uuid_t uuid) and fill it via import_uuid(&uuid, extent->uuid) instead > of casting (uuid_t *)extent->uuid. > --- > drivers/cxl/core/extent.c | 85 +++++++++++++++++++++++++++++++++++++-- > 1 file changed, 82 insertions(+), 3 deletions(-) > > diff --git a/drivers/cxl/core/extent.c b/drivers/cxl/core/extent.c > index 6e67e787d14d..2e770c5279c2 100644 > --- a/drivers/cxl/core/extent.c > +++ b/drivers/cxl/core/extent.c > @@ -76,11 +76,67 @@ alloc_tag_group(struct cxl_dax_region *cxlr_dax, uuid_t *uuid) > return no_free_ptr(group); > } > > +/* > + * Find the DC (Dynamic Capacity) partition that fully contains @ext_range, > + * or NULL if the extent falls outside every DC partition on this memdev. > + * The returned pointer is owned by mds->cxlds.part[] and lives for the > + * lifetime of the memdev. > + */ > +static const struct cxl_dpa_partition * > +cxl_extent_dc_partition(struct cxl_memdev_state *mds, > + struct cxl_extent *extent, > + struct range *ext_range) > +{ > + struct cxl_dev_state *cxlds = &mds->cxlds; > + struct device *dev = mds->cxlds.dev; > + > + /* > + * A device-side error could cause end < start, which range_contains() > + * would treat as contained in any partition. > + */ > + if (ext_range->end < ext_range->start) { > + dev_err_ratelimited(dev, > + "DC extent DPA %pra (%pU) has invalid length (firmware bug)\n", > + ext_range, extent->uuid); > + return NULL; > + } > + > + for (int i = 0; i < cxlds->nr_partitions; i++) { > + struct cxl_dpa_partition *part = &cxlds->part[i]; > + struct range partition_range = { > + .start = part->res.start, > + .end = part->res.end, > + }; > + > + if (part->mode != CXL_PARTMODE_DYNAMIC_RAM_1) > + continue; > + > + if (range_contains(&partition_range, ext_range)) { > + dev_dbg(dev, "DC extent DPA %pra (DCR:%pra)(%pU)\n", > + ext_range, &partition_range, extent->uuid); > + return part; > + } > + } > + > + dev_err_ratelimited(dev, > + "DC extent DPA %pra (%pU) is not in a valid DC partition\n", > + ext_range, extent->uuid); > + return NULL; > +} > + > /* > * Stage 1 of the add pipeline: pure, no allocation. Resolve the extent > - * to its region/endpoint decoder and ext_range, and verify the range > - * fits in the resolved endpoint decoder's DPA resource. Further > - * per-extent invariants layer into this function in subsequent commits. > + * to its region/endpoint decoder and ext_range, and enforce every > + * per-extent invariant the device must satisfy: > + * > + * - DPA falls inside a Dynamic Capacity partition (cxl_extent_dc_partition). > + * - Sharability is a property of the partition (part->shareable), not of > + * the shared_extn_seq value: a sharable-partition extent must carry a > + * non-null tag, and a non-sharable-partition extent must leave > + * shared_extn_seq reserved (zero). The dense 0..n-1 numbering within a > + * sharable tag group is validated separately (cxl_check_group_seq()). > + * - DPA resolves to an endpoint decoder attached to a region. > + * - The extent's range is fully contained in that ED's DPA resource. > * > * Caller must hold cxl_rwsem.region for read (cxl_dpa_to_region()). > * On success, @out_cxled / @out_cxlr_dax / @out_ext_range carry the > @@ -94,6 +150,8 @@ static int cxl_validate_extent(struct cxl_memdev_state *mds, > { > u64 start_dpa = le64_to_cpu(extent->start_dpa); > struct cxl_memdev *cxlmd = mds->cxlds.cxlmd; > + struct device *dev = mds->cxlds.dev; > + const struct cxl_dpa_partition *part; > struct cxl_endpoint_decoder *cxled; > struct cxl_region *cxlr; > struct range ext_range = (struct range) { > @@ -101,6 +159,27 @@ static int cxl_validate_extent(struct cxl_memdev_state *mds, > .end = start_dpa + le64_to_cpu(extent->length) - 1, > }; > struct range ed_range; > + uuid_t uuid; > + > + import_uuid(&uuid, extent->uuid); > + > + part = cxl_extent_dc_partition(mds, extent, &ext_range); > + if (!part) > + return -ENXIO; > + > + if (part->shareable) { > + if (uuid_is_null(&uuid)) { > + dev_err_ratelimited(dev, > + "DC extent DPA %pra: sharable-partition extent has null tag (firmware bug)\n", > + &ext_range); > + return -ENXIO; > + } > + } else if (le16_to_cpu(extent->shared_extn_seq)) { > + dev_err_ratelimited(dev, > + "DC extent DPA %pra (%pU): non-sharable partition but shared_extn_seq=%u (firmware bug)\n", > + &ext_range, &uuid, le16_to_cpu(extent->shared_extn_seq)); > + return -ENXIO; > + } > > cxlr = cxl_dpa_to_region(cxlmd, start_dpa, &cxled); > if (!cxlr || !cxlr->cxlr_dax)