Re: [PATCH 3/7] libcxl: Add poison injection support

Cheatham, Benjamin
2026-01-12T17:20:26Z

On 1/9/2026 12:03 PM, Dave Jiang wrote:
>
>
> On 1/9/26 9:07 AM, Ben Cheatham wrote:
>> Add a library API for clearing and injecting poison into a CXL memory
>> device through the CXL debugfs.
>>
>> This API will be used by the 'cxl-inject-error' and 'cxl-clear-error'
>> commands in later commits.
>>
>> Signed-off-by: Ben Cheatham <Benjamin.Cheatham@amd.com>
>> ---
>> cxl/lib/libcxl.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++
>> cxl/lib/libcxl.sym | 3 ++
>> cxl/libcxl.h | 3 ++
>> 3 files changed, 89 insertions(+)
>>
>> diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
>> index 27ff037..deebf7f 100644
>> --- a/cxl/lib/libcxl.c
>> +++ b/cxl/lib/libcxl.c
>> @@ -5046,3 +5046,86 @@ CXL_EXPORT struct cxl_cmd *cxl_cmd_new_set_alert_config(struct cxl_memdev *memde
>> {
>> return cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_SET_ALERT_CONFIG);
>> }
>> +
>> +CXL_EXPORT bool cxl_memdev_has_poison_injection(struct cxl_memdev *memdev)
>> +{
>> + struct cxl_ctx *ctx = memdev->ctx;
>> + size_t path_len, len;
>> + bool exists = true;
>> + char *path;
>> + int rc;
>> +
>> + if (!ctx->cxl_debugfs)
>> + return false;
>> +
>> + path_len = strlen(ctx->cxl_debugfs) + 100;
>
> Same comment about PATH_MAX.

I'll change it (here and everywhere else).

>
>> + path = calloc(path_len, sizeof(char));
>> + if (!path)
>> + return false;
>> +
>> + len = snprintf(path, path_len, "%s/%s/inject_poison", ctx->cxl_debugfs,
>> + cxl_memdev_get_devname(memdev));
>> + if (len >= path_len) {
>> + err(ctx, "%s: buffer too small\n",
>> + cxl_memdev_get_devname(memdev));
>> + free(path);
>> + return false;
>
> I think I saw in an earlier patch that you were using goto to filter error exit point. So may as well make it consistent and do it here as well.

Sure, I'll update this and the function below. I already screwed up one of the return paths last revision so
it's probably warranted.
>
>> + }
>> +
>> + rc = access(path, F_OK);
>> + if (rc)
>> + exists = false;
>> +
>> + free(path);
>> + return exists;
>> +}
>> +
>> +static int cxl_memdev_poison_action(struct cxl_memdev *memdev, size_t dpa,
>> + bool clear)
>> +{
>> + struct cxl_ctx *ctx = memdev->ctx;
>> + size_t path_len, len;
>> + char addr[32];
>> + char *path;
>> + int rc;
>> +
>> + if (!ctx->cxl_debugfs)
>> + return -ENOENT;
>> +
>> + path_len = strlen(ctx->cxl_debugfs) + 100;
>
> same comment about path len
>
>> + path = calloc(path_len, sizeof(char));
>> + if (!path)
>> + return -ENOMEM;
>> +
>> + len = snprintf(path, path_len, "%s/%s/%s", ctx->cxl_debugfs,
>> + cxl_memdev_get_devname(memdev),
>> + clear ? "clear_poison" : "inject_poison");
>> + if (len >= path_len) {
>> + err(ctx, "%s: buffer too small\n",
>> + cxl_memdev_get_devname(memdev));
>> + free(path);
>> + return -ENOMEM;
>
> same comment about error paths
>
> DJ
>
>> + }
>> +
>> + len = snprintf(addr, sizeof(addr), "0x%lx\n", dpa);
>> + if (len >= sizeof(addr)) {
>> + err(ctx, "%s: buffer too small\n",
>> + cxl_memdev_get_devname(memdev));
>> + free(path);
>> + return -ENOMEM;
>> + }
>> +
>> + rc = sysfs_write_attr(ctx, path, addr);
>> + free(path);
>> + return rc;
>> +}
>> +
>> +CXL_EXPORT int cxl_memdev_inject_poison(struct cxl_memdev *memdev, size_t addr)
>> +{
>> + return cxl_memdev_poison_action(memdev, addr, false);
>> +}
>> +
>> +CXL_EXPORT int cxl_memdev_clear_poison(struct cxl_memdev *memdev, size_t addr)
>> +{
>> + return cxl_memdev_poison_action(memdev, addr, true);
>> +}
>> diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
>> index c683b83..c636edb 100644
>> --- a/cxl/lib/libcxl.sym
>> +++ b/cxl/lib/libcxl.sym
>> @@ -309,4 +309,7 @@ global:
>> cxl_protocol_error_get_num;
>> cxl_protocol_error_get_str;
>> cxl_dport_protocol_error_inject;
>> + cxl_memdev_has_poison_injection;
>> + cxl_memdev_inject_poison;
>> + cxl_memdev_clear_poison;
>> } LIBCXL_10;
>> diff --git a/cxl/libcxl.h b/cxl/libcxl.h
>> index faef62e..4d035f0 100644
>> --- a/cxl/libcxl.h
>> +++ b/cxl/libcxl.h
>> @@ -105,6 +105,9 @@ int cxl_memdev_read_label(struct cxl_memdev *memdev, void *buf, size_t length,
>> size_t offset);
>> int cxl_memdev_write_label(struct cxl_memdev *memdev, void *buf, size_t length,
>> size_t offset);
>> +bool cxl_memdev_has_poison_injection(struct cxl_memdev *memdev);
>> +int cxl_memdev_inject_poison(struct cxl_memdev *memdev, size_t dpa);
>> +int cxl_memdev_clear_poison(struct cxl_memdev *memdev, size_t dpa);
>> struct cxl_cmd *cxl_cmd_new_get_fw_info(struct cxl_memdev *memdev);
>> unsigned int cxl_cmd_fw_info_get_num_slots(struct cxl_cmd *cmd);
>> unsigned int cxl_cmd_fw_info_get_active_slot(struct cxl_cmd *cmd);
>