All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/8] sysfs files for multipath transport control
@ 2021-02-15 17:39 Dan Aloni
  2021-02-15 17:39 ` [PATCH v1 1/8] sunrpc: rename 'net' to 'client' Dan Aloni
                   ` (8 more replies)
  0 siblings, 9 replies; 16+ messages in thread
From: Dan Aloni @ 2021-02-15 17:39 UTC (permalink / raw)
  To: linux-nfs, Anna Schumaker; +Cc: Trond Myklebust

Hi Anna,

This patchset builds ontop v2 of your 'sysfs files for changing IP' changeset.

- The patchset adds two more sysfs objects, for one for transport and another
  for multipath.
- Also, `net` renamed to `client`, and `client` now has symlink to its principal
  transport. A client also has a symlink to its `multipath` object.
- The transport interface lets you change `dstaddr` of individual transports,
  when `nconnect` is used (or if it wasn't used and these were added with the
  new interface).
- The interface to add a transport is using a single string written to 'add',
  for example:

       echo 'dstaddr 192.168.40.8 kind rdma' \
               > /sys/kernel/sunrpc/client/0/multipath/add

These changes are independent of the method used to obtain a sunrpc ID for a
mountpoint. For that I've sent a concept patch showing an fspick-based
implementation: https://marc.info/?l=linux-nfs&m=161332454821849&w=4

Thanks

Dan Aloni (8):
  sunrpc: rename 'net' to 'client'
  sunrpc: add xprt id
  sunrpc: add a directory per sunrpc xprt
  sunrpc: have client directory a symlink to the root transport
  sunrpc: add IDs to multipath
  sunrpc: add multipath directory and symlink from client
  sunrpc: change rpc_clnt_add_xprt() to rpc_add_xprt()
  sunrpc: introduce an 'add' node to 'multipath' sysfs directory

 fs/nfs/pnfs_nfs.c                    |  12 +-
 include/linux/sunrpc/clnt.h          |  12 +-
 include/linux/sunrpc/xprt.h          |   3 +
 include/linux/sunrpc/xprtmultipath.h |   6 +
 net/sunrpc/clnt.c                    |  39 +--
 net/sunrpc/sunrpc_syms.c             |   2 +
 net/sunrpc/sysfs.c                   | 403 +++++++++++++++++++++++----
 net/sunrpc/sysfs.h                   |  21 +-
 net/sunrpc/xprt.c                    |  29 ++
 net/sunrpc/xprtmultipath.c           |  37 +++
 10 files changed, 487 insertions(+), 77 deletions(-)

-- 
2.26.2


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v1 1/8] sunrpc: rename 'net' to 'client'
  2021-02-15 17:39 [PATCH v1 0/8] sysfs files for multipath transport control Dan Aloni
@ 2021-02-15 17:39 ` Dan Aloni
  2021-02-16 21:24   ` Anna Schumaker
  2021-02-15 17:39 ` [PATCH v1 2/8] sunrpc: add xprt id Dan Aloni
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 16+ messages in thread
From: Dan Aloni @ 2021-02-15 17:39 UTC (permalink / raw)
  To: linux-nfs, Anna Schumaker; +Cc: Trond Myklebust

This is in preparation to adding a second directory to keep track
of each transport.

Signed-off-by: Dan Aloni <dan@kernelim.com>
---
 net/sunrpc/clnt.c  |  8 ++++----
 net/sunrpc/sysfs.c | 22 +++++++++++-----------
 net/sunrpc/sysfs.h |  4 ++--
 3 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 02905eae5c0a..0a4811be01cd 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -301,7 +301,7 @@ static int rpc_client_register(struct rpc_clnt *clnt,
 	int err;
 
 	rpc_clnt_debugfs_register(clnt);
-	rpc_netns_sysfs_setup(clnt, net);
+	rpc_netns_client_sysfs_setup(clnt, net);
 
 	pipefs_sb = rpc_get_sb_net(net);
 	if (pipefs_sb) {
@@ -329,7 +329,7 @@ static int rpc_client_register(struct rpc_clnt *clnt,
 out:
 	if (pipefs_sb)
 		rpc_put_sb_net(net);
-	rpc_netns_sysfs_destroy(clnt);
+	rpc_netns_client_sysfs_destroy(clnt);
 	rpc_clnt_debugfs_unregister(clnt);
 	return err;
 }
@@ -736,7 +736,7 @@ int rpc_switch_client_transport(struct rpc_clnt *clnt,
 
 	rpc_unregister_client(clnt);
 	__rpc_clnt_remove_pipedir(clnt);
-	rpc_netns_sysfs_destroy(clnt);
+	rpc_netns_client_sysfs_destroy(clnt);
 	rpc_clnt_debugfs_unregister(clnt);
 
 	/*
@@ -883,7 +883,7 @@ static void rpc_free_client_work(struct work_struct *work)
 	 * so they cannot be called in rpciod, so they are handled separately
 	 * here.
 	 */
-	rpc_netns_sysfs_destroy(clnt);
+	rpc_netns_client_sysfs_destroy(clnt);
 	rpc_clnt_debugfs_unregister(clnt);
 	rpc_free_clid(clnt);
 	rpc_clnt_remove_pipedir(clnt);
diff --git a/net/sunrpc/sysfs.c b/net/sunrpc/sysfs.c
index 8b01b4df64ee..3fe814795ed9 100644
--- a/net/sunrpc/sysfs.c
+++ b/net/sunrpc/sysfs.c
@@ -9,7 +9,7 @@
 #include "sysfs.h"
 
 struct kobject *rpc_client_kobj;
-static struct kset *rpc_client_kset;
+static struct kset *rpc_sunrpc_kset;
 
 static void rpc_netns_object_release(struct kobject *kobj)
 {
@@ -45,13 +45,13 @@ static struct kobject *rpc_netns_object_alloc(const char *name,
 
 int rpc_sysfs_init(void)
 {
-	rpc_client_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
-	if (!rpc_client_kset)
+	rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
+	if (!rpc_sunrpc_kset)
 		return -ENOMEM;
-	rpc_client_kobj = rpc_netns_object_alloc("net", rpc_client_kset, NULL);
+	rpc_client_kobj = rpc_netns_object_alloc("client", rpc_sunrpc_kset, NULL);
 	if (!rpc_client_kobj) {
-		kset_unregister(rpc_client_kset);
-		rpc_client_kset = NULL;
+		kset_unregister(rpc_sunrpc_kset);
+		rpc_sunrpc_kset = NULL;
 		return -ENOMEM;
 	}
 	return 0;
@@ -119,18 +119,18 @@ static struct kobj_type rpc_netns_client_type = {
 void rpc_sysfs_exit(void)
 {
 	kobject_put(rpc_client_kobj);
-	kset_unregister(rpc_client_kset);
+	kset_unregister(rpc_sunrpc_kset);
 }
 
 static struct rpc_netns_client *rpc_netns_client_alloc(struct kobject *parent,
-						struct net *net, int clid)
+						       struct net *net, int clid)
 {
 	struct rpc_netns_client *p;
 
 	p = kzalloc(sizeof(*p), GFP_KERNEL);
 	if (p) {
 		p->net = net;
-		p->kobject.kset = rpc_client_kset;
+		p->kobject.kset = rpc_sunrpc_kset;
 		if (kobject_init_and_add(&p->kobject, &rpc_netns_client_type,
 					parent, "%d", clid) == 0)
 			return p;
@@ -139,7 +139,7 @@ static struct rpc_netns_client *rpc_netns_client_alloc(struct kobject *parent,
 	return NULL;
 }
 
-void rpc_netns_sysfs_setup(struct rpc_clnt *clnt, struct net *net)
+void rpc_netns_client_sysfs_setup(struct rpc_clnt *clnt, struct net *net)
 {
 	struct rpc_netns_client *rpc_client;
 	struct rpc_xprt *xprt = rcu_dereference(clnt->cl_xprt);
@@ -155,7 +155,7 @@ void rpc_netns_sysfs_setup(struct rpc_clnt *clnt, struct net *net)
 	}
 }
 
-void rpc_netns_sysfs_destroy(struct rpc_clnt *clnt)
+void rpc_netns_client_sysfs_destroy(struct rpc_clnt *clnt)
 {
 	struct rpc_netns_client *rpc_client = clnt->cl_sysfs;
 
diff --git a/net/sunrpc/sysfs.h b/net/sunrpc/sysfs.h
index 137a12c87954..ab75c3cc91b6 100644
--- a/net/sunrpc/sysfs.h
+++ b/net/sunrpc/sysfs.h
@@ -16,7 +16,7 @@ extern struct kobject *rpc_client_kobj;
 extern int rpc_sysfs_init(void);
 extern void rpc_sysfs_exit(void);
 
-void rpc_netns_sysfs_setup(struct rpc_clnt *clnt, struct net *net);
-void rpc_netns_sysfs_destroy(struct rpc_clnt *clnt);
+void rpc_netns_client_sysfs_setup(struct rpc_clnt *clnt, struct net *net);
+void rpc_netns_client_sysfs_destroy(struct rpc_clnt *clnt);
 
 #endif
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v1 2/8] sunrpc: add xprt id
  2021-02-15 17:39 [PATCH v1 0/8] sysfs files for multipath transport control Dan Aloni
  2021-02-15 17:39 ` [PATCH v1 1/8] sunrpc: rename 'net' to 'client' Dan Aloni
@ 2021-02-15 17:39 ` Dan Aloni
  2021-02-15 17:39 ` [PATCH v1 3/8] sunrpc: add a directory per sunrpc xprt Dan Aloni
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Dan Aloni @ 2021-02-15 17:39 UTC (permalink / raw)
  To: linux-nfs, Anna Schumaker; +Cc: Trond Myklebust

This adds a unique identifier for a sunrpc transport in sysfs, which is
similarly managed to the unique IDs of clients.

Signed-off-by: Dan Aloni <dan@kernelim.com>
---
 include/linux/sunrpc/xprt.h |  2 ++
 net/sunrpc/sunrpc_syms.c    |  1 +
 net/sunrpc/xprt.c           | 26 ++++++++++++++++++++++++++
 3 files changed, 29 insertions(+)

diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index d2e97ee802af..fbf57a87dc47 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -185,6 +185,7 @@ enum xprt_transports {
 struct rpc_xprt {
 	struct kref		kref;		/* Reference count */
 	const struct rpc_xprt_ops *ops;		/* transport methods */
+	unsigned int		id;		/* transport id */
 
 	const struct rpc_timeout *timeout;	/* timeout parms */
 	struct sockaddr_storage	addr;		/* server address */
@@ -367,6 +368,7 @@ struct rpc_xprt *	xprt_alloc(struct net *net, size_t size,
 				unsigned int num_prealloc,
 				unsigned int max_req);
 void			xprt_free(struct rpc_xprt *);
+void			xprt_cleanup_ids(void);
 
 static inline int
 xprt_enable_swap(struct rpc_xprt *xprt)
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 3b57efc692ec..b61b74c00483 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -133,6 +133,7 @@ cleanup_sunrpc(void)
 {
 	rpc_sysfs_exit();
 	rpc_cleanup_clids();
+	xprt_cleanup_ids();
 	rpcauth_remove_module();
 	cleanup_socket_xprt();
 	svc_cleanup_xprt_sock();
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 691ccf8049a4..e30acd1f0e31 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -1717,6 +1717,30 @@ static void xprt_free_all_slots(struct rpc_xprt *xprt)
 	}
 }
 
+static DEFINE_IDA(rpc_xprt_ids);
+
+void xprt_cleanup_ids(void)
+{
+	ida_destroy(&rpc_xprt_ids);
+}
+
+static int xprt_alloc_id(struct rpc_xprt *xprt)
+{
+	int id;
+
+	id = ida_simple_get(&rpc_xprt_ids, 0, 0, GFP_KERNEL);
+	if (id < 0)
+		return id;
+
+	xprt->id = id;
+	return 0;
+}
+
+static void xprt_free_id(struct rpc_xprt *xprt)
+{
+	ida_simple_remove(&rpc_xprt_ids, xprt->id);
+}
+
 struct rpc_xprt *xprt_alloc(struct net *net, size_t size,
 		unsigned int num_prealloc,
 		unsigned int max_alloc)
@@ -1729,6 +1753,7 @@ struct rpc_xprt *xprt_alloc(struct net *net, size_t size,
 	if (xprt == NULL)
 		goto out;
 
+	xprt_alloc_id(xprt);
 	xprt_init(xprt, net);
 
 	for (i = 0; i < num_prealloc; i++) {
@@ -1757,6 +1782,7 @@ void xprt_free(struct rpc_xprt *xprt)
 {
 	put_net(xprt->xprt_net);
 	xprt_free_all_slots(xprt);
+	xprt_free_id(xprt);
 	kfree_rcu(xprt, rcu);
 }
 EXPORT_SYMBOL_GPL(xprt_free);
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v1 3/8] sunrpc: add a directory per sunrpc xprt
  2021-02-15 17:39 [PATCH v1 0/8] sysfs files for multipath transport control Dan Aloni
  2021-02-15 17:39 ` [PATCH v1 1/8] sunrpc: rename 'net' to 'client' Dan Aloni
  2021-02-15 17:39 ` [PATCH v1 2/8] sunrpc: add xprt id Dan Aloni
@ 2021-02-15 17:39 ` Dan Aloni
  2021-02-16 21:46   ` Anna Schumaker
  2021-02-15 17:39 ` [PATCH v1 4/8] sunrpc: have client directory a symlink to the root transport Dan Aloni
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 16+ messages in thread
From: Dan Aloni @ 2021-02-15 17:39 UTC (permalink / raw)
  To: linux-nfs, Anna Schumaker; +Cc: Trond Myklebust

This uses much of the code from the per-client directory, except that
now we have direct access to the transport struct. The per-client
direct is adjusted in a subsequent commit.

Signed-off-by: Dan Aloni <dan@kernelim.com>
---
 include/linux/sunrpc/xprt.h |   1 +
 net/sunrpc/sysfs.c          | 131 ++++++++++++++++++++++++++++++++++--
 net/sunrpc/sysfs.h          |   9 +++
 net/sunrpc/xprt.c           |   3 +
 4 files changed, 139 insertions(+), 5 deletions(-)

diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index fbf57a87dc47..df0252de58f4 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -260,6 +260,7 @@ struct rpc_xprt {
 						 * items */
 	struct list_head	bc_pa_list;	/* List of preallocated
 						 * backchannel rpc_rqst's */
+	void			*sysfs;         /* /sys/kernel/sunrpc/xprt/<id> */
 #endif /* CONFIG_SUNRPC_BACKCHANNEL */
 
 	struct rb_root		recv_queue;	/* Receive queue */
diff --git a/net/sunrpc/sysfs.c b/net/sunrpc/sysfs.c
index 3fe814795ed9..687d4470b90d 100644
--- a/net/sunrpc/sysfs.c
+++ b/net/sunrpc/sysfs.c
@@ -9,6 +9,7 @@
 #include "sysfs.h"
 
 struct kobject *rpc_client_kobj;
+struct kobject *rpc_xprt_kobj;
 static struct kset *rpc_sunrpc_kset;
 
 static void rpc_netns_object_release(struct kobject *kobj)
@@ -48,13 +49,24 @@ int rpc_sysfs_init(void)
 	rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
 	if (!rpc_sunrpc_kset)
 		return -ENOMEM;
+
 	rpc_client_kobj = rpc_netns_object_alloc("client", rpc_sunrpc_kset, NULL);
-	if (!rpc_client_kobj) {
-		kset_unregister(rpc_sunrpc_kset);
-		rpc_sunrpc_kset = NULL;
-		return -ENOMEM;
-	}
+	if (!rpc_client_kobj)
+		goto err_kset;
+
+	rpc_xprt_kobj = rpc_netns_object_alloc("transport", rpc_sunrpc_kset, NULL);
+	if (!rpc_xprt_kobj)
+		goto err_client;
+
 	return 0;
+
+err_client:
+	kobject_put(rpc_client_kobj);
+	rpc_client_kobj = NULL;
+err_kset:
+	kset_unregister(rpc_sunrpc_kset);
+	rpc_sunrpc_kset = NULL;
+	return -ENOMEM;
 }
 
 static ssize_t rpc_netns_dstaddr_show(struct kobject *kobj,
@@ -118,6 +130,7 @@ static struct kobj_type rpc_netns_client_type = {
 
 void rpc_sysfs_exit(void)
 {
+	kobject_put(rpc_xprt_kobj);
 	kobject_put(rpc_client_kobj);
 	kset_unregister(rpc_sunrpc_kset);
 }
@@ -166,3 +179,111 @@ void rpc_netns_client_sysfs_destroy(struct rpc_clnt *clnt)
 		clnt->cl_sysfs = NULL;
 	}
 }
+
+static ssize_t rpc_netns_xprt_dstaddr_show(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	struct rpc_netns_xprt *c = container_of(kobj,
+				struct rpc_netns_xprt, kobject);
+	struct rpc_xprt *xprt = c->xprt;
+
+	if (!(xprt->prot & (IPPROTO_TCP | XPRT_TRANSPORT_RDMA))) {
+		sprintf(buf, "N/A");
+		return 0;
+	}
+
+	return rpc_ntop((struct sockaddr *)&xprt->addr, buf, PAGE_SIZE);
+}
+
+static ssize_t rpc_netns_xprt_dstaddr_store(struct kobject *kobj,
+		struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	struct rpc_netns_xprt *c = container_of(kobj,
+				struct rpc_netns_xprt, kobject);
+	struct rpc_xprt *xprt = c->xprt;
+	struct sockaddr *saddr = (struct sockaddr *)&xprt->addr;
+	int port;
+
+	if (!(xprt->prot & (IPPROTO_TCP | XPRT_TRANSPORT_RDMA)))
+		return -EINVAL;
+
+	port = rpc_get_port(saddr);
+
+	xprt->addrlen = rpc_pton(xprt->xprt_net, buf, count - 1, saddr, sizeof(*saddr));
+	rpc_set_port(saddr, port);
+
+	kfree(xprt->address_strings[RPC_DISPLAY_ADDR]);
+	xprt->address_strings[RPC_DISPLAY_ADDR] = kstrndup(buf, count - 1, GFP_KERNEL);
+
+	xprt->ops->connect(xprt, NULL);
+	return count;
+}
+
+static void rpc_netns_xprt_release(struct kobject *kobj)
+{
+	struct rpc_netns_xprt *c;
+
+	c = container_of(kobj, struct rpc_netns_xprt, kobject);
+	kfree(c);
+}
+
+static const void *rpc_netns_xprt_namespace(struct kobject *kobj)
+{
+	return container_of(kobj, struct rpc_netns_xprt, kobject)->net;
+}
+
+static struct kobj_attribute rpc_netns_xprt_dstaddr = __ATTR(dstaddr,
+		0644, rpc_netns_xprt_dstaddr_show, rpc_netns_xprt_dstaddr_store);
+
+static struct attribute *rpc_netns_xprt_attrs[] = {
+	&rpc_netns_xprt_dstaddr.attr,
+	NULL,
+};
+
+static struct kobj_type rpc_netns_xprt_type = {
+	.release = rpc_netns_xprt_release,
+	.default_attrs = rpc_netns_xprt_attrs,
+	.sysfs_ops = &kobj_sysfs_ops,
+	.namespace = rpc_netns_xprt_namespace,
+};
+
+static struct rpc_netns_xprt *rpc_netns_xprt_alloc(struct kobject *parent,
+						   struct net *net, int id)
+{
+	struct rpc_netns_xprt *p;
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (p) {
+		p->net = net;
+		p->kobject.kset = rpc_sunrpc_kset;
+		if (kobject_init_and_add(&p->kobject, &rpc_netns_xprt_type,
+					 parent, "%d", id) == 0)
+			return p;
+		kobject_put(&p->kobject);
+	}
+	return NULL;
+}
+
+void rpc_netns_xprt_sysfs_setup(struct rpc_xprt *xprt, struct net *net)
+{
+	struct rpc_netns_xprt *rpc_xprt;
+
+	rpc_xprt = rpc_netns_xprt_alloc(rpc_xprt_kobj, net, xprt->id);
+	if (rpc_xprt) {
+		xprt->sysfs = rpc_xprt;
+		rpc_xprt->xprt = xprt;
+		kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD);
+	}
+}
+
+void rpc_netns_xprt_sysfs_destroy(struct rpc_xprt *xprt)
+{
+	struct rpc_netns_xprt *rpc_xprt = xprt->sysfs;
+
+	if (rpc_xprt) {
+		kobject_uevent(&rpc_xprt->kobject, KOBJ_REMOVE);
+		kobject_del(&rpc_xprt->kobject);
+		kobject_put(&rpc_xprt->kobject);
+		xprt->sysfs = NULL;
+	}
+}
diff --git a/net/sunrpc/sysfs.h b/net/sunrpc/sysfs.h
index ab75c3cc91b6..e08dd7f6a1ec 100644
--- a/net/sunrpc/sysfs.h
+++ b/net/sunrpc/sysfs.h
@@ -11,12 +11,21 @@ struct rpc_netns_client {
 	struct rpc_clnt *clnt;
 };
 
+struct rpc_netns_xprt {
+	struct kobject kobject;
+	struct net *net;
+	struct rpc_xprt *xprt;
+};
+
 extern struct kobject *rpc_client_kobj;
+extern struct kobject *rpc_xprt_kobj;
 
 extern int rpc_sysfs_init(void);
 extern void rpc_sysfs_exit(void);
 
 void rpc_netns_client_sysfs_setup(struct rpc_clnt *clnt, struct net *net);
 void rpc_netns_client_sysfs_destroy(struct rpc_clnt *clnt);
+void rpc_netns_xprt_sysfs_setup(struct rpc_xprt *xprt, struct net *net);
+void rpc_netns_xprt_sysfs_destroy(struct rpc_xprt *xprt);
 
 #endif
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index e30acd1f0e31..4098cb6b1453 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -55,6 +55,7 @@
 #include <trace/events/sunrpc.h>
 
 #include "sunrpc.h"
+#include "sysfs.h"
 
 /*
  * Local variables
@@ -1768,6 +1769,7 @@ struct rpc_xprt *xprt_alloc(struct net *net, size_t size,
 		xprt->max_reqs = num_prealloc;
 	xprt->min_reqs = num_prealloc;
 	xprt->num_reqs = num_prealloc;
+	rpc_netns_xprt_sysfs_setup(xprt, net);
 
 	return xprt;
 
@@ -1780,6 +1782,7 @@ EXPORT_SYMBOL_GPL(xprt_alloc);
 
 void xprt_free(struct rpc_xprt *xprt)
 {
+	rpc_netns_xprt_sysfs_destroy(xprt);
 	put_net(xprt->xprt_net);
 	xprt_free_all_slots(xprt);
 	xprt_free_id(xprt);
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v1 4/8] sunrpc: have client directory a symlink to the root transport
  2021-02-15 17:39 [PATCH v1 0/8] sysfs files for multipath transport control Dan Aloni
                   ` (2 preceding siblings ...)
  2021-02-15 17:39 ` [PATCH v1 3/8] sunrpc: add a directory per sunrpc xprt Dan Aloni
@ 2021-02-15 17:39 ` Dan Aloni
  2021-02-15 17:39 ` [PATCH v1 5/8] sunrpc: add IDs to multipath Dan Aloni
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Dan Aloni @ 2021-02-15 17:39 UTC (permalink / raw)
  To: linux-nfs, Anna Schumaker; +Cc: Trond Myklebust

Instead of duplicating `dstaddr` in client directory, we add a symlink
to the relevant transport directory which now hosts a `dstaddr`.

Signed-off-by: Dan Aloni <dan@kernelim.com>
---
 net/sunrpc/sysfs.c | 44 ++++++--------------------------------------
 1 file changed, 6 insertions(+), 38 deletions(-)

diff --git a/net/sunrpc/sysfs.c b/net/sunrpc/sysfs.c
index 687d4470b90d..ae608235d7e0 100644
--- a/net/sunrpc/sysfs.c
+++ b/net/sunrpc/sysfs.c
@@ -69,37 +69,6 @@ int rpc_sysfs_init(void)
 	return -ENOMEM;
 }
 
-static ssize_t rpc_netns_dstaddr_show(struct kobject *kobj,
-		struct kobj_attribute *attr, char *buf)
-{
-	struct rpc_netns_client *c = container_of(kobj,
-				struct rpc_netns_client, kobject);
-	struct rpc_clnt *clnt = c->clnt;
-	struct rpc_xprt *xprt = rcu_dereference(clnt->cl_xprt);
-
-	return rpc_ntop((struct sockaddr *)&xprt->addr, buf, PAGE_SIZE);
-}
-
-static ssize_t rpc_netns_dstaddr_store(struct kobject *kobj,
-		struct kobj_attribute *attr, const char *buf, size_t count)
-{
-	struct rpc_netns_client *c = container_of(kobj,
-				struct rpc_netns_client, kobject);
-	struct rpc_clnt *clnt = c->clnt;
-	struct rpc_xprt *xprt = rcu_dereference(clnt->cl_xprt);
-	struct sockaddr *saddr = (struct sockaddr *)&xprt->addr;
-	int port = rpc_get_port(saddr);
-
-	xprt->addrlen = rpc_pton(xprt->xprt_net, buf, count - 1, saddr, sizeof(*saddr));
-	rpc_set_port(saddr, port);
-
-	kfree(xprt->address_strings[RPC_DISPLAY_ADDR]);
-	xprt->address_strings[RPC_DISPLAY_ADDR] = kstrndup(buf, count - 1, GFP_KERNEL);
-
-	xprt->ops->connect(xprt, NULL);
-	return count;
-}
-
 static void rpc_netns_client_release(struct kobject *kobj)
 {
 	struct rpc_netns_client *c;
@@ -113,11 +82,7 @@ static const void *rpc_netns_client_namespace(struct kobject *kobj)
 	return container_of(kobj, struct rpc_netns_client, kobject)->net;
 }
 
-static struct kobj_attribute rpc_netns_client_dstaddr = __ATTR(dstaddr,
-		0644, rpc_netns_dstaddr_show, rpc_netns_dstaddr_store);
-
 static struct attribute *rpc_netns_client_attrs[] = {
-	&rpc_netns_client_dstaddr.attr,
 	NULL,
 };
 
@@ -156,12 +121,14 @@ void rpc_netns_client_sysfs_setup(struct rpc_clnt *clnt, struct net *net)
 {
 	struct rpc_netns_client *rpc_client;
 	struct rpc_xprt *xprt = rcu_dereference(clnt->cl_xprt);
-
-	if (!(xprt->prot & (IPPROTO_TCP | XPRT_TRANSPORT_RDMA)))
-		return;
+	struct rpc_netns_xprt *rpc_xprt;
+	int ret;
 
 	rpc_client = rpc_netns_client_alloc(rpc_client_kobj, net, clnt->cl_clid);
 	if (rpc_client) {
+		rpc_xprt = xprt->sysfs;
+		ret = sysfs_create_link_nowarn(&rpc_client->kobject,
+					 &rpc_xprt->kobject, "transport");
 		clnt->cl_sysfs = rpc_client;
 		rpc_client->clnt = clnt;
 		kobject_uevent(&rpc_client->kobject, KOBJ_ADD);
@@ -173,6 +140,7 @@ void rpc_netns_client_sysfs_destroy(struct rpc_clnt *clnt)
 	struct rpc_netns_client *rpc_client = clnt->cl_sysfs;
 
 	if (rpc_client) {
+		sysfs_remove_link(&rpc_client->kobject, "transport");
 		kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE);
 		kobject_del(&rpc_client->kobject);
 		kobject_put(&rpc_client->kobject);
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v1 5/8] sunrpc: add IDs to multipath
  2021-02-15 17:39 [PATCH v1 0/8] sysfs files for multipath transport control Dan Aloni
                   ` (3 preceding siblings ...)
  2021-02-15 17:39 ` [PATCH v1 4/8] sunrpc: have client directory a symlink to the root transport Dan Aloni
@ 2021-02-15 17:39 ` Dan Aloni
  2021-02-15 17:40 ` [PATCH v1 6/8] sunrpc: add multipath directory and symlink from client Dan Aloni
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Dan Aloni @ 2021-02-15 17:39 UTC (permalink / raw)
  To: linux-nfs, Anna Schumaker; +Cc: Trond Myklebust

This is used to uniquely identify sunrpc multipath objects in /sys.

Signed-off-by: Dan Aloni <dan@kernelim.com>
---
 include/linux/sunrpc/xprtmultipath.h |  4 ++++
 net/sunrpc/sunrpc_syms.c             |  1 +
 net/sunrpc/xprtmultipath.c           | 27 +++++++++++++++++++++++++++
 3 files changed, 32 insertions(+)

diff --git a/include/linux/sunrpc/xprtmultipath.h b/include/linux/sunrpc/xprtmultipath.h
index c6cce3fbf29d..ef95a6f18ccf 100644
--- a/include/linux/sunrpc/xprtmultipath.h
+++ b/include/linux/sunrpc/xprtmultipath.h
@@ -14,6 +14,7 @@ struct rpc_xprt_switch {
 	spinlock_t		xps_lock;
 	struct kref		xps_kref;
 
+	unsigned int		xps_id;
 	unsigned int		xps_nxprts;
 	unsigned int		xps_nactive;
 	atomic_long_t		xps_queuelen;
@@ -71,4 +72,7 @@ extern struct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi);
 
 extern bool rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps,
 		const struct sockaddr *sap);
+
+extern void xprt_multipath_cleanup_ids(void);
+
 #endif
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index b61b74c00483..691c0000e9ea 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -134,6 +134,7 @@ cleanup_sunrpc(void)
 	rpc_sysfs_exit();
 	rpc_cleanup_clids();
 	xprt_cleanup_ids();
+	xprt_multipath_cleanup_ids();
 	rpcauth_remove_module();
 	cleanup_socket_xprt();
 	svc_cleanup_xprt_sock();
diff --git a/net/sunrpc/xprtmultipath.c b/net/sunrpc/xprtmultipath.c
index 78c075a68c04..52a9584b23af 100644
--- a/net/sunrpc/xprtmultipath.c
+++ b/net/sunrpc/xprtmultipath.c
@@ -86,6 +86,31 @@ void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
 	xprt_put(xprt);
 }
 
+static DEFINE_IDA(rpc_xprtswitch_ids);
+
+void xprt_multipath_cleanup_ids(void)
+{
+       ida_destroy(&rpc_xprtswitch_ids);
+}
+
+static int xprt_switch_alloc_id(struct rpc_xprt_switch *xps)
+{
+       int id;
+
+       id = ida_simple_get(&rpc_xprtswitch_ids, 0, 0, GFP_KERNEL);
+       if (id < 0)
+               return id;
+
+       xps->xps_id = id;
+       return 0;
+}
+
+static void xprt_switch_free_id(struct rpc_xprt_switch *xps)
+{
+       ida_simple_remove(&rpc_xprtswitch_ids, xps->xps_id);
+}
+
+
 /**
  * xprt_switch_alloc - Allocate a new struct rpc_xprt_switch
  * @xprt: pointer to struct rpc_xprt
@@ -103,6 +128,7 @@ struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt,
 	if (xps != NULL) {
 		spin_lock_init(&xps->xps_lock);
 		kref_init(&xps->xps_kref);
+		xprt_switch_alloc_id(xps);
 		xps->xps_nxprts = xps->xps_nactive = 0;
 		atomic_long_set(&xps->xps_queuelen, 0);
 		xps->xps_net = NULL;
@@ -136,6 +162,7 @@ static void xprt_switch_free(struct kref *kref)
 			struct rpc_xprt_switch, xps_kref);
 
 	xprt_switch_free_entries(xps);
+	xprt_switch_free_id(xps);
 	kfree_rcu(xps, xps_rcu);
 }
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v1 6/8] sunrpc: add multipath directory and symlink from client
  2021-02-15 17:39 [PATCH v1 0/8] sysfs files for multipath transport control Dan Aloni
                   ` (4 preceding siblings ...)
  2021-02-15 17:39 ` [PATCH v1 5/8] sunrpc: add IDs to multipath Dan Aloni
@ 2021-02-15 17:40 ` Dan Aloni
  2021-02-15 17:40 ` [PATCH v1 7/8] sunrpc: change rpc_clnt_add_xprt() to rpc_add_xprt() Dan Aloni
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 16+ messages in thread
From: Dan Aloni @ 2021-02-15 17:40 UTC (permalink / raw)
  To: linux-nfs, Anna Schumaker; +Cc: Trond Myklebust

This also adds a `list` attribute to multipath directory that provides
the transport IDs of the transports contained in the multipath object.

Signed-off-by: Dan Aloni <dan@kernelim.com>
---
 include/linux/sunrpc/xprtmultipath.h |   2 +
 net/sunrpc/sysfs.c                   | 122 +++++++++++++++++++++++++++
 net/sunrpc/sysfs.h                   |   8 ++
 net/sunrpc/xprtmultipath.c           |  10 +++
 4 files changed, 142 insertions(+)

diff --git a/include/linux/sunrpc/xprtmultipath.h b/include/linux/sunrpc/xprtmultipath.h
index ef95a6f18ccf..2d0832dc10f5 100644
--- a/include/linux/sunrpc/xprtmultipath.h
+++ b/include/linux/sunrpc/xprtmultipath.h
@@ -24,6 +24,8 @@ struct rpc_xprt_switch {
 
 	const struct rpc_xprt_iter_ops *xps_iter_ops;
 
+	void                    *xps_sysfs; /* /sys/kernel/sunrpc/multipath/<id> */
+
 	struct rcu_head		xps_rcu;
 };
 
diff --git a/net/sunrpc/sysfs.c b/net/sunrpc/sysfs.c
index ae608235d7e0..3592f3b862b2 100644
--- a/net/sunrpc/sysfs.c
+++ b/net/sunrpc/sysfs.c
@@ -10,6 +10,7 @@
 
 struct kobject *rpc_client_kobj;
 struct kobject *rpc_xprt_kobj;
+struct kobject *rpc_xps_kobj;
 static struct kset *rpc_sunrpc_kset;
 
 static void rpc_netns_object_release(struct kobject *kobj)
@@ -58,8 +59,15 @@ int rpc_sysfs_init(void)
 	if (!rpc_xprt_kobj)
 		goto err_client;
 
+	rpc_xps_kobj = rpc_netns_object_alloc("multipath", rpc_sunrpc_kset, NULL);
+	if (!rpc_xps_kobj)
+		goto err_xprt;
+
 	return 0;
 
+err_xprt:
+	kobject_put(rpc_xprt_kobj);
+	rpc_xprt_kobj = NULL;
 err_client:
 	kobject_put(rpc_client_kobj);
 	rpc_client_kobj = NULL;
@@ -95,6 +103,7 @@ static struct kobj_type rpc_netns_client_type = {
 
 void rpc_sysfs_exit(void)
 {
+	kobject_put(rpc_xps_kobj);
 	kobject_put(rpc_xprt_kobj);
 	kobject_put(rpc_client_kobj);
 	kset_unregister(rpc_sunrpc_kset);
@@ -122,17 +131,29 @@ void rpc_netns_client_sysfs_setup(struct rpc_clnt *clnt, struct net *net)
 	struct rpc_netns_client *rpc_client;
 	struct rpc_xprt *xprt = rcu_dereference(clnt->cl_xprt);
 	struct rpc_netns_xprt *rpc_xprt;
+	struct rpc_netns_multipath *rpc_multipath;
+	struct rpc_xprt_switch *xps;
 	int ret;
 
+	xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
+
 	rpc_client = rpc_netns_client_alloc(rpc_client_kobj, net, clnt->cl_clid);
 	if (rpc_client) {
 		rpc_xprt = xprt->sysfs;
 		ret = sysfs_create_link_nowarn(&rpc_client->kobject,
 					 &rpc_xprt->kobject, "transport");
+		if (xps) {
+			rpc_multipath = xps->xps_sysfs;
+			ret = sysfs_create_link_nowarn(&rpc_client->kobject,
+						       &rpc_multipath->kobject,
+						       "multipath");
+		}
 		clnt->cl_sysfs = rpc_client;
 		rpc_client->clnt = clnt;
 		kobject_uevent(&rpc_client->kobject, KOBJ_ADD);
 	}
+
+	xprt_switch_put(xps);
 }
 
 void rpc_netns_client_sysfs_destroy(struct rpc_clnt *clnt)
@@ -141,6 +162,7 @@ void rpc_netns_client_sysfs_destroy(struct rpc_clnt *clnt)
 
 	if (rpc_client) {
 		sysfs_remove_link(&rpc_client->kobject, "transport");
+		sysfs_remove_link(&rpc_client->kobject, "multipath");
 		kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE);
 		kobject_del(&rpc_client->kobject);
 		kobject_put(&rpc_client->kobject);
@@ -255,3 +277,103 @@ void rpc_netns_xprt_sysfs_destroy(struct rpc_xprt *xprt)
 		xprt->sysfs = NULL;
 	}
 }
+
+static void rpc_netns_multipath_release(struct kobject *kobj)
+{
+	struct rpc_netns_multipath *c;
+
+	c = container_of(kobj, struct rpc_netns_multipath, kobject);
+	kfree(c);
+}
+
+static const void *rpc_netns_multipath_namespace(struct kobject *kobj)
+{
+	return container_of(kobj, struct rpc_netns_multipath, kobject)->net;
+}
+
+static ssize_t rpc_netns_multipath_list_show(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	struct rpc_netns_multipath *c =
+		container_of(kobj, struct rpc_netns_multipath, kobject);
+	struct rpc_xprt_switch *xps = c->xps;
+	struct rpc_xprt_iter xpi;
+	int pos = 0;
+
+	xprt_iter_init_listall(&xpi, xps);
+	for (;;) {
+		struct rpc_xprt *xprt = xprt_iter_get_next(&xpi);
+		if (!xprt)
+			break;
+
+		snprintf(&buf[pos], PAGE_SIZE - pos, "%d\n", xprt->id);
+		pos += strlen(&buf[pos]);
+		xprt_put(xprt);
+	}
+	xprt_iter_destroy(&xpi);
+
+	return pos;
+}
+
+static ssize_t rpc_netns_multipath_list_store(struct kobject *kobj,
+		struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	return -EINVAL;
+}
+
+static struct kobj_attribute rpc_netns_multipath_list = __ATTR(list,
+	0644, rpc_netns_multipath_list_show, rpc_netns_multipath_list_store);
+
+
+static struct attribute *rpc_netns_multipath_attrs[] = {
+	&rpc_netns_multipath_list.attr,
+	NULL,
+};
+
+static struct kobj_type rpc_netns_multipath_type = {
+	.release = rpc_netns_multipath_release,
+	.default_attrs = rpc_netns_multipath_attrs,
+	.sysfs_ops = &kobj_sysfs_ops,
+	.namespace = rpc_netns_multipath_namespace,
+};
+
+static struct rpc_netns_multipath *rpc_netns_multipath_alloc(struct kobject *parent,
+							     struct net *net, int id)
+{
+	struct rpc_netns_multipath *p;
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (p) {
+		p->net = net;
+		p->kobject.kset = rpc_sunrpc_kset;
+		if (kobject_init_and_add(&p->kobject, &rpc_netns_multipath_type,
+					 parent, "%d", id) == 0)
+			return p;
+		kobject_put(&p->kobject);
+	}
+	return NULL;
+}
+
+void rpc_netns_multipath_sysfs_setup(struct rpc_xprt_switch *xps, struct net *net)
+{
+	struct rpc_netns_multipath *rpc_multipath;
+
+	rpc_multipath = rpc_netns_multipath_alloc(rpc_xps_kobj, net, xps->xps_id);
+	if (rpc_multipath) {
+		xps->xps_sysfs = rpc_multipath;
+		rpc_multipath->xps = xps;
+		kobject_uevent(&rpc_multipath->kobject, KOBJ_ADD);
+	}
+}
+
+void rpc_netns_multipath_sysfs_destroy(struct rpc_xprt_switch *xps)
+{
+	struct rpc_netns_multipath *rpc_multipath = xps->xps_sysfs;
+
+	if (rpc_multipath) {
+		kobject_uevent(&rpc_multipath->kobject, KOBJ_REMOVE);
+		kobject_del(&rpc_multipath->kobject);
+		kobject_put(&rpc_multipath->kobject);
+		xps->xps_sysfs = NULL;
+	}
+}
diff --git a/net/sunrpc/sysfs.h b/net/sunrpc/sysfs.h
index e08dd7f6a1ec..b2e379f78b91 100644
--- a/net/sunrpc/sysfs.h
+++ b/net/sunrpc/sysfs.h
@@ -17,6 +17,12 @@ struct rpc_netns_xprt {
 	struct rpc_xprt *xprt;
 };
 
+struct rpc_netns_multipath {
+	struct kobject kobject;
+	struct net *net;
+	struct rpc_xprt_switch *xps;
+};
+
 extern struct kobject *rpc_client_kobj;
 extern struct kobject *rpc_xprt_kobj;
 
@@ -27,5 +33,7 @@ void rpc_netns_client_sysfs_setup(struct rpc_clnt *clnt, struct net *net);
 void rpc_netns_client_sysfs_destroy(struct rpc_clnt *clnt);
 void rpc_netns_xprt_sysfs_setup(struct rpc_xprt *xprt, struct net *net);
 void rpc_netns_xprt_sysfs_destroy(struct rpc_xprt *xprt);
+void rpc_netns_multipath_sysfs_setup(struct rpc_xprt_switch *xps, struct net *net);
+void rpc_netns_multipath_sysfs_destroy(struct rpc_xprt_switch *xps);
 
 #endif
diff --git a/net/sunrpc/xprtmultipath.c b/net/sunrpc/xprtmultipath.c
index 52a9584b23af..d03fb3bb74ce 100644
--- a/net/sunrpc/xprtmultipath.c
+++ b/net/sunrpc/xprtmultipath.c
@@ -19,6 +19,8 @@
 #include <linux/sunrpc/addr.h>
 #include <linux/sunrpc/xprtmultipath.h>
 
+#include "sysfs.h"
+
 typedef struct rpc_xprt *(*xprt_switch_find_xprt_t)(struct rpc_xprt_switch *xps,
 		const struct rpc_xprt *cur);
 
@@ -83,6 +85,9 @@ void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
 	spin_lock(&xps->xps_lock);
 	xprt_switch_remove_xprt_locked(xps, xprt);
 	spin_unlock(&xps->xps_lock);
+
+	if (!xps->xps_net)
+		rpc_netns_multipath_sysfs_destroy(xps);
 	xprt_put(xprt);
 }
 
@@ -135,6 +140,10 @@ struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt,
 		INIT_LIST_HEAD(&xps->xps_xprt_list);
 		xps->xps_iter_ops = &rpc_xprt_iter_singular;
 		xprt_switch_add_xprt_locked(xps, xprt);
+		xps->xps_sysfs = NULL;
+
+		if (xprt->xprt_net != NULL)
+			rpc_netns_multipath_sysfs_setup(xps, xprt->xprt_net);
 	}
 
 	return xps;
@@ -162,6 +171,7 @@ static void xprt_switch_free(struct kref *kref)
 			struct rpc_xprt_switch, xps_kref);
 
 	xprt_switch_free_entries(xps);
+	rpc_netns_multipath_sysfs_destroy(xps);
 	xprt_switch_free_id(xps);
 	kfree_rcu(xps, xps_rcu);
 }
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v1 7/8] sunrpc: change rpc_clnt_add_xprt() to rpc_add_xprt()
  2021-02-15 17:39 [PATCH v1 0/8] sysfs files for multipath transport control Dan Aloni
                   ` (5 preceding siblings ...)
  2021-02-15 17:40 ` [PATCH v1 6/8] sunrpc: add multipath directory and symlink from client Dan Aloni
@ 2021-02-15 17:40 ` Dan Aloni
  2021-02-15 17:40 ` [PATCH v1 8/8] sunrpc: introduce an 'add' node to 'multipath' sysfs directory Dan Aloni
  2021-03-02  3:56 ` [PATCH v1 0/8] sysfs files for multipath transport control Olga Kornievskaia
  8 siblings, 0 replies; 16+ messages in thread
From: Dan Aloni @ 2021-02-15 17:40 UTC (permalink / raw)
  To: linux-nfs, Anna Schumaker; +Cc: Trond Myklebust

This change of API allows adding transports without holding a reference
to an rpc client.

Signed-off-by: Dan Aloni <dan@kernelim.com>
---
 fs/nfs/pnfs_nfs.c           | 12 +++++++-----
 include/linux/sunrpc/clnt.h | 12 +++++++-----
 net/sunrpc/clnt.c           | 31 +++++++++++++++++--------------
 3 files changed, 31 insertions(+), 24 deletions(-)

diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c
index 49d3389bd813..1e61626bd0fa 100644
--- a/fs/nfs/pnfs_nfs.c
+++ b/fs/nfs/pnfs_nfs.c
@@ -878,8 +878,9 @@ static int _nfs4_pnfs_v3_ds_connect(struct nfs_server *mds_srv,
 			if (da->da_addr.ss_family != clp->cl_addr.ss_family)
 				continue;
 			/* Add this address as an alias */
-			rpc_clnt_add_xprt(clp->cl_rpcclient, &xprt_args,
-					rpc_clnt_test_and_add_xprt, NULL);
+			rpc_add_xprt(&clp->cl_rpcclient->cl_xpi,
+				     clp->cl_rpcclient, &xprt_args,
+				     rpc_clnt_test_and_add_xprt, NULL);
 			continue;
 		}
 		clp = get_v3_ds_connect(mds_srv,
@@ -945,9 +946,10 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
 			* add as an alias
 			*/
 			xprtdata.cred = nfs4_get_clid_cred(clp),
-			rpc_clnt_add_xprt(clp->cl_rpcclient, &xprt_args,
-					  rpc_clnt_setup_test_and_add_xprt,
-					  &rpcdata);
+			rpc_add_xprt(&clp->cl_rpcclient->cl_xpi,
+				     clp->cl_rpcclient, &xprt_args,
+				     rpc_clnt_setup_test_and_add_xprt,
+				     &rpcdata);
 			if (xprtdata.cred)
 				put_cred(xprtdata.cred);
 		} else {
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 503653720e18..19bb23143eef 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -210,21 +210,23 @@ int 		rpc_clnt_iterate_for_each_xprt(struct rpc_clnt *clnt,
 			int (*fn)(struct rpc_clnt *, struct rpc_xprt *, void *),
 			void *data);
 
-int 		rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
+int 		rpc_clnt_test_and_add_xprt(void *clnt,
 			struct rpc_xprt_switch *xps,
 			struct rpc_xprt *xprt,
 			void *dummy);
-int		rpc_clnt_add_xprt(struct rpc_clnt *, struct xprt_create *,
-			int (*setup)(struct rpc_clnt *,
+int		rpc_add_xprt(struct rpc_xprt_iter *iter,
+		        void *ctx,
+		        struct xprt_create *xprtargs,
+		        int (*setup)(void *ctx,
 				struct rpc_xprt_switch *,
 				struct rpc_xprt *,
 				void *),
-			void *data);
+		        void *data);
 void		rpc_set_connect_timeout(struct rpc_clnt *clnt,
 			unsigned long connect_timeout,
 			unsigned long reconnect_timeout);
 
-int		rpc_clnt_setup_test_and_add_xprt(struct rpc_clnt *,
+int		rpc_clnt_setup_test_and_add_xprt(void *,
 			struct rpc_xprt_switch *,
 			struct rpc_xprt *,
 			void *);
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 0a4811be01cd..b94d274a5446 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -598,7 +598,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
 		return clnt;
 
 	for (i = 0; i < args->nconnect - 1; i++) {
-		if (rpc_clnt_add_xprt(clnt, &xprtargs, NULL, NULL) < 0)
+		if (rpc_add_xprt(&clnt->cl_xpi, NULL, &xprtargs, NULL, NULL) < 0)
 			break;
 	}
 	return clnt;
@@ -2751,10 +2751,11 @@ static const struct rpc_call_ops rpc_cb_add_xprt_call_ops = {
  * @xprt: pointer struct rpc_xprt
  * @dummy: unused
  */
-int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
+int rpc_clnt_test_and_add_xprt(void *ptr,
 		struct rpc_xprt_switch *xps, struct rpc_xprt *xprt,
 		void *dummy)
 {
+	struct rpc_clnt *clnt = ptr;
 	struct rpc_cb_add_xprt_calldata *data;
 	struct rpc_task *task;
 
@@ -2795,11 +2796,12 @@ EXPORT_SYMBOL_GPL(rpc_clnt_test_and_add_xprt);
  * @data: a struct rpc_add_xprt_test pointer that holds the test function
  *        and test function call data
  */
-int rpc_clnt_setup_test_and_add_xprt(struct rpc_clnt *clnt,
+int rpc_clnt_setup_test_and_add_xprt(void *ptr,
 				     struct rpc_xprt_switch *xps,
 				     struct rpc_xprt *xprt,
 				     void *data)
 {
+	struct rpc_clnt *clnt = ptr;
 	struct rpc_task *task;
 	struct rpc_add_xprt_test *xtest = (struct rpc_add_xprt_test *)data;
 	int status = -EADDRINUSE;
@@ -2852,13 +2854,14 @@ EXPORT_SYMBOL_GPL(rpc_clnt_setup_test_and_add_xprt);
  * adding the new transport.
  *
  */
-int rpc_clnt_add_xprt(struct rpc_clnt *clnt,
-		struct xprt_create *xprtargs,
-		int (*setup)(struct rpc_clnt *,
-			struct rpc_xprt_switch *,
-			struct rpc_xprt *,
-			void *),
-		void *data)
+int rpc_add_xprt(struct rpc_xprt_iter *iter,
+		 void *ctx,
+		 struct xprt_create *xprtargs,
+		 int (*setup)(void *ctx,
+			      struct rpc_xprt_switch *,
+			      struct rpc_xprt *,
+			      void *),
+		 void *data)
 {
 	struct rpc_xprt_switch *xps;
 	struct rpc_xprt *xprt;
@@ -2868,8 +2871,8 @@ int rpc_clnt_add_xprt(struct rpc_clnt *clnt,
 	int ret = 0;
 
 	rcu_read_lock();
-	xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
-	xprt = xprt_iter_xprt(&clnt->cl_xpi);
+	xps = xprt_switch_get(rcu_dereference(iter->xpi_xpswitch));
+	xprt = xprt_iter_xprt(iter);
 	if (xps == NULL || xprt == NULL) {
 		rcu_read_unlock();
 		xprt_switch_put(xps);
@@ -2895,7 +2898,7 @@ int rpc_clnt_add_xprt(struct rpc_clnt *clnt,
 
 	rpc_xprt_switch_set_roundrobin(xps);
 	if (setup) {
-		ret = setup(clnt, xps, xprt, data);
+		ret = setup(ctx, xps, xprt, data);
 		if (ret != 0)
 			goto out_put_xprt;
 	}
@@ -2906,7 +2909,7 @@ int rpc_clnt_add_xprt(struct rpc_clnt *clnt,
 	xprt_switch_put(xps);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(rpc_clnt_add_xprt);
+EXPORT_SYMBOL_GPL(rpc_add_xprt);
 
 struct connect_timeout_data {
 	unsigned long connect_timeout;
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v1 8/8] sunrpc: introduce an 'add' node to 'multipath' sysfs directory
  2021-02-15 17:39 [PATCH v1 0/8] sysfs files for multipath transport control Dan Aloni
                   ` (6 preceding siblings ...)
  2021-02-15 17:40 ` [PATCH v1 7/8] sunrpc: change rpc_clnt_add_xprt() to rpc_add_xprt() Dan Aloni
@ 2021-02-15 17:40 ` Dan Aloni
  2021-03-02  3:56 ` [PATCH v1 0/8] sysfs files for multipath transport control Olga Kornievskaia
  8 siblings, 0 replies; 16+ messages in thread
From: Dan Aloni @ 2021-02-15 17:40 UTC (permalink / raw)
  To: linux-nfs, Anna Schumaker; +Cc: Trond Myklebust

This allows adding new transports to an existing multipath switch. This
is similar to what the `nconnect` mount parameter does, but instead we
can do this while the NFS mount is live.

For example:

    echo 'dstaddr 192.168.40.8 kind rdma' \
	   > /sys/kernel/sunrpc/client/0/multipath/add

Signed-off-by: Dan Aloni <dan@kernelim.com>
---
 net/sunrpc/sysfs.c | 104 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 101 insertions(+), 3 deletions(-)

diff --git a/net/sunrpc/sysfs.c b/net/sunrpc/sysfs.c
index 3592f3b862b2..d745dfb7cef4 100644
--- a/net/sunrpc/sysfs.c
+++ b/net/sunrpc/sysfs.c
@@ -315,18 +315,116 @@ static ssize_t rpc_netns_multipath_list_show(struct kobject *kobj,
 	return pos;
 }
 
-static ssize_t rpc_netns_multipath_list_store(struct kobject *kobj,
+static ssize_t rpc_netns_multipath_add_store(struct kobject *kobj,
 		struct kobj_attribute *attr, const char *buf, size_t count)
 {
-	return -EINVAL;
+	struct rpc_netns_multipath *c =
+		container_of(kobj, struct rpc_netns_multipath, kobject);
+	struct rpc_xprt_switch *xps = c->xps;
+	struct rpc_xprt_iter xpi;
+	struct sockaddr_storage addr;
+	struct xprt_create xprt_args = {
+		.ident = XPRT_TRANSPORT_RDMA,
+		.net = c->net,
+		.dstaddr = (struct sockaddr *)&addr,
+	};
+	struct rpc_xprt *existing_xprt;
+	char *opt, *str, *arg;
+	bool has_dstaddr = false;
+	bool has_kind = false;
+	int err;
+
+	opt = kstrndup(buf, count, GFP_KERNEL);
+	if (!opt)
+		return -ENOMEM;
+
+	str = strstrip(opt);
+
+	while (1) {
+		arg = strsep(&str, " ");
+		if (!arg)
+			break;
+
+		if (sysfs_streq(arg, "kind")) {
+			arg = strsep(&str, " ");
+			if (!arg) {
+				err = -EINVAL;
+				goto out;
+			}
+			if (has_kind) {
+				err = -EINVAL;
+				goto out;
+			}
+
+			if (sysfs_streq(arg, "rdma")) {
+				xprt_args.ident = XPRT_TRANSPORT_RDMA;
+			} else if (sysfs_streq(arg, "tcp")) {
+				xprt_args.ident = XPRT_TRANSPORT_TCP;
+			} else {
+				err = -EINVAL;
+				goto out;
+			}
+
+			has_kind = true;
+		} else if (sysfs_streq(arg, "dstaddr")) {
+			arg = strsep(&str, " ");
+			if (!arg) {
+				err = -EINVAL;
+				goto out;
+			}
+			xprt_args.addrlen = rpc_pton(c->net,
+				arg, strlen(arg), (struct sockaddr *)&addr,
+				sizeof(addr));
+			if (has_dstaddr || !xprt_args.addrlen) {
+				err = -EINVAL;
+				goto out;
+			}
+
+			has_dstaddr = true;
+		} else {
+			break;
+		}
+	}
+
+	if (!has_dstaddr || !has_kind)  {
+		err = -EINVAL;
+		goto out;
+	}
+
+
+	/* Discover an existing xprt */
+	xprt_iter_init_listall(&xpi, xps);
+	existing_xprt = xprt_iter_get_next(&xpi);
+	xprt_iter_destroy(&xpi);
+
+	if (!existing_xprt) {
+		err = -ENOENT;
+		goto out;
+	}
+
+	xprt_args.servername = existing_xprt->servername;
+	xprt_iter_init_listall(&xpi, xps);
+	rpc_add_xprt(&xpi, NULL, &xprt_args, NULL, NULL);
+	xprt_iter_destroy(&xpi);
+
+	xprt_put(existing_xprt);
+
+	err = count;
+out:
+	kfree(opt);
+
+	return err;
 }
 
 static struct kobj_attribute rpc_netns_multipath_list = __ATTR(list,
-	0644, rpc_netns_multipath_list_show, rpc_netns_multipath_list_store);
+	0444, rpc_netns_multipath_list_show, NULL);
 
+static struct kobj_attribute rpc_netns_multipath_add = __ATTR(add,
+	0200, NULL, rpc_netns_multipath_add_store);
 
 static struct attribute *rpc_netns_multipath_attrs[] = {
 	&rpc_netns_multipath_list.attr,
+	&rpc_netns_multipath_add.attr,
 	NULL,
 };
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 1/8] sunrpc: rename 'net' to 'client'
  2021-02-15 17:39 ` [PATCH v1 1/8] sunrpc: rename 'net' to 'client' Dan Aloni
@ 2021-02-16 21:24   ` Anna Schumaker
  2021-02-17 18:58     ` Dan Aloni
  0 siblings, 1 reply; 16+ messages in thread
From: Anna Schumaker @ 2021-02-16 21:24 UTC (permalink / raw)
  To: Dan Aloni; +Cc: Linux NFS Mailing List, Trond Myklebust

Hi Dan,

On Mon, Feb 15, 2021 at 12:42 PM Dan Aloni <dan@kernelim.com> wrote:
>
> This is in preparation to adding a second directory to keep track
> of each transport.

I initially named the directory "net" to match how NFS's sysfs
directories are created (/sys/fs/nfs/net). If naming it "client" makes
more sense then I should probably introduce it that way in my patches.

Thoughts?
Anna

>
> Signed-off-by: Dan Aloni <dan@kernelim.com>
> ---
>  net/sunrpc/clnt.c  |  8 ++++----
>  net/sunrpc/sysfs.c | 22 +++++++++++-----------
>  net/sunrpc/sysfs.h |  4 ++--
>  3 files changed, 17 insertions(+), 17 deletions(-)
>
> diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
> index 02905eae5c0a..0a4811be01cd 100644
> --- a/net/sunrpc/clnt.c
> +++ b/net/sunrpc/clnt.c
> @@ -301,7 +301,7 @@ static int rpc_client_register(struct rpc_clnt *clnt,
>         int err;
>
>         rpc_clnt_debugfs_register(clnt);
> -       rpc_netns_sysfs_setup(clnt, net);
> +       rpc_netns_client_sysfs_setup(clnt, net);
>
>         pipefs_sb = rpc_get_sb_net(net);
>         if (pipefs_sb) {
> @@ -329,7 +329,7 @@ static int rpc_client_register(struct rpc_clnt *clnt,
>  out:
>         if (pipefs_sb)
>                 rpc_put_sb_net(net);
> -       rpc_netns_sysfs_destroy(clnt);
> +       rpc_netns_client_sysfs_destroy(clnt);
>         rpc_clnt_debugfs_unregister(clnt);
>         return err;
>  }
> @@ -736,7 +736,7 @@ int rpc_switch_client_transport(struct rpc_clnt *clnt,
>
>         rpc_unregister_client(clnt);
>         __rpc_clnt_remove_pipedir(clnt);
> -       rpc_netns_sysfs_destroy(clnt);
> +       rpc_netns_client_sysfs_destroy(clnt);
>         rpc_clnt_debugfs_unregister(clnt);
>
>         /*
> @@ -883,7 +883,7 @@ static void rpc_free_client_work(struct work_struct *work)
>          * so they cannot be called in rpciod, so they are handled separately
>          * here.
>          */
> -       rpc_netns_sysfs_destroy(clnt);
> +       rpc_netns_client_sysfs_destroy(clnt);
>         rpc_clnt_debugfs_unregister(clnt);
>         rpc_free_clid(clnt);
>         rpc_clnt_remove_pipedir(clnt);
> diff --git a/net/sunrpc/sysfs.c b/net/sunrpc/sysfs.c
> index 8b01b4df64ee..3fe814795ed9 100644
> --- a/net/sunrpc/sysfs.c
> +++ b/net/sunrpc/sysfs.c
> @@ -9,7 +9,7 @@
>  #include "sysfs.h"
>
>  struct kobject *rpc_client_kobj;
> -static struct kset *rpc_client_kset;
> +static struct kset *rpc_sunrpc_kset;
>
>  static void rpc_netns_object_release(struct kobject *kobj)
>  {
> @@ -45,13 +45,13 @@ static struct kobject *rpc_netns_object_alloc(const char *name,
>
>  int rpc_sysfs_init(void)
>  {
> -       rpc_client_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
> -       if (!rpc_client_kset)
> +       rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
> +       if (!rpc_sunrpc_kset)
>                 return -ENOMEM;
> -       rpc_client_kobj = rpc_netns_object_alloc("net", rpc_client_kset, NULL);
> +       rpc_client_kobj = rpc_netns_object_alloc("client", rpc_sunrpc_kset, NULL);
>         if (!rpc_client_kobj) {
> -               kset_unregister(rpc_client_kset);
> -               rpc_client_kset = NULL;
> +               kset_unregister(rpc_sunrpc_kset);
> +               rpc_sunrpc_kset = NULL;
>                 return -ENOMEM;
>         }
>         return 0;
> @@ -119,18 +119,18 @@ static struct kobj_type rpc_netns_client_type = {
>  void rpc_sysfs_exit(void)
>  {
>         kobject_put(rpc_client_kobj);
> -       kset_unregister(rpc_client_kset);
> +       kset_unregister(rpc_sunrpc_kset);
>  }
>
>  static struct rpc_netns_client *rpc_netns_client_alloc(struct kobject *parent,
> -                                               struct net *net, int clid)
> +                                                      struct net *net, int clid)
>  {
>         struct rpc_netns_client *p;
>
>         p = kzalloc(sizeof(*p), GFP_KERNEL);
>         if (p) {
>                 p->net = net;
> -               p->kobject.kset = rpc_client_kset;
> +               p->kobject.kset = rpc_sunrpc_kset;
>                 if (kobject_init_and_add(&p->kobject, &rpc_netns_client_type,
>                                         parent, "%d", clid) == 0)
>                         return p;
> @@ -139,7 +139,7 @@ static struct rpc_netns_client *rpc_netns_client_alloc(struct kobject *parent,
>         return NULL;
>  }
>
> -void rpc_netns_sysfs_setup(struct rpc_clnt *clnt, struct net *net)
> +void rpc_netns_client_sysfs_setup(struct rpc_clnt *clnt, struct net *net)
>  {
>         struct rpc_netns_client *rpc_client;
>         struct rpc_xprt *xprt = rcu_dereference(clnt->cl_xprt);
> @@ -155,7 +155,7 @@ void rpc_netns_sysfs_setup(struct rpc_clnt *clnt, struct net *net)
>         }
>  }
>
> -void rpc_netns_sysfs_destroy(struct rpc_clnt *clnt)
> +void rpc_netns_client_sysfs_destroy(struct rpc_clnt *clnt)
>  {
>         struct rpc_netns_client *rpc_client = clnt->cl_sysfs;
>
> diff --git a/net/sunrpc/sysfs.h b/net/sunrpc/sysfs.h
> index 137a12c87954..ab75c3cc91b6 100644
> --- a/net/sunrpc/sysfs.h
> +++ b/net/sunrpc/sysfs.h
> @@ -16,7 +16,7 @@ extern struct kobject *rpc_client_kobj;
>  extern int rpc_sysfs_init(void);
>  extern void rpc_sysfs_exit(void);
>
> -void rpc_netns_sysfs_setup(struct rpc_clnt *clnt, struct net *net);
> -void rpc_netns_sysfs_destroy(struct rpc_clnt *clnt);
> +void rpc_netns_client_sysfs_setup(struct rpc_clnt *clnt, struct net *net);
> +void rpc_netns_client_sysfs_destroy(struct rpc_clnt *clnt);
>
>  #endif
> --
> 2.26.2
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 3/8] sunrpc: add a directory per sunrpc xprt
  2021-02-15 17:39 ` [PATCH v1 3/8] sunrpc: add a directory per sunrpc xprt Dan Aloni
@ 2021-02-16 21:46   ` Anna Schumaker
  2021-02-17 19:01     ` Dan Aloni
  0 siblings, 1 reply; 16+ messages in thread
From: Anna Schumaker @ 2021-02-16 21:46 UTC (permalink / raw)
  To: Dan Aloni; +Cc: Linux NFS Mailing List, Trond Myklebust

Hi Dan,

On Mon, Feb 15, 2021 at 12:42 PM Dan Aloni <dan@kernelim.com> wrote:
>
> This uses much of the code from the per-client directory, except that
> now we have direct access to the transport struct. The per-client
> direct is adjusted in a subsequent commit.

Just a heads up that I've changed the per-client functions a bit, so
you'll probably need to adjust for that once I post v3 of my patches.


>
> Signed-off-by: Dan Aloni <dan@kernelim.com>
> ---
>  include/linux/sunrpc/xprt.h |   1 +
>  net/sunrpc/sysfs.c          | 131 ++++++++++++++++++++++++++++++++++--
>  net/sunrpc/sysfs.h          |   9 +++
>  net/sunrpc/xprt.c           |   3 +
>  4 files changed, 139 insertions(+), 5 deletions(-)
>
> diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
> index fbf57a87dc47..df0252de58f4 100644
> --- a/include/linux/sunrpc/xprt.h
> +++ b/include/linux/sunrpc/xprt.h
> @@ -260,6 +260,7 @@ struct rpc_xprt {
>                                                  * items */
>         struct list_head        bc_pa_list;     /* List of preallocated
>                                                  * backchannel rpc_rqst's */
> +       void                    *sysfs;         /* /sys/kernel/sunrpc/xprt/<id> */
>  #endif /* CONFIG_SUNRPC_BACKCHANNEL */
>
>         struct rb_root          recv_queue;     /* Receive queue */
> diff --git a/net/sunrpc/sysfs.c b/net/sunrpc/sysfs.c
> index 3fe814795ed9..687d4470b90d 100644
> --- a/net/sunrpc/sysfs.c
> +++ b/net/sunrpc/sysfs.c
> @@ -9,6 +9,7 @@
>  #include "sysfs.h"
>
>  struct kobject *rpc_client_kobj;
> +struct kobject *rpc_xprt_kobj;
>  static struct kset *rpc_sunrpc_kset;
>
>  static void rpc_netns_object_release(struct kobject *kobj)
> @@ -48,13 +49,24 @@ int rpc_sysfs_init(void)
>         rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
>         if (!rpc_sunrpc_kset)
>                 return -ENOMEM;
> +
>         rpc_client_kobj = rpc_netns_object_alloc("client", rpc_sunrpc_kset, NULL);
> -       if (!rpc_client_kobj) {
> -               kset_unregister(rpc_sunrpc_kset);
> -               rpc_sunrpc_kset = NULL;
> -               return -ENOMEM;
> -       }
> +       if (!rpc_client_kobj)
> +               goto err_kset;
> +
> +       rpc_xprt_kobj = rpc_netns_object_alloc("transport", rpc_sunrpc_kset, NULL);
> +       if (!rpc_xprt_kobj)
> +               goto err_client;
> +
>         return 0;
> +
> +err_client:
> +       kobject_put(rpc_client_kobj);
> +       rpc_client_kobj = NULL;
> +err_kset:
> +       kset_unregister(rpc_sunrpc_kset);
> +       rpc_sunrpc_kset = NULL;
> +       return -ENOMEM;
>  }
>
>  static ssize_t rpc_netns_dstaddr_show(struct kobject *kobj,
> @@ -118,6 +130,7 @@ static struct kobj_type rpc_netns_client_type = {
>
>  void rpc_sysfs_exit(void)
>  {
> +       kobject_put(rpc_xprt_kobj);
>         kobject_put(rpc_client_kobj);
>         kset_unregister(rpc_sunrpc_kset);
>  }
> @@ -166,3 +179,111 @@ void rpc_netns_client_sysfs_destroy(struct rpc_clnt *clnt)
>                 clnt->cl_sysfs = NULL;
>         }
>  }
> +
> +static ssize_t rpc_netns_xprt_dstaddr_show(struct kobject *kobj,
> +               struct kobj_attribute *attr, char *buf)
> +{
> +       struct rpc_netns_xprt *c = container_of(kobj,
> +                               struct rpc_netns_xprt, kobject);
> +       struct rpc_xprt *xprt = c->xprt;
> +
> +       if (!(xprt->prot & (IPPROTO_TCP | XPRT_TRANSPORT_RDMA))) {

We might want to change these restrictions later on, so if we're going
to put this into each function then maybe it would make sense to have
a quick inline to check protocol support?

I do the same check in the setup function for my patches, so if you
want I can add the inline function and then it'll just be there for
you to use.

> +               sprintf(buf, "N/A");
> +               return 0;

I'm guessing the point of putting "N/A" here is so userspace tools
don't have to guess which files exist or not for each protocol type?
Should I change my patches to match this style too?

Anna

> +       }
> +
> +       return rpc_ntop((struct sockaddr *)&xprt->addr, buf, PAGE_SIZE);
> +}
> +
> +static ssize_t rpc_netns_xprt_dstaddr_store(struct kobject *kobj,
> +               struct kobj_attribute *attr, const char *buf, size_t count)
> +{
> +       struct rpc_netns_xprt *c = container_of(kobj,
> +                               struct rpc_netns_xprt, kobject);
> +       struct rpc_xprt *xprt = c->xprt;
> +       struct sockaddr *saddr = (struct sockaddr *)&xprt->addr;
> +       int port;
> +
> +       if (!(xprt->prot & (IPPROTO_TCP | XPRT_TRANSPORT_RDMA)))
> +               return -EINVAL;
> +
> +       port = rpc_get_port(saddr);
> +
> +       xprt->addrlen = rpc_pton(xprt->xprt_net, buf, count - 1, saddr, sizeof(*saddr));
> +       rpc_set_port(saddr, port);
> +
> +       kfree(xprt->address_strings[RPC_DISPLAY_ADDR]);
> +       xprt->address_strings[RPC_DISPLAY_ADDR] = kstrndup(buf, count - 1, GFP_KERNEL);
> +
> +       xprt->ops->connect(xprt, NULL);
> +       return count;
> +}
> +
> +static void rpc_netns_xprt_release(struct kobject *kobj)
> +{
> +       struct rpc_netns_xprt *c;
> +
> +       c = container_of(kobj, struct rpc_netns_xprt, kobject);
> +       kfree(c);
> +}
> +
> +static const void *rpc_netns_xprt_namespace(struct kobject *kobj)
> +{
> +       return container_of(kobj, struct rpc_netns_xprt, kobject)->net;
> +}
> +
> +static struct kobj_attribute rpc_netns_xprt_dstaddr = __ATTR(dstaddr,
> +               0644, rpc_netns_xprt_dstaddr_show, rpc_netns_xprt_dstaddr_store);
> +
> +static struct attribute *rpc_netns_xprt_attrs[] = {
> +       &rpc_netns_xprt_dstaddr.attr,
> +       NULL,
> +};
> +
> +static struct kobj_type rpc_netns_xprt_type = {
> +       .release = rpc_netns_xprt_release,
> +       .default_attrs = rpc_netns_xprt_attrs,
> +       .sysfs_ops = &kobj_sysfs_ops,
> +       .namespace = rpc_netns_xprt_namespace,
> +};
> +
> +static struct rpc_netns_xprt *rpc_netns_xprt_alloc(struct kobject *parent,
> +                                                  struct net *net, int id)
> +{
> +       struct rpc_netns_xprt *p;
> +
> +       p = kzalloc(sizeof(*p), GFP_KERNEL);
> +       if (p) {
> +               p->net = net;
> +               p->kobject.kset = rpc_sunrpc_kset;
> +               if (kobject_init_and_add(&p->kobject, &rpc_netns_xprt_type,
> +                                        parent, "%d", id) == 0)
> +                       return p;
> +               kobject_put(&p->kobject);
> +       }
> +       return NULL;
> +}
> +
> +void rpc_netns_xprt_sysfs_setup(struct rpc_xprt *xprt, struct net *net)
> +{
> +       struct rpc_netns_xprt *rpc_xprt;
> +
> +       rpc_xprt = rpc_netns_xprt_alloc(rpc_xprt_kobj, net, xprt->id);
> +       if (rpc_xprt) {
> +               xprt->sysfs = rpc_xprt;
> +               rpc_xprt->xprt = xprt;
> +               kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD);
> +       }
> +}
> +
> +void rpc_netns_xprt_sysfs_destroy(struct rpc_xprt *xprt)
> +{
> +       struct rpc_netns_xprt *rpc_xprt = xprt->sysfs;
> +
> +       if (rpc_xprt) {
> +               kobject_uevent(&rpc_xprt->kobject, KOBJ_REMOVE);
> +               kobject_del(&rpc_xprt->kobject);
> +               kobject_put(&rpc_xprt->kobject);
> +               xprt->sysfs = NULL;
> +       }
> +}
> diff --git a/net/sunrpc/sysfs.h b/net/sunrpc/sysfs.h
> index ab75c3cc91b6..e08dd7f6a1ec 100644
> --- a/net/sunrpc/sysfs.h
> +++ b/net/sunrpc/sysfs.h
> @@ -11,12 +11,21 @@ struct rpc_netns_client {
>         struct rpc_clnt *clnt;
>  };
>
> +struct rpc_netns_xprt {
> +       struct kobject kobject;
> +       struct net *net;
> +       struct rpc_xprt *xprt;
> +};
> +
>  extern struct kobject *rpc_client_kobj;
> +extern struct kobject *rpc_xprt_kobj;
>
>  extern int rpc_sysfs_init(void);
>  extern void rpc_sysfs_exit(void);
>
>  void rpc_netns_client_sysfs_setup(struct rpc_clnt *clnt, struct net *net);
>  void rpc_netns_client_sysfs_destroy(struct rpc_clnt *clnt);
> +void rpc_netns_xprt_sysfs_setup(struct rpc_xprt *xprt, struct net *net);
> +void rpc_netns_xprt_sysfs_destroy(struct rpc_xprt *xprt);
>
>  #endif
> diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
> index e30acd1f0e31..4098cb6b1453 100644
> --- a/net/sunrpc/xprt.c
> +++ b/net/sunrpc/xprt.c
> @@ -55,6 +55,7 @@
>  #include <trace/events/sunrpc.h>
>
>  #include "sunrpc.h"
> +#include "sysfs.h"
>
>  /*
>   * Local variables
> @@ -1768,6 +1769,7 @@ struct rpc_xprt *xprt_alloc(struct net *net, size_t size,
>                 xprt->max_reqs = num_prealloc;
>         xprt->min_reqs = num_prealloc;
>         xprt->num_reqs = num_prealloc;
> +       rpc_netns_xprt_sysfs_setup(xprt, net);
>
>         return xprt;
>
> @@ -1780,6 +1782,7 @@ EXPORT_SYMBOL_GPL(xprt_alloc);
>
>  void xprt_free(struct rpc_xprt *xprt)
>  {
> +       rpc_netns_xprt_sysfs_destroy(xprt);
>         put_net(xprt->xprt_net);
>         xprt_free_all_slots(xprt);
>         xprt_free_id(xprt);
> --
> 2.26.2
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 1/8] sunrpc: rename 'net' to 'client'
  2021-02-16 21:24   ` Anna Schumaker
@ 2021-02-17 18:58     ` Dan Aloni
  0 siblings, 0 replies; 16+ messages in thread
From: Dan Aloni @ 2021-02-17 18:58 UTC (permalink / raw)
  To: Anna Schumaker; +Cc: Linux NFS Mailing List, Trond Myklebust

On Tue, Feb 16, 2021 at 04:24:41PM -0500, Anna Schumaker wrote:
> Hi Dan,
> 
> On Mon, Feb 15, 2021 at 12:42 PM Dan Aloni <dan@kernelim.com> wrote:
> >
> > This is in preparation to adding a second directory to keep track
> > of each transport.
> 
> I initially named the directory "net" to match how NFS's sysfs
> directories are created (/sys/fs/nfs/net). If naming it "client" makes
> more sense then I should probably introduce it that way in my patches.
> 
> Thoughts?

We can keep the "net" directory under "sunrpc" and have the three
directories under it, i.e:

     /sys/kernel/sunrpc/net/client
     /sys/kernel/sunrpc/net/transport
     /sys/kernel/sunrpc/net/multipath

It works for me too, but I no preference either way.

-- 
Dan Aloni

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 3/8] sunrpc: add a directory per sunrpc xprt
  2021-02-16 21:46   ` Anna Schumaker
@ 2021-02-17 19:01     ` Dan Aloni
  0 siblings, 0 replies; 16+ messages in thread
From: Dan Aloni @ 2021-02-17 19:01 UTC (permalink / raw)
  To: Anna Schumaker; +Cc: Linux NFS Mailing List, Trond Myklebust

On Tue, Feb 16, 2021 at 04:46:55PM -0500, Anna Schumaker wrote:
> > +static ssize_t rpc_netns_xprt_dstaddr_show(struct kobject *kobj,
> > +               struct kobj_attribute *attr, char *buf)
> > +{
> > +       struct rpc_netns_xprt *c = container_of(kobj,
> > +                               struct rpc_netns_xprt, kobject);
> > +       struct rpc_xprt *xprt = c->xprt;
> > +
> > +       if (!(xprt->prot & (IPPROTO_TCP | XPRT_TRANSPORT_RDMA))) {
> 
> We might want to change these restrictions later on, so if we're going
> to put this into each function then maybe it would make sense to have
> a quick inline to check protocol support?

Yeah, I agree.

> I do the same check in the setup function for my patches, so if you
> want I can add the inline function and then it'll just be there for
> you to use.

Sure, go ahead.

> 
> > +               sprintf(buf, "N/A");
> > +               return 0;
> 
> I'm guessing the point of putting "N/A" here is so userspace tools
> don't have to guess which files exist or not for each protocol type?
> Should I change my patches to match this style too?

Yes, though I'm not sure what are the common kernel convention here.
Maybe a "-" string is sufficient?

-- 
Dan Aloni

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 0/8] sysfs files for multipath transport control
  2021-02-15 17:39 [PATCH v1 0/8] sysfs files for multipath transport control Dan Aloni
                   ` (7 preceding siblings ...)
  2021-02-15 17:40 ` [PATCH v1 8/8] sunrpc: introduce an 'add' node to 'multipath' sysfs directory Dan Aloni
@ 2021-03-02  3:56 ` Olga Kornievskaia
  2021-03-04 11:58   ` Dan Aloni
  8 siblings, 1 reply; 16+ messages in thread
From: Olga Kornievskaia @ 2021-03-02  3:56 UTC (permalink / raw)
  To: Dan Aloni; +Cc: linux-nfs, Anna Schumaker, Trond Myklebust

Hi Dan,

On Mon, Feb 15, 2021 at 12:43 PM Dan Aloni <dan@kernelim.com> wrote:
>
> Hi Anna,
>
> This patchset builds ontop v2 of your 'sysfs files for changing IP' changeset.
>
> - The patchset adds two more sysfs objects, for one for transport and another
>   for multipath.
> - Also, `net` renamed to `client`, and `client` now has symlink to its principal
>   transport. A client also has a symlink to its `multipath` object.
> - The transport interface lets you change `dstaddr` of individual transports,
>   when `nconnect` is used (or if it wasn't used and these were added with the
>   new interface).
> - The interface to add a transport is using a single string written to 'add',
>   for example:
>
>        echo 'dstaddr 192.168.40.8 kind rdma' \
>                > /sys/kernel/sunrpc/client/0/multipath/add
>
> These changes are independent of the method used to obtain a sunrpc ID for a
> mountpoint. For that I've sent a concept patch showing an fspick-based
> implementation: https://marc.info/?l=linux-nfs&m=161332454821849&w=4

I'm confused: does this allow adding arbitrary connections between a
client and some server IP to an existing RPC client? Given the above
description, that's how it reads to me, can you clarify please. I
thought it was something specifically for v3 (because it has no
concept of trunking). As for NFSv4 there is a notion of getting server
locations via FS_LOCATION and doing trunking (ie multipathing)? I
don't see how this code restricts the addition of transports to v3.

>
> Thanks
>
> Dan Aloni (8):
>   sunrpc: rename 'net' to 'client'
>   sunrpc: add xprt id
>   sunrpc: add a directory per sunrpc xprt
>   sunrpc: have client directory a symlink to the root transport
>   sunrpc: add IDs to multipath
>   sunrpc: add multipath directory and symlink from client
>   sunrpc: change rpc_clnt_add_xprt() to rpc_add_xprt()
>   sunrpc: introduce an 'add' node to 'multipath' sysfs directory
>
>  fs/nfs/pnfs_nfs.c                    |  12 +-
>  include/linux/sunrpc/clnt.h          |  12 +-
>  include/linux/sunrpc/xprt.h          |   3 +
>  include/linux/sunrpc/xprtmultipath.h |   6 +
>  net/sunrpc/clnt.c                    |  39 +--
>  net/sunrpc/sunrpc_syms.c             |   2 +
>  net/sunrpc/sysfs.c                   | 403 +++++++++++++++++++++++----
>  net/sunrpc/sysfs.h                   |  21 +-
>  net/sunrpc/xprt.c                    |  29 ++
>  net/sunrpc/xprtmultipath.c           |  37 +++
>  10 files changed, 487 insertions(+), 77 deletions(-)
>
> --
> 2.26.2
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 0/8] sysfs files for multipath transport control
  2021-03-02  3:56 ` [PATCH v1 0/8] sysfs files for multipath transport control Olga Kornievskaia
@ 2021-03-04 11:58   ` Dan Aloni
  2021-03-04 18:39     ` Chuck Lever
  0 siblings, 1 reply; 16+ messages in thread
From: Dan Aloni @ 2021-03-04 11:58 UTC (permalink / raw)
  To: Olga Kornievskaia; +Cc: linux-nfs, Anna Schumaker, Trond Myklebust

On Mon, Mar 01, 2021 at 10:56:22PM -0500, Olga Kornievskaia wrote:
> Hi Dan,
> 
> On Mon, Feb 15, 2021 at 12:43 PM Dan Aloni <dan@kernelim.com> wrote:
> >
> > Hi Anna,
> >
> > This patchset builds ontop v2 of your 'sysfs files for changing IP' changeset.
> >
> > - The patchset adds two more sysfs objects, for one for transport and another
> >   for multipath.
> > - Also, `net` renamed to `client`, and `client` now has symlink to its principal
> >   transport. A client also has a symlink to its `multipath` object.
> > - The transport interface lets you change `dstaddr` of individual transports,
> >   when `nconnect` is used (or if it wasn't used and these were added with the
> >   new interface).
> > - The interface to add a transport is using a single string written to 'add',
> >   for example:
> >
> >        echo 'dstaddr 192.168.40.8 kind rdma' \
> >                > /sys/kernel/sunrpc/client/0/multipath/add
> >
> > These changes are independent of the method used to obtain a sunrpc ID for a
> > mountpoint. For that I've sent a concept patch showing an fspick-based
> > implementation: https://marc.info/?l=linux-nfs&m=161332454821849&w=4
> 
> I'm confused: does this allow adding arbitrary connections between a
> client and some server IP to an existing RPC client? Given the above
> description, that's how it reads to me, can you clarify please. I
> thought it was something specifically for v3 (because it has no
> concept of trunking). As for NFSv4 there is a notion of getting server
> locations via FS_LOCATION and doing trunking (ie multipathing)? I
> don't see how this code restricts the addition of transports to v3.

Indeed, there's no restriction to NFSv3.

There can be potential uses for this for NFSv4 too. FS_LOCATIONS serving
as recommendation to which hosts the client can connect, while smart
load-balancing logic in userspace can determine to which subset of these
servers each client in a cluster should actually connect (a full mesh
is not always desired).

At any case, if this restriction is desired, we can add a new sunrpc
client flag for that and pass it only in NFSv3 client init.

-- 
Dan Aloni

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 0/8] sysfs files for multipath transport control
  2021-03-04 11:58   ` Dan Aloni
@ 2021-03-04 18:39     ` Chuck Lever
  0 siblings, 0 replies; 16+ messages in thread
From: Chuck Lever @ 2021-03-04 18:39 UTC (permalink / raw)
  To: Dan Aloni, Olga Kornievskaia
  Cc: Linux NFS Mailing List, Anna Schumaker, Trond Myklebust



> On Mar 4, 2021, at 6:58 AM, Dan Aloni <dan@kernelim.com> wrote:
> 
> On Mon, Mar 01, 2021 at 10:56:22PM -0500, Olga Kornievskaia wrote:
>> Hi Dan,
>> 
>> On Mon, Feb 15, 2021 at 12:43 PM Dan Aloni <dan@kernelim.com> wrote:
>>> 
>>> Hi Anna,
>>> 
>>> This patchset builds ontop v2 of your 'sysfs files for changing IP' changeset.
>>> 
>>> - The patchset adds two more sysfs objects, for one for transport and another
>>>  for multipath.
>>> - Also, `net` renamed to `client`, and `client` now has symlink to its principal
>>>  transport. A client also has a symlink to its `multipath` object.
>>> - The transport interface lets you change `dstaddr` of individual transports,
>>>  when `nconnect` is used (or if it wasn't used and these were added with the
>>>  new interface).
>>> - The interface to add a transport is using a single string written to 'add',
>>>  for example:
>>> 
>>>       echo 'dstaddr 192.168.40.8 kind rdma' \
>>>> /sys/kernel/sunrpc/client/0/multipath/add
>>> 
>>> These changes are independent of the method used to obtain a sunrpc ID for a
>>> mountpoint. For that I've sent a concept patch showing an fspick-based
>>> implementation: https://marc.info/?l=linux-nfs&m=161332454821849&w=4
>> 
>> I'm confused: does this allow adding arbitrary connections between a
>> client and some server IP to an existing RPC client? Given the above
>> description, that's how it reads to me, can you clarify please. I
>> thought it was something specifically for v3 (because it has no
>> concept of trunking). As for NFSv4 there is a notion of getting server
>> locations via FS_LOCATION and doing trunking (ie multipathing)? I
>> don't see how this code restricts the addition of transports to v3.
> 
> Indeed, there's no restriction to NFSv3.
> 
> There can be potential uses for this for NFSv4 too. FS_LOCATIONS serving
> as recommendation to which hosts the client can connect, while smart
> load-balancing logic in userspace can determine to which subset of these
> servers each client in a cluster should actually connect (a full mesh
> is not always desired).
> 
> At any case, if this restriction is desired, we can add a new sunrpc
> client flag for that and pass it only in NFSv3 client init.

IMO an NFSv3-only policy should not be built into this API.

This is a user-space / kernel API, not something that is an administrative
interface. The administrative interface, which is the place to apply an
NFSv3-only policy, would use this sysfs API. So would smart load-
balancing logic based on fs_locations.

If the API is under /sys/kernel/sunrpc/client, then including NFS-specific
controls is a layering violation. Consider that the kernel can send
multiple protocols over the same connection (NFSv3 and NFSACL, eg).


--
Chuck Lever




^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2021-03-04 18:41 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-15 17:39 [PATCH v1 0/8] sysfs files for multipath transport control Dan Aloni
2021-02-15 17:39 ` [PATCH v1 1/8] sunrpc: rename 'net' to 'client' Dan Aloni
2021-02-16 21:24   ` Anna Schumaker
2021-02-17 18:58     ` Dan Aloni
2021-02-15 17:39 ` [PATCH v1 2/8] sunrpc: add xprt id Dan Aloni
2021-02-15 17:39 ` [PATCH v1 3/8] sunrpc: add a directory per sunrpc xprt Dan Aloni
2021-02-16 21:46   ` Anna Schumaker
2021-02-17 19:01     ` Dan Aloni
2021-02-15 17:39 ` [PATCH v1 4/8] sunrpc: have client directory a symlink to the root transport Dan Aloni
2021-02-15 17:39 ` [PATCH v1 5/8] sunrpc: add IDs to multipath Dan Aloni
2021-02-15 17:40 ` [PATCH v1 6/8] sunrpc: add multipath directory and symlink from client Dan Aloni
2021-02-15 17:40 ` [PATCH v1 7/8] sunrpc: change rpc_clnt_add_xprt() to rpc_add_xprt() Dan Aloni
2021-02-15 17:40 ` [PATCH v1 8/8] sunrpc: introduce an 'add' node to 'multipath' sysfs directory Dan Aloni
2021-03-02  3:56 ` [PATCH v1 0/8] sysfs files for multipath transport control Olga Kornievskaia
2021-03-04 11:58   ` Dan Aloni
2021-03-04 18:39     ` Chuck Lever

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.