diff mbox

[V2,net-next,15/15] smc: proc-fs interface for smc connections

Message ID 20160927164156.26184-16-ubraun@linux.vnet.ibm.com
State Changes Requested, archived
Delegated to: David Miller
Headers show

Commit Message

Ursula Braun Sept. 27, 2016, 4:41 p.m. UTC
Maintain a list of SMC sockets and display important SMC socket
information in /proc/net/smc.

Signed-off-by: Ursula Braun <ubraun@linux.vnet.ibm.com>
---
 net/smc/Makefile   |   2 +-
 net/smc/af_smc.c   |  14 +++
 net/smc/smc.h      |   1 +
 net/smc/smc_proc.c | 247 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 net/smc/smc_proc.h |  19 +++++
 5 files changed, 282 insertions(+), 1 deletion(-)
 create mode 100644 net/smc/smc_proc.c
 create mode 100644 net/smc/smc_proc.h

Comments

David Miller Sept. 28, 2016, 2:27 a.m. UTC | #1
From: Ursula Braun <ubraun@linux.vnet.ibm.com>
Date: Tue, 27 Sep 2016 18:41:56 +0200

> Maintain a list of SMC sockets and display important SMC socket
> information in /proc/net/smc.
> 
> Signed-off-by: Ursula Braun <ubraun@linux.vnet.ibm.com>

Dumping internal tables and information via /procfs is strongly
deprecated.

Please use a more modern mechanism (such as netlink) to expose this
information to the user.

You'll be most likely to succeed in your submission if you make use of
or design a generic facility that allows other drivers similar to
your's to provide this kind of information as well.

I'm sorry if this is frustrating, but this is a huge piece of
infrastructure, therefore you can expect lots of pieces to get
feedback and require changes like this.
Ursula Braun Oct. 12, 2016, 2 p.m. UTC | #2
Hi Dave,

thank you for your feedback. Following your guidance I studied the
inet_diag/tcp_diag kernel code for AF_INET sockets. It could make sense
to create an smc_diag module with an smc_diag_handler to provide
SMC-socket data to userspace. Userspace tools could exploit this by
receiving the SMC-socket data via AF_NETLINK sockets of protocol
NETLINK_SOCK_DIAG.
Please let me know, if this is the right direction.

Regards, Ursula

On 09/28/2016 04:27 AM, David Miller wrote:
> From: Ursula Braun <ubraun@linux.vnet.ibm.com>
> Date: Tue, 27 Sep 2016 18:41:56 +0200
> 
>> Maintain a list of SMC sockets and display important SMC socket
>> information in /proc/net/smc.
>>
>> Signed-off-by: Ursula Braun <ubraun@linux.vnet.ibm.com>
> 
> Dumping internal tables and information via /procfs is strongly
> deprecated.
> 
> Please use a more modern mechanism (such as netlink) to expose this
> information to the user.
> 
> You'll be most likely to succeed in your submission if you make use of
> or design a generic facility that allows other drivers similar to
> your's to provide this kind of information as well.
> 
> I'm sorry if this is frustrating, but this is a huge piece of
> infrastructure, therefore you can expect lots of pieces to get
> feedback and require changes like this.
> 
>
diff mbox

Patch

diff --git a/net/smc/Makefile b/net/smc/Makefile
index 5cf0caf..7918a45 100644
--- a/net/smc/Makefile
+++ b/net/smc/Makefile
@@ -1,3 +1,3 @@ 
 obj-$(CONFIG_SMC)	+= smc.o
 smc-y := af_smc.o smc_pnet.o smc_ib.o smc_clc.o smc_core.o smc_wr.o smc_llc.o
-smc-y += smc_cdc.o smc_tx.o smc_rx.o smc_close.o
+smc-y += smc_cdc.o smc_tx.o smc_rx.o smc_close.o smc_proc.o
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 5a2d60e..942063a 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -39,6 +39,7 @@ 
 #include "smc_tx.h"
 #include "smc_rx.h"
 #include "smc_close.h"
+#include "smc_proc.h"
 
 static DEFINE_MUTEX(smc_create_lgr_pending);	/* serialize link group
 						 * creation
@@ -118,11 +119,14 @@  out:
 
 static void smc_destruct(struct sock *sk)
 {
+	struct smc_sock *smc = smc_sk(sk);
+
 	if (sk->sk_state != SMC_CLOSED)
 		return;
 	if (!sock_flag(sk, SOCK_DEAD))
 		return;
 
+	smc_proc_sock_list_del(smc);
 	sk_refcnt_debug_dec(sk);
 }
 
@@ -151,6 +155,7 @@  static struct sock *smc_sock_alloc(struct net *net, struct socket *sock)
 	INIT_LIST_HEAD(&smc->accept_q);
 	spin_lock_init(&smc->accept_q_lock);
 	INIT_DELAYED_WORK(&smc->sock_put_work, smc_close_sock_put_work);
+	smc_proc_sock_list_add(smc);
 
 	return sk;
 }
@@ -1327,8 +1332,16 @@  static int __init smc_init(void)
 		goto out_sock;
 	}
 
+	rc = smc_proc_init();
+	if (rc) {
+		pr_err("%s: smc_proc_init fails with %d\n", __func__, rc);
+		goto out_ibclient;
+	}
+
 	return 0;
 
+out_ibclient:
+	smc_ib_unregister_client();
 out_sock:
 	sock_unregister(PF_SMC);
 out_proto:
@@ -1351,6 +1364,7 @@  static void __exit smc_exit(void)
 		list_del_init(&lgr->list);
 		smc_lgr_free(lgr); /* free link group */
 	}
+	smc_proc_exit();
 	smc_ib_unregister_client();
 	sock_unregister(PF_SMC);
 	proto_unregister(&smc_proto);
diff --git a/net/smc/smc.h b/net/smc/smc.h
index 5df305c..5163be6 100644
--- a/net/smc/smc.h
+++ b/net/smc/smc.h
@@ -163,6 +163,7 @@  struct smc_connection {
 
 struct smc_sock {				/* smc sock container */
 	struct sock		sk;
+	struct list_head	proc_list;	/* smc socket list */
 	struct socket		*clcsock;	/* internal tcp socket */
 	struct smc_connection	conn;		/* smc connection */
 	struct sockaddr		*addr;		/* inet connect address */
diff --git a/net/smc/smc_proc.c b/net/smc/smc_proc.c
new file mode 100644
index 0000000..2150dbc
--- /dev/null
+++ b/net/smc/smc_proc.c
@@ -0,0 +1,247 @@ 
+/*
+ * Shared Memory Communications over RDMA (SMC-R) and RoCE
+ *
+ * Handle /proc entries for SMC sockets
+ *
+ * Copyright IBM Corp. 2016
+ *
+ * Author(s):  Ursula Braun <ubraun@linux.vnet.ibm.com>
+ */
+
+#include <linux/proc_fs.h>
+
+#include "smc.h"
+#include "smc_core.h"
+#include "smc_proc.h"
+
+struct smc_proc_sock_list {
+	struct list_head list;
+	rwlock_t lock;
+};
+
+static struct smc_proc_sock_list smc_proc_socket_list = {
+	.list = LIST_HEAD_INIT(smc_proc_socket_list.list),
+	.lock = __RW_LOCK_UNLOCKED(smc_proc_socket_list.lock),
+};
+
+void smc_proc_sock_list_add(struct smc_sock *smc)
+{
+	write_lock(&smc_proc_socket_list.lock);
+	list_add_tail(&smc->proc_list, &smc_proc_socket_list.list);
+	write_unlock(&smc_proc_socket_list.lock);
+}
+
+void smc_proc_sock_list_del(struct smc_sock *smc)
+{
+	write_lock(&smc_proc_socket_list.lock);
+	if (!list_empty(&smc->proc_list))
+		list_del_init(&smc->proc_list);
+	write_unlock(&smc_proc_socket_list.lock);
+}
+
+#ifdef CONFIG_PROC_FS
+
+static struct proc_dir_entry *proc_fs_smc;
+
+static int smc_proc_gid_to_hex(char *gid, char *buf, int buf_len)
+{
+	int i;
+	int j;
+
+	if (buf_len < (2 * SMC_GID_SIZE + 1))
+		return -EINVAL;
+
+	j = 0;
+	for (i = 0; i < SMC_GID_SIZE; i++) {
+		buf[j++] = hex_asc_hi(gid[i]);
+		buf[j++] = hex_asc_lo(gid[i]);
+	}
+	buf[j] = '\0';
+
+	return 0;
+}
+
+static int smc_proc_seq_show_header(struct seq_file *m)
+{
+	seq_puts(m, "state   uid inode  local_address peer_address  ");
+	seq_puts(m, "tcp target   role ");
+	seq_puts(m, "gid_peer_0                       ");
+	seq_puts(m, "gid_peer_1                       ");
+	seq_puts(m, "sndbuf   rmbe     token    peerrmb  rxprodc  rxprodw ");
+	seq_puts(m, "rxconsc  rxconsw txprodc  txprodw txconsc  txconsw ");
+	seq_puts(m, "tx_flags rx_flags");
+	seq_pad(m, '\n');
+	return 0;
+}
+
+static void *smc_proc_seq_start(struct seq_file *seq, loff_t *pos)
+	__acquires(smc_proc_socket_list.lock)
+{
+	read_lock(&smc_proc_socket_list.lock);
+
+	if (!*pos)
+		return SEQ_START_TOKEN;
+
+	return seq_list_start(&smc_proc_socket_list.list, *pos);
+}
+
+static void *smc_proc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	if (v == SEQ_START_TOKEN)
+		return seq_list_start(&smc_proc_socket_list.list, *pos);
+	return seq_list_next(v, &smc_proc_socket_list.list, pos);
+}
+
+static void smc_proc_seq_stop(struct seq_file *seq, void *v)
+	__releases(smc_proc_socket_list.lock)
+{
+	read_unlock(&smc_proc_socket_list.lock);
+}
+
+static int smc_proc_seq_show(struct seq_file *m, void *v)
+{
+	struct smc_sock *smc = list_entry(v, struct smc_sock, proc_list);
+	char hex_buf[2 * SMC_GID_SIZE + 1];
+	struct sockaddr_in locl_addr;
+	struct sockaddr_in peer_addr;
+	int len;
+	int rc;
+	int i;
+
+	if (v == SEQ_START_TOKEN)
+		return smc_proc_seq_show_header(m);
+
+	if (!smc)
+		return -ENOENT;
+
+	seq_printf(m,
+		   "%5d %5d %6ld ",
+		   smc->sk.sk_state,
+		   from_kuid_munged(seq_user_ns(m), sock_i_uid(&smc->sk)),
+		   sock_i_ino(&smc->sk));
+
+	if (smc->sk.sk_state == SMC_INIT)
+		goto out_line;
+
+	if (smc->clcsock && smc->clcsock->sk) {
+		rc = smc->clcsock->ops->getname(smc->clcsock,
+						(struct sockaddr *)&locl_addr,
+						&len, 0);
+		if (!rc)
+			seq_printf(m,
+				   "%08X:%04X ",
+				   locl_addr.sin_addr.s_addr,
+				   locl_addr.sin_port);
+		else
+			seq_printf(m, "%13s ", " ");
+	} else {
+		seq_printf(m, "%13s ", " ");
+	}
+
+	if (smc->sk.sk_state == SMC_LISTEN)
+		goto out_line;
+
+	if (smc->clcsock && smc->clcsock->sk) {
+		rc = smc->clcsock->ops->getname(smc->clcsock,
+						(struct sockaddr *)&peer_addr,
+						&len, 1);
+		if (!rc)
+			seq_printf(m,
+				   "%08X:%04X ",
+				   peer_addr.sin_addr.s_addr,
+				   peer_addr.sin_port);
+		else
+			seq_printf(m, "%-13s ", " ");
+	} else {
+		seq_printf(m, "%13s ", " ");
+	}
+
+	seq_printf(m, "%3d ",  smc->use_fallback);
+	if (smc->use_fallback)
+		goto out_line;
+
+	if (smc->conn.lgr && (smc->sk.sk_state != SMC_CLOSED)) {
+		seq_printf(m, "%08X ", smc->conn.lgr->daddr);
+		seq_printf(m, "%4d ", smc->conn.lgr->role);
+
+		for (i = 0; i < 2; i++) {
+			smc_proc_gid_to_hex(smc->conn.lgr->lnk[i].peer_gid,
+					    hex_buf, sizeof(hex_buf));
+			seq_printf(m, "%32s ", hex_buf);
+		}
+	} else {
+		seq_printf(m, "%-80s ", " ");
+	}
+
+	seq_printf(m,
+		   "%08X %08X %08X %08X ",
+		   smc->conn.sndbuf_size,
+		   smc->conn.rmbe_size,
+		   smc->conn.alert_token_local,
+		   smc->conn.peer_rmbe_len);
+	seq_printf(m,
+		   "%08X    %04X %08X    %04X ",
+		   smc->conn.local_rx_ctrl.prod.count,
+		   smc->conn.local_rx_ctrl.prod.wrap,
+		   smc->conn.local_rx_ctrl.cons.count,
+		   smc->conn.local_rx_ctrl.cons.wrap);
+	seq_printf(m,
+		   "%08X    %04X %08X    %04X  ",
+		   smc->conn.local_tx_ctrl.prod.count,
+		   smc->conn.local_tx_ctrl.prod.wrap,
+		   smc->conn.local_tx_ctrl.cons.count,
+		   smc->conn.local_tx_ctrl.cons.wrap);
+	seq_printf(m,
+		   "%02X%02X     %02X%02X     ",
+		   *(u8 *)&smc->conn.local_tx_ctrl.prod_flags,
+		   *(u8 *)&smc->conn.local_tx_ctrl.conn_state_flags,
+		   *(u8 *)&smc->conn.local_rx_ctrl.prod_flags,
+		   *(u8 *)&smc->conn.local_rx_ctrl.conn_state_flags);
+out_line:
+	seq_putc(m, '\n');
+	return 0;
+}
+
+static const struct seq_operations smc_proc_seq_ops = {
+	.start = smc_proc_seq_start,
+	.next  = smc_proc_seq_next,
+	.stop  = smc_proc_seq_stop,
+	.show  = smc_proc_seq_show,
+};
+
+static int smc_proc_seq_open(struct inode *inode, struct file *filp)
+{
+	return seq_open(filp, &smc_proc_seq_ops);
+}
+
+static const struct file_operations smc_proc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= smc_proc_seq_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+int __init smc_proc_init(void)
+{
+	proc_fs_smc = proc_create("smc", S_IFREG | S_IRUGO,
+				  init_net.proc_net, &smc_proc_fops);
+	return (!proc_fs_smc) ? -EFAULT : 0;
+}
+
+void smc_proc_exit(void)
+{
+	proc_remove(proc_fs_smc);
+}
+
+#else /* CONFIG_PROC_FS */
+int __init smc_proc_init(void)
+{
+	return 0;
+}
+
+void smc_proc_exit(void)
+{
+}
+
+#endif /* CONFIG_PROC_FS */
diff --git a/net/smc/smc_proc.h b/net/smc/smc_proc.h
new file mode 100644
index 0000000..85e5cd6
--- /dev/null
+++ b/net/smc/smc_proc.h
@@ -0,0 +1,19 @@ 
+/*
+ * Shared Memory Communications over RDMA (SMC-R) and RoCE
+ *
+ * Handle /proc entries for SMC sockets
+ *
+ * Copyright IBM Corp. 2016
+ *
+ * Author(s):  Ursula Braun <ubraun@linux.vnet.ibm.com>
+ */
+
+#ifndef SMC_PROC_H
+#define SMC_PROC_H
+
+void smc_proc_sock_list_add(struct smc_sock *);
+void smc_proc_sock_list_del(struct smc_sock *);
+int smc_proc_init(void) __init;
+void smc_proc_exit(void);
+
+#endif /* SMC_PROC_H */