Add support for the tag-based dynamic-capacity release policy via the QMP
interface. The new path scans committed extents, selects those whose stored
tag matches the requested UUID, and emits a Release Dynamic Capacity event
for each matching range.
This is intentionally scoped to tag-driven selection. Prescriptive release
handling and the underlying extent teardown stay in the existing paths.
Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
---
hw/mem/cxl_type3.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)
diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
index 6b73d58358..d5fa8a530a 100644
--- a/hw/mem/cxl_type3.c
+++ b/hw/mem/cxl_type3.c
@@ -2492,6 +2492,63 @@ static void qmp_cxl_process_dynamic_capacity_prescriptive(const char *path,
cxl_create_dc_event_records_for_extents(dcd, type, extents, num_extents);
}
+static void qmp_cxl_process_dynamic_capacity_tag_based(const char *path,
+ uint16_t hid, CXLDCEventType type, uint8_t rid, const char *tag,
+ CxlDynamicCapacityExtentList *records, Error **errp)
+{
+ Object *obj;
+ CXLType3Dev *dcd;
+ CXLDCExtentList *list = NULL;
+ CXLDCExtent *ent;
+ g_autofree CXLDCExtentRaw *extents = NULL;
+
+ obj = object_resolve_path_type(path, TYPE_CXL_TYPE3, NULL);
+ if (!obj) {
+ error_setg(errp, "Unable to resolve CXL type 3 device");
+ return;
+ }
+
+ dcd = CXL_TYPE3(obj);
+ if (!dcd->dc.num_regions) {
+ error_setg(errp, "No dynamic capacity support from the device");
+ return;
+ }
+
+ if (rid >= dcd->dc.num_regions) {
+ error_setg(errp, "region id is too large");
+ return;
+ }
+
+ QemuUUID uuid_req;
+ qemu_uuid_parse(tag, &uuid_req);
+
+ list = &dcd->dc.extents;
+ size_t cap = 8, n = 0;
+ extents = g_new0(CXLDCExtentRaw, cap);
+ QTAILQ_FOREACH(ent, list, node) {
+ QemuUUID uuid_ext;
+ memcpy(&uuid_ext.data, ent->tag, sizeof(ent->tag));
+ if (!qemu_uuid_is_equal(&uuid_req, &uuid_ext)) {
+ continue;
+ }
+
+ if (n == cap) {
+ cap *= 2;
+ extents = g_renew(CXLDCExtentRaw, extents, cap);
+ }
+
+ extents[n++] = (CXLDCExtentRaw){ .start_dpa = ent->start_dpa,
+ .len = ent->len,
+ .shared_seq = 0 };
+ }
+
+ if (n == 0) {
+ return;
+ }
+ extents = g_renew(CXLDCExtentRaw, extents, n);
+ cxl_create_dc_event_records_for_extents(dcd, type, extents, n);
+}
+
void qmp_cxl_add_dynamic_capacity(const char *path, uint16_t host_id,
CxlExtentSelectionPolicy sel_policy,
uint8_t region, const char *tag,
@@ -2537,6 +2594,10 @@ void qmp_cxl_release_dynamic_capacity(const char *path, uint16_t host_id,
region, tag,
extents, errp);
return;
+ case CXL_EXTENT_REMOVAL_POLICY_TAG_BASED:
+ qmp_cxl_process_dynamic_capacity_tag_based(path, host_id, type, region,
+ tag, extents, errp);
+ return;
default:
error_setg(errp, "Removal policy not supported");
return;
--
2.50.1 (Apple Git-155)
On Wed, Mar 25, 2026 at 06:42:56PM +0000, Alireza Sanaee wrote:
> Add support for the tag-based dynamic-capacity release policy via the QMP
> interface. The new path scans committed extents, selects those whose stored
> tag matches the requested UUID, and emits a Release Dynamic Capacity event
> for each matching range.
>
> This is intentionally scoped to tag-driven selection. Prescriptive release
> handling and the underlying extent teardown stay in the existing paths.
>
> Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
> ---
> hw/mem/cxl_type3.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 61 insertions(+)
>
> diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
> index 6b73d58358..d5fa8a530a 100644
> --- a/hw/mem/cxl_type3.c
> +++ b/hw/mem/cxl_type3.c
> @@ -2492,6 +2492,63 @@ static void qmp_cxl_process_dynamic_capacity_prescriptive(const char *path,
> cxl_create_dc_event_records_for_extents(dcd, type, extents, num_extents);
> }
>
> +static void qmp_cxl_process_dynamic_capacity_tag_based(const char *path,
> + uint16_t hid, CXLDCEventType type, uint8_t rid, const char *tag,
> + CxlDynamicCapacityExtentList *records, Error **errp)
> +{
> + Object *obj;
> + CXLType3Dev *dcd;
> + CXLDCExtentList *list = NULL;
> + CXLDCExtent *ent;
> + g_autofree CXLDCExtentRaw *extents = NULL;
> +
> + obj = object_resolve_path_type(path, TYPE_CXL_TYPE3, NULL);
> + if (!obj) {
> + error_setg(errp, "Unable to resolve CXL type 3 device");
> + return;
> + }
> +
> + dcd = CXL_TYPE3(obj);
> + if (!dcd->dc.num_regions) {
> + error_setg(errp, "No dynamic capacity support from the device");
> + return;
> + }
> +
> + if (rid >= dcd->dc.num_regions) {
> + error_setg(errp, "region id is too large");
> + return;
> + }
> +
> + QemuUUID uuid_req;
> + qemu_uuid_parse(tag, &uuid_req);
> +
> + list = &dcd->dc.extents;
> + size_t cap = 8, n = 0;
> + extents = g_new0(CXLDCExtentRaw, cap);
> + QTAILQ_FOREACH(ent, list, node) {
> + QemuUUID uuid_ext;
> + memcpy(&uuid_ext.data, ent->tag, sizeof(ent->tag));
> + if (!qemu_uuid_is_equal(&uuid_req, &uuid_ext)) {
> + continue;
> + }
> +
> + if (n == cap) {
> + cap *= 2;
> + extents = g_renew(CXLDCExtentRaw, extents, cap);
> + }
> +
> + extents[n++] = (CXLDCExtentRaw){ .start_dpa = ent->start_dpa,
> + .len = ent->len,
> + .shared_seq = 0 };
extents[n] = (CXLDCExtentRaw){ .start_dpa = ent->start_dpa,
.len = ent->len,
.shared_seq = 0 };
memcpy(extents[n].tag, uuid_ext.data, 0x10);
n++;
That should fix the issue I was talking about earlier in the other thread haha
(I tested it this time)
> + }
> +
> + if (n == 0) {
> + return;
> + }
> + extents = g_renew(CXLDCExtentRaw, extents, n);
> + cxl_create_dc_event_records_for_extents(dcd, type, extents, n);
> +}
> +
> void qmp_cxl_add_dynamic_capacity(const char *path, uint16_t host_id,
> CxlExtentSelectionPolicy sel_policy,
> uint8_t region, const char *tag,
> @@ -2537,6 +2594,10 @@ void qmp_cxl_release_dynamic_capacity(const char *path, uint16_t host_id,
> region, tag,
> extents, errp);
> return;
> + case CXL_EXTENT_REMOVAL_POLICY_TAG_BASED:
> + qmp_cxl_process_dynamic_capacity_tag_based(path, host_id, type, region,
> + tag, extents, errp);
> + return;
> default:
> error_setg(errp, "Removal policy not supported");
> return;
> --
> 2.50.1 (Apple Git-155)
>
On Mon, 30 Mar 2026 11:03:10 -0700
Anisa Su <anisa.su887@gmail.com> wrote:
Hi Anisa,
Thanks for testing. I will make this change and send a new version then.
> On Wed, Mar 25, 2026 at 06:42:56PM +0000, Alireza Sanaee wrote:
> > Add support for the tag-based dynamic-capacity release policy via the QMP
> > interface. The new path scans committed extents, selects those whose stored
> > tag matches the requested UUID, and emits a Release Dynamic Capacity event
> > for each matching range.
> >
> > This is intentionally scoped to tag-driven selection. Prescriptive release
> > handling and the underlying extent teardown stay in the existing paths.
> >
> > Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
> > ---
> > hw/mem/cxl_type3.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 61 insertions(+)
> >
> > diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
> > index 6b73d58358..d5fa8a530a 100644
> > --- a/hw/mem/cxl_type3.c
> > +++ b/hw/mem/cxl_type3.c
> > @@ -2492,6 +2492,63 @@ static void qmp_cxl_process_dynamic_capacity_prescriptive(const char *path,
> > cxl_create_dc_event_records_for_extents(dcd, type, extents, num_extents);
> > }
> >
> > +static void qmp_cxl_process_dynamic_capacity_tag_based(const char *path,
> > + uint16_t hid, CXLDCEventType type, uint8_t rid, const char *tag,
> > + CxlDynamicCapacityExtentList *records, Error **errp)
> > +{
> > + Object *obj;
> > + CXLType3Dev *dcd;
> > + CXLDCExtentList *list = NULL;
> > + CXLDCExtent *ent;
> > + g_autofree CXLDCExtentRaw *extents = NULL;
> > +
> > + obj = object_resolve_path_type(path, TYPE_CXL_TYPE3, NULL);
> > + if (!obj) {
> > + error_setg(errp, "Unable to resolve CXL type 3 device");
> > + return;
> > + }
> > +
> > + dcd = CXL_TYPE3(obj);
> > + if (!dcd->dc.num_regions) {
> > + error_setg(errp, "No dynamic capacity support from the device");
> > + return;
> > + }
> > +
> > + if (rid >= dcd->dc.num_regions) {
> > + error_setg(errp, "region id is too large");
> > + return;
> > + }
> > +
> > + QemuUUID uuid_req;
> > + qemu_uuid_parse(tag, &uuid_req);
> > +
> > + list = &dcd->dc.extents;
> > + size_t cap = 8, n = 0;
> > + extents = g_new0(CXLDCExtentRaw, cap);
> > + QTAILQ_FOREACH(ent, list, node) {
> > + QemuUUID uuid_ext;
> > + memcpy(&uuid_ext.data, ent->tag, sizeof(ent->tag));
> > + if (!qemu_uuid_is_equal(&uuid_req, &uuid_ext)) {
> > + continue;
> > + }
> > +
> > + if (n == cap) {
> > + cap *= 2;
> > + extents = g_renew(CXLDCExtentRaw, extents, cap);
> > + }
> > +
> > + extents[n++] = (CXLDCExtentRaw){ .start_dpa = ent->start_dpa,
> > + .len = ent->len,
> > + .shared_seq = 0 };
> extents[n] = (CXLDCExtentRaw){ .start_dpa = ent->start_dpa,
> .len = ent->len,
> .shared_seq = 0 };
> memcpy(extents[n].tag, uuid_ext.data, 0x10);
> n++;
>
> That should fix the issue I was talking about earlier in the other thread haha
> (I tested it this time)
> > + }
> > +
> > + if (n == 0) {
> > + return;
> > + }
> > + extents = g_renew(CXLDCExtentRaw, extents, n);
> > + cxl_create_dc_event_records_for_extents(dcd, type, extents, n);
> > +}
> > +
> > void qmp_cxl_add_dynamic_capacity(const char *path, uint16_t host_id,
> > CxlExtentSelectionPolicy sel_policy,
> > uint8_t region, const char *tag,
> > @@ -2537,6 +2594,10 @@ void qmp_cxl_release_dynamic_capacity(const char *path, uint16_t host_id,
> > region, tag,
> > extents, errp);
> > return;
> > + case CXL_EXTENT_REMOVAL_POLICY_TAG_BASED:
> > + qmp_cxl_process_dynamic_capacity_tag_based(path, host_id, type, region,
> > + tag, extents, errp);
> > + return;
> > default:
> > error_setg(errp, "Removal policy not supported");
> > return;
> > --
> > 2.50.1 (Apple Git-155)
> >
>
© 2016 - 2026 Red Hat, Inc.