[RFC PATCHv3 5/6] nvme: add generic debugfs support

Nilay Shroff nilay at linux.ibm.com
Mon Oct 27 05:02:54 PDT 2025



On 10/27/25 5:25 PM, Hannes Reinecke wrote:
> On 10/27/25 10:29, Nilay Shroff wrote:
>> Add generic infrastructure for creating and managing debugfs files in
>> the NVMe module. This introduces helper APIs that allow NVMe drivers to
>> register and unregister debugfs entries, along with a reusable attribute
>> structure for defining new debugfs files.
>>
>> The implementation uses seq_file interfaces to safely expose per-NS and
>> per-NS-head statistics, while supporting both simple show callbacks and
>> full seq_operations.
>>
>> Reviewed-by: Hannes Reinecke <hare at suse.de>
>> Signed-off-by: Nilay Shroff <nilay at linux.ibm.com>
>> ---
>>   drivers/nvme/host/Makefile  |   2 +-
>>   drivers/nvme/host/debugfs.c | 122 ++++++++++++++++++++++++++++++++++++
>>   drivers/nvme/host/nvme.h    |  11 ++++
>>   3 files changed, 134 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/nvme/host/debugfs.c
>>
>> diff --git a/drivers/nvme/host/Makefile b/drivers/nvme/host/Makefile
>> index 6414ec968f99..7962dfc3b2ad 100644
>> --- a/drivers/nvme/host/Makefile
>> +++ b/drivers/nvme/host/Makefile
>> @@ -10,7 +10,7 @@ obj-$(CONFIG_NVME_FC)            += nvme-fc.o
>>   obj-$(CONFIG_NVME_TCP)            += nvme-tcp.o
>>   obj-$(CONFIG_NVME_APPLE)        += nvme-apple.o
>>   -nvme-core-y                += core.o ioctl.o sysfs.o pr.o
>> +nvme-core-y                += core.o ioctl.o sysfs.o pr.o debugfs.o
>>   nvme-core-$(CONFIG_NVME_VERBOSE_ERRORS)    += constants.o
>>   nvme-core-$(CONFIG_TRACING)        += trace.o
>>   nvme-core-$(CONFIG_NVME_MULTIPATH)    += multipath.o
>> diff --git a/drivers/nvme/host/debugfs.c b/drivers/nvme/host/debugfs.c
>> new file mode 100644
>> index 000000000000..5c441779554f
>> --- /dev/null
>> +++ b/drivers/nvme/host/debugfs.c
>> @@ -0,0 +1,122 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (c) 2025 IBM Corporation
>> + *    Nilay Shroff <nilay at linux.ibm.com>
>> + */
>> +
>> +#include <linux/debugfs.h>
>> +#include <linux/seq_file.h>
>> +
>> +#include "nvme.h"
>> +
>> +struct nvme_debugfs_attr {
>> +    const char *name;
>> +    umode_t mode;
>> +    int (*show)(void *data, struct seq_file *m);
>> +    const struct seq_operations *seq_ops;
>> +};
>> +
>> +struct nvme_debugfs_ctx {
>> +    void *data;
>> +    struct nvme_debugfs_attr *attr;
>> +    int srcu_idx;
>> +};
>> +
>> +static int nvme_debugfs_show(struct seq_file *m, void *v)
>> +{
>> +    struct nvme_debugfs_ctx *ctx = m->private;
>> +    void *data = ctx->data;
>> +    struct nvme_debugfs_attr *attr = ctx->attr;
>> +
>> +    return attr->show(data, m);
>> +}
>> +
>> +static int nvme_debugfs_open(struct inode *inode, struct file *file)
>> +{
>> +    void *data = inode->i_private;
>> +    struct nvme_debugfs_attr *attr = debugfs_get_aux(file);
>> +    struct nvme_debugfs_ctx *ctx;
>> +    struct seq_file *m;
>> +    int ret;
>> +
>> +    ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
>> +    if (WARN_ON_ONCE(!ctx))
>> +        return -ENOMEM;
>> +
>> +    ctx->data = data;
>> +    ctx->attr = attr;
>> +
>> +    if (attr->seq_ops) {
>> +        ret = seq_open(file, attr->seq_ops);
>> +        if (ret) {
>> +            kfree(ctx);
>> +            return ret;
>> +        }
>> +        m = file->private_data;
>> +        m->private = ctx;
>> +        return ret;
>> +    }
>> +
>> +    if (WARN_ON_ONCE(!attr->show)) {
>> +        kfree(ctx);
>> +        return -EPERM;
>> +    }
>> +
>> +    return single_open(file, nvme_debugfs_show, ctx);
>> +}
>> +
>> +static int nvme_debugfs_release(struct inode *inode, struct file *file)
>> +{
>> +    struct seq_file *m = file->private_data;
>> +    struct nvme_debugfs_ctx *ctx = m->private;
>> +    struct nvme_debugfs_attr *attr = ctx->attr;
>> +    int ret;
>> +
>> +    if (attr->seq_ops)
>> +        ret = seq_release(inode, file);
>> +    else
>> +        ret = single_release(inode, file);
>> +
>> +    kfree(ctx);
>> +    return ret;
>> +}
>> +
>> +static const struct file_operations nvme_debugfs_fops = {
>> +    .owner   = THIS_MODULE,
>> +    .open    = nvme_debugfs_open,
>> +    .read    = seq_read,
>> +    .llseek  = seq_lseek,
>> +    .release = nvme_debugfs_release,
>> +};
>> +
>> +
>> +static const struct nvme_debugfs_attr nvme_mpath_debugfs_attrs[] = {
>> +    {},
>> +};
>> +
>> +static const struct nvme_debugfs_attr nvme_ns_debugfs_attrs[] = {
>> +    {},
>> +};
>> +
>> +static void nvme_debugfs_create_files(struct request_queue *q,
>> +        const struct nvme_debugfs_attr *attr, void *data)
>> +{
>> +    if (WARN_ON_ONCE(!q->debugfs_dir))
>> +        return;
>> +
>> +    for (; attr->name; attr++)
>> +        debugfs_create_file_aux(attr->name, attr->mode, q->debugfs_dir,
>> +                data, (void *)attr, &nvme_debugfs_fops);
>> +}
>> +
>> +void nvme_debugfs_register(struct gendisk *disk)
>> +{
>> +    const struct nvme_debugfs_attr *attr;
>> +
>> +    if (nvme_disk_is_ns_head(disk))
>> +        attr = nvme_mpath_debugfs_attrs;
>> +    else
>> +        attr = nvme_ns_debugfs_attrs;
>> +
>> +    nvme_debugfs_create_files(disk->queue, attr, disk->private_data);
>> +}
>> diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
>> index 2e58d4d6902a..d049b62b71d2 100644
>> --- a/drivers/nvme/host/nvme.h
>> +++ b/drivers/nvme/host/nvme.h
>> @@ -988,6 +988,7 @@ extern const struct attribute_group *nvme_dev_attr_groups[];
>>   extern const struct block_device_operations nvme_bdev_ops;
>>     void nvme_delete_ctrl_sync(struct nvme_ctrl *ctrl);
>> +
>>   struct nvme_ns *nvme_find_path(struct nvme_ns_head *head, unsigned int op_type);
>>   static inline int nvme_data_dir(const enum req_op op)
>>   {
>> @@ -999,6 +1000,16 @@ static inline int nvme_data_dir(const enum req_op op)
>>           return NVME_STAT_OTHER;
>>   }
>>   +void nvme_debugfs_register(struct gendisk *disk);
>> +static inline void nvme_debugfs_unregister(struct gendisk *disk)
>> +{
>> +    /*
>> +     * Nothing to do for now. When the request queue is unregistered,
>> +     * all files under q->debugfs_dir are recursively deleted.
>> +     * This is just a placeholder; the compiler will optimize it out.
>> +     */
>> +}
>> +
>>   #ifdef CONFIG_NVME_MULTIPATH
>>   static inline bool nvme_ctrl_use_ana(struct nvme_ctrl *ctrl)
>>   {
> 
> Especially as you already add a debugfs entry, so moving
> the values from the previous two patches should be easy.
> 
Okay will move those two entries under debugfs.

Thanks,
--Nilay




More information about the Linux-nvme mailing list