Re: [PATCH] NTB: ntb_transport: Use seq_file for QP stats debugfs

Koichiro Den <[email protected]>
Newsgroups dev.linux.lists.ntb,org.kernel.vger.linux-kernel
Message-ID <xvvxd2znh4oevszatoonpefnggg5ujknx4phy667vzrevmztmi@t2swaz73yhdm>
On Tue, Jan 06, 2026 at 09:37:06AM -0700, Dave Jiang wrote:
> 
> 
> On 12/17/25 1:19 AM, Koichiro Den wrote:
> > The ./qp*/stats debugfs file for each NTB transport QP is currently
> > implemented with a hand-crafted kmalloc() buffer and a series of
> > scnprintf() calls. This is a pre-seq_file style pattern and makes future
> > extensions easy to truncate.
> > 
> > Convert the stats file to use the seq_file helpers via
> > DEFINE_SHOW_ATTRIBUTE(), which simplifies the code and lets the seq_file
> > core handle buffering and partial reads.
> > 
> > While touching this area, fix a bug in the per-QP debugfs directory
> > naming: the buffer used for "qp%d" was only 4 bytes, which truncates
> > names like "qp10" to "qp1" and causes multiple queues to share the same
> > directory. Enlarge the buffer and use sizeof() to avoid truncation.
> > 
> > Reviewed-by: Frank Li <[email protected]>
> > Signed-off-by: Koichiro Den <[email protected]>
> 
> Reviewed-by: Dave Jiang <[email protected]>
> 
> Thanks for the improvement!
> 
> Can you please split out the bug fix and add a Fixes tag so it can go to stable kernels? Thanks!

I have split it out and sent v2 here:
https://lore.kernel.org/all/[email protected]/

Thanks for the review,
Koichiro

> 
> > ---
> > Note: This patch is split out from the following series, where it was
> > originally included as a preparatory change (refactor + small fix):
> > https://lore.kernel.org/all/aS3xe0CNHeIMUu7P@lizhi-Precision-Tower-5810/
> > ---
> >  drivers/ntb/ntb_transport.c | 136 +++++++++++-------------------------
> >  1 file changed, 41 insertions(+), 95 deletions(-)
> > 
> > diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
> > index eb875e3db2e3..d5a544bf8fd6 100644
> > --- a/drivers/ntb/ntb_transport.c
> > +++ b/drivers/ntb/ntb_transport.c
> > @@ -57,6 +57,7 @@
> >  #include <linux/module.h>
> >  #include <linux/pci.h>
> >  #include <linux/slab.h>
> > +#include <linux/seq_file.h>
> >  #include <linux/types.h>
> >  #include <linux/uaccess.h>
> >  #include <linux/mutex.h>
> > @@ -466,104 +467,49 @@ void ntb_transport_unregister_client(struct ntb_transport_client *drv)
> >  }
> >  EXPORT_SYMBOL_GPL(ntb_transport_unregister_client);
> >  
> > -static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count,
> > -			    loff_t *offp)
> > +static int ntb_qp_debugfs_stats_show(struct seq_file *s, void *v)
> >  {
> > -	struct ntb_transport_qp *qp;
> > -	char *buf;
> > -	ssize_t ret, out_offset, out_count;
> > -
> > -	qp = filp->private_data;
> > +	struct ntb_transport_qp *qp = s->private;
> >  
> >  	if (!qp || !qp->link_is_up)
> >  		return 0;
> >  
> > -	out_count = 1000;
> > -
> > -	buf = kmalloc(out_count, GFP_KERNEL);
> > -	if (!buf)
> > -		return -ENOMEM;
> > +	seq_puts(s, "\nNTB QP stats:\n\n");
> > +
> > +	seq_printf(s, "rx_bytes - \t%llu\n", qp->rx_bytes);
> > +	seq_printf(s, "rx_pkts - \t%llu\n", qp->rx_pkts);
> > +	seq_printf(s, "rx_memcpy - \t%llu\n", qp->rx_memcpy);
> > +	seq_printf(s, "rx_async - \t%llu\n", qp->rx_async);
> > +	seq_printf(s, "rx_ring_empty - %llu\n", qp->rx_ring_empty);
> > +	seq_printf(s, "rx_err_no_buf - %llu\n", qp->rx_err_no_buf);
> > +	seq_printf(s, "rx_err_oflow - \t%llu\n", qp->rx_err_oflow);
> > +	seq_printf(s, "rx_err_ver - \t%llu\n", qp->rx_err_ver);
> > +	seq_printf(s, "rx_buff - \t0x%p\n", qp->rx_buff);
> > +	seq_printf(s, "rx_index - \t%u\n", qp->rx_index);
> > +	seq_printf(s, "rx_max_entry - \t%u\n", qp->rx_max_entry);
> > +	seq_printf(s, "rx_alloc_entry - \t%u\n\n", qp->rx_alloc_entry);
> > +
> > +	seq_printf(s, "tx_bytes - \t%llu\n", qp->tx_bytes);
> > +	seq_printf(s, "tx_pkts - \t%llu\n", qp->tx_pkts);
> > +	seq_printf(s, "tx_memcpy - \t%llu\n", qp->tx_memcpy);
> > +	seq_printf(s, "tx_async - \t%llu\n", qp->tx_async);
> > +	seq_printf(s, "tx_ring_full - \t%llu\n", qp->tx_ring_full);
> > +	seq_printf(s, "tx_err_no_buf - %llu\n", qp->tx_err_no_buf);
> > +	seq_printf(s, "tx_mw - \t0x%p\n", qp->tx_mw);
> > +	seq_printf(s, "tx_index (H) - \t%u\n", qp->tx_index);
> > +	seq_printf(s, "RRI (T) - \t%u\n", qp->remote_rx_info->entry);
> > +	seq_printf(s, "tx_max_entry - \t%u\n", qp->tx_max_entry);
> > +	seq_printf(s, "free tx - \t%u\n", ntb_transport_tx_free_entry(qp));
> > +	seq_putc(s, '\n');
> > +
> > +	seq_printf(s, "Using TX DMA - \t%s\n", qp->tx_dma_chan ? "Yes" : "No");
> > +	seq_printf(s, "Using RX DMA - \t%s\n", qp->rx_dma_chan ? "Yes" : "No");
> > +	seq_printf(s, "QP Link - \t%s\n", qp->link_is_up ? "Up" : "Down");
> > +	seq_putc(s, '\n');
> >  
> > -	out_offset = 0;
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "\nNTB QP stats:\n\n");
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "rx_bytes - \t%llu\n", qp->rx_bytes);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "rx_pkts - \t%llu\n", qp->rx_pkts);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "rx_memcpy - \t%llu\n", qp->rx_memcpy);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "rx_async - \t%llu\n", qp->rx_async);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "rx_ring_empty - %llu\n", qp->rx_ring_empty);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "rx_err_no_buf - %llu\n", qp->rx_err_no_buf);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "rx_err_oflow - \t%llu\n", qp->rx_err_oflow);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "rx_err_ver - \t%llu\n", qp->rx_err_ver);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "rx_buff - \t0x%p\n", qp->rx_buff);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "rx_index - \t%u\n", qp->rx_index);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "rx_max_entry - \t%u\n", qp->rx_max_entry);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "rx_alloc_entry - \t%u\n\n", qp->rx_alloc_entry);
> > -
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "tx_bytes - \t%llu\n", qp->tx_bytes);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "tx_pkts - \t%llu\n", qp->tx_pkts);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "tx_memcpy - \t%llu\n", qp->tx_memcpy);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "tx_async - \t%llu\n", qp->tx_async);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "tx_ring_full - \t%llu\n", qp->tx_ring_full);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "tx_err_no_buf - %llu\n", qp->tx_err_no_buf);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "tx_mw - \t0x%p\n", qp->tx_mw);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "tx_index (H) - \t%u\n", qp->tx_index);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "RRI (T) - \t%u\n",
> > -			       qp->remote_rx_info->entry);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "tx_max_entry - \t%u\n", qp->tx_max_entry);
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "free tx - \t%u\n",
> > -			       ntb_transport_tx_free_entry(qp));
> > -
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "\n");
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "Using TX DMA - \t%s\n",
> > -			       qp->tx_dma_chan ? "Yes" : "No");
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "Using RX DMA - \t%s\n",
> > -			       qp->rx_dma_chan ? "Yes" : "No");
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "QP Link - \t%s\n",
> > -			       qp->link_is_up ? "Up" : "Down");
> > -	out_offset += scnprintf(buf + out_offset, out_count - out_offset,
> > -			       "\n");
> > -
> > -	if (out_offset > out_count)
> > -		out_offset = out_count;
> > -
> > -	ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset);
> > -	kfree(buf);
> > -	return ret;
> > -}
> > -
> > -static const struct file_operations ntb_qp_debugfs_stats = {
> > -	.owner = THIS_MODULE,
> > -	.open = simple_open,
> > -	.read = debugfs_read,
> > -};
> > +	return 0;
> > +}
> > +DEFINE_SHOW_ATTRIBUTE(ntb_qp_debugfs_stats);
> >  
> >  static void ntb_list_add(spinlock_t *lock, struct list_head *entry,
> >  			 struct list_head *list)
> > @@ -1236,15 +1182,15 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt,
> >  	qp->tx_max_entry = tx_size / qp->tx_max_frame;
> >  
> >  	if (nt->debugfs_node_dir) {
> > -		char debugfs_name[4];
> > +		char debugfs_name[8];
> >  
> > -		snprintf(debugfs_name, 4, "qp%d", qp_num);
> > +		snprintf(debugfs_name, sizeof(debugfs_name), "qp%d", qp_num);
> >  		qp->debugfs_dir = debugfs_create_dir(debugfs_name,
> >  						     nt->debugfs_node_dir);
> >  
> >  		qp->debugfs_stats = debugfs_create_file("stats", S_IRUSR,
> >  							qp->debugfs_dir, qp,
> > -							&ntb_qp_debugfs_stats);
> > +							&ntb_qp_debugfs_stats_fops);
> >  	} else {
> >  		qp->debugfs_dir = NULL;
> >  		qp->debugfs_stats = NULL;
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.