On 5/23/26 2:43 AM, Anisa Su wrote:
> From: Ira Weiny <[email protected]>
>
> Extent information can be helpful to the user to coordinate memory
> usage with the external orchestrator and FM.
>
> Expose the details of each dc_extent by creating the following sysfs
> entries.
>
> /sys/bus/cxl/devices/dax_regionX/extentX.Y
> /sys/bus/cxl/devices/dax_regionX/extentX.Y/offset
> /sys/bus/cxl/devices/dax_regionX/extentX.Y/length
> /sys/bus/cxl/devices/dax_regionX/extentX.Y/uuid
>
> Each dc_extent surfaces as its own extentX.Y device under the parent
> dax_region. offset and length describe that dc_extent's HPA range,
> not an aggregate bounding box across the containing tagged
> allocation — so when a tagged allocation has multiple
> DPA-discontiguous extents, each is reported with its own offset and
> length. uuid is the tag identifying the containing allocation; it
> is shared across dc_extents that belong to the same tagged
> allocation and is hidden for untagged extents.
>
> Based on an original patch by Navneet Singh.
>
> Reviewed-by: Jonathan Cameron <[email protected]>
> Reviewed-by: Fan Ni <[email protected]>
> Tested-by: Fan Ni <[email protected]>
> Signed-off-by: Ira Weiny <[email protected]>
Missing Anisa sign off
> ---
> Documentation/ABI/testing/sysfs-bus-cxl | 36 +++++++++++++++
> drivers/cxl/core/extent.c | 58 +++++++++++++++++++++++++
> 2 files changed, 94 insertions(+)
>
> diff --git a/Documentation/ABI/testing/sysfs-bus-cxl
> b/Documentation/ABI/testing/sysfs-bus-cxl
> index 3080aef9ad67..38cf0a2894b9 100644
> --- a/Documentation/ABI/testing/sysfs-bus-cxl
> +++ b/Documentation/ABI/testing/sysfs-bus-cxl
> @@ -661,3 +661,39 @@ Description:
> The count is persistent across power loss and wraps back to 0
> upon overflow. If this file is not present, the device does not
> have the necessary support for dirty tracking.
> +
> +
> +What: /sys/bus/cxl/devices/dax_regionX/extentX.Y/offset
> +Date: May, 2025
> +KernelVersion: v6.16
Update date and kernel version for all
> +Contact: [email protected]
> +Description:
> + (RO) [For Dynamic Capacity regions only] Users can use the
> + extent information to create DAX devices on specific extents.
> + This is done by creating and destroying DAX devices in specific
> + sequences and looking at the mappings created. Extent offset
> + within the region.
> +
> +
> +What: /sys/bus/cxl/devices/dax_regionX/extentX.Y/length
> +Date: May, 2025
> +KernelVersion: v6.16
> +Contact: [email protected]
> +Description:
> + (RO) [For Dynamic Capacity regions only] Users can use the
> + extent information to create DAX devices on specific extents.
> + This is done by creating and destroying DAX devices in specific
> + sequences and looking at the mappings created. Extent length
> + within the region.
> +
> +
> +What: /sys/bus/cxl/devices/dax_regionX/extentX.Y/uuid
> +Date: May, 2025
> +KernelVersion: v6.16
> +Contact: [email protected]
> +Description:
> + (RO) [For Dynamic Capacity regions only] Users can use the
> + extent information to create DAX devices on specific extents.
> + This is done by creating and destroying DAX devices in specific
> + sequences and looking at the mappings created. UUID of this
> + extent.
> diff --git a/drivers/cxl/core/extent.c b/drivers/cxl/core/extent.c
> index f66fa8c600c5..34babfe032d1 100644
> --- a/drivers/cxl/core/extent.c
> +++ b/drivers/cxl/core/extent.c
> @@ -6,6 +6,63 @@
>
> #include "core.h"
>
> +static ssize_t offset_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct dc_extent *dc_extent = to_dc_extent(dev);
> +
> + return sysfs_emit(buf, "%#llx\n", dc_extent->hpa_range.start);
> +}
> +static DEVICE_ATTR_RO(offset);
> +
> +static ssize_t length_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct dc_extent *dc_extent = to_dc_extent(dev);
> + u64 length = range_len(&dc_extent->hpa_range);
> +
> + return sysfs_emit(buf, "%#llx\n", length);
> +}
> +static DEVICE_ATTR_RO(length);
> +
> +static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct dc_extent *dc_extent = to_dc_extent(dev);
> +
> + return sysfs_emit(buf, "%pUb\n", &dc_extent->group->uuid);
> +}
> +static DEVICE_ATTR_RO(uuid);
> +
> +static struct attribute *dc_extent_attrs[] = {
> + &dev_attr_offset.attr,
> + &dev_attr_length.attr,
> + &dev_attr_uuid.attr,
> + NULL
> +};
> +
> +static uuid_t empty_uuid = { 0 };
> +
> +static umode_t dc_extent_visible(struct kobject *kobj,
> + struct attribute *a, int n)
> +{
> + struct device *dev = kobj_to_dev(kobj);
> + struct dc_extent *dc_extent = to_dc_extent(dev);
> +
> + if (a == &dev_attr_uuid.attr &&
> + uuid_equal(&dc_extent->group->uuid, &empty_uuid))'
uuid_is_null() can be used?
DJ
> + return 0;
> +
> + return a->mode;
> +}
> +
> +static const struct attribute_group dc_extent_attribute_group = {
> + .attrs = dc_extent_attrs,
> + .is_visible = dc_extent_visible,
> +};
> +
> +__ATTRIBUTE_GROUPS(dc_extent_attribute);
> +
>
> static void cxled_release_extent(struct cxl_endpoint_decoder *cxled,
> struct dc_extent *dc_extent)
> @@ -93,6 +150,7 @@ static void dc_extent_release(struct device *dev)
> static const struct device_type dc_extent_type = {
> .name = "extent",
> .release = dc_extent_release,
> + .groups = dc_extent_attribute_groups,
> };
>
> bool is_dc_extent(struct device *dev)