[PATCH net-next v6 13/15] ibmveth: Expose per-queue buffer pool details via debugfs

Mingming Cao <[email protected]>
Newsgroups gmane.linux.ports.ppc.embedded
Message-ID <b902e379c7df6d47c33c1f3024ae204f6ac395ea.1788102125.git.mmc__17634.5674249873$1788188991$gmane$org@linux.ibm.com>
With multi-queue RX each queue owns its own set of five buffer pools,
so a 16-queue adapter has 80 of them. Nothing reports their runtime
state: sysfs exposes queue 0 only, and only as configuration, and no
ethtool key is per-pool. When RX drops under load, rx%d_no_buffer_drops
names the queue but not which of its pools ran dry, nor how close the
others are.

Add a read-only buffer_pools debugfs file, one row per RX queue and
buffer pool:

  /sys/kernel/debug/ibmveth/<dev_name>/buffer_pools
  (e.g. /sys/kernel/debug/ibmveth/30000002/buffer_pools)

  Queue  Pool  Count  BuffSize  Active  Available

Active is live allocation (skbuff && free_map), not the sysfs
poolN/active configuration flag.

The root is driver-owned so each adapter directory can use its stable
vio name rather than the mutable netdev->name. It is created in
module_init() and unwound if vio_register_driver() fails.

A multi-line table does not belong in sysfs, so the historical queue-0
ABI is left alone:

  .../poolN/{active,num,size}

Those stay one-value configuration for queue-0 pool classes. Open
copies that geometry to queues 1..N. This series does not add
per-queue pool sysfs dirs.

Signed-off-by: Mingming Cao <[email protected]>
Reviewed-by: Dave Marquardt <[email protected]>
Tested-by: Shaik Abdulla <[email protected]>
---

Changes in v6:
- create the debugfs root in module_init() instead of lazily on
  first probe, which raced concurrent probes and could orphan the
  directory on ERR_PTR(-EEXIST)
- rename the pool buffer-count column from Size to Count, so the
  debugfs table stops reusing the word sysfs poolN/size spells as a
  byte length on the same pool object
- widen the down banner: geometry above queue 0 is only populated
  once open copies the queue-0 template
- scope the dump RTNL comment to geometry/pool->active; available is
  atomic_read

Changes in v5:
- debugfs buffer_pools_show walks get_num_rx_queues()
- Series renumber: mailed v4 11/14 debugfs -> tip P13 (14->15)
- Path uses stable vio dev_name under a driver-owned root (not netdev
  name - avoids rename/collide)
- rtnl_lock around dump (writers are under RTNL)
- Show Active/Available as 0 when pool !live (debugfs view; free-path
  available clear already in the buffer-submit patch)

Changes in v4:
- Move the all-queue buffer_pools diagnostic from sysfs to debugfs;
  subject updated to match.
- Keep historical queue-0 poolN/{active,num,size} sysfs as one-value
  config (template for MQ); do not add per-queue pool sysfs dirs.

 drivers/net/ethernet/ibm/ibmveth.c | 80 +++++++++++++++++++++++++++++-
 drivers/net/ethernet/ibm/ibmveth.h |  2 +
 2 files changed, 81 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 4f2d956b4c89..954846c9ec7b 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -31,6 +31,7 @@
 #include <linux/ipv6.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/debugfs.h>
 #include <asm/hvcall.h>
 #include <linux/atomic.h>
 #include <asm/vio.h>
@@ -3513,6 +3514,67 @@ static const struct net_device_ops ibmveth_netdev_ops = {
 #endif
 };
 
+static int ibmveth_buffer_pools_show(struct seq_file *m, void *v)
+{
+	struct ibmveth_adapter *adapter = m->private;
+	int i, j;
+
+	/*
+	 * size / buff_size / pool->active are written under RTNL
+	 * (veth_pool_store, open template copy). Take the same lock so
+	 * those columns are not a torn snapshot. available is updated
+	 * from NAPI/softirq; only atomic_read() keeps it from tearing.
+	 * Not required for memory safety; embedded arrays only.
+	 */
+	rtnl_lock();
+
+	seq_puts(m, "Queue  Pool  Count  BuffSize  Active  Available\n");
+	seq_puts(m, "-----  ----  -----  --------  ------  ---------\n");
+	if (!adapter->opened) {
+		seq_puts(m, "# down: Active/Available 0 unless allocated\n");
+		seq_puts(m, "# down: geometry above queue 0 set at open\n");
+	}
+
+	for (i = 0; i < ibmveth_get_num_rx_queues(adapter); i++) {
+		for (j = 0; j < IBMVETH_NUM_BUFF_POOLS; j++) {
+			struct ibmveth_buff_pool *pool =
+				&adapter->rx_buff_pool[i][j];
+			bool live = pool->skbuff && pool->free_map;
+			int active = live ? pool->active : 0;
+			int available = live ? atomic_read(&pool->available)
+					     : 0;
+
+			seq_printf(m, "%5d  %4d  %5u  %8u  %6d  %9d\n",
+				   i, j, pool->size, pool->buff_size,
+				   active, available);
+		}
+	}
+
+	rtnl_unlock();
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ibmveth_buffer_pools);
+
+/* Driver-owned root so per-adapter dirs use a stable vio name, not the
+ * mutable netdev->name (avoids stale names / eth0 collisions after rename).
+ */
+static struct dentry *ibmveth_dbg_root;
+
+static void ibmveth_debugfs_init(struct ibmveth_adapter *adapter)
+{
+	adapter->debugfs_dir =
+		debugfs_create_dir(dev_name(&adapter->vdev->dev),
+				   ibmveth_dbg_root);
+	debugfs_create_file("buffer_pools", 0400, adapter->debugfs_dir,
+			    adapter, &ibmveth_buffer_pools_fops);
+}
+
+static void ibmveth_debugfs_exit(struct ibmveth_adapter *adapter)
+{
+	debugfs_remove_recursive(adapter->debugfs_dir);
+	adapter->debugfs_dir = NULL;
+}
+
 static void ibmveth_put_pool_kobjs(struct ibmveth_adapter *adapter,
 				   int pools_ready)
 {
@@ -3751,6 +3813,8 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
 
 	netdev_dbg(netdev, "registered\n");
 
+	ibmveth_debugfs_init(adapter);
+
 	return 0;
 }
 
@@ -3760,6 +3824,8 @@ static void ibmveth_remove(struct vio_dev *dev)
 	struct ibmveth_adapter *adapter = netdev_priv(netdev);
 	int i;
 
+	ibmveth_debugfs_exit(adapter);
+
 	for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++)
 		kobject_put(&adapter->rx_buff_pool[0][i].kobj);
 
@@ -3986,15 +4052,27 @@ static struct vio_driver ibmveth_driver = {
 
 static int __init ibmveth_module_init(void)
 {
+	int rc;
+
 	printk(KERN_DEBUG "%s: %s %s\n", ibmveth_driver_name,
 	       ibmveth_driver_string, ibmveth_driver_version);
 
-	return vio_register_driver(&ibmveth_driver);
+	ibmveth_dbg_root = debugfs_create_dir(ibmveth_driver_name, NULL);
+
+	rc = vio_register_driver(&ibmveth_driver);
+	if (rc) {
+		debugfs_remove_recursive(ibmveth_dbg_root);
+		ibmveth_dbg_root = NULL;
+	}
+
+	return rc;
 }
 
 static void __exit ibmveth_module_exit(void)
 {
 	vio_unregister_driver(&ibmveth_driver);
+	debugfs_remove_recursive(ibmveth_dbg_root);
+	ibmveth_dbg_root = NULL;
 }
 
 module_init(ibmveth_module_init);
diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h
index 0f2971c8627a..1276b3669f2c 100644
--- a/drivers/net/ethernet/ibm/ibmveth.h
+++ b/drivers/net/ethernet/ibm/ibmveth.h
@@ -381,6 +381,8 @@ struct ibmveth_adapter {
 	struct ibmveth_rx_queue_stats *rx_qstats;
 	struct ibmveth_tx_queue_stats *tx_qstats;
 
+	struct dentry *debugfs_dir;
+
 	/* Ethtool settings */
 	u8 duplex;
 	u32 speed;
-- 
2.50.1 (Apple Git-155)
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.