From: Trond Myklebust <trond.mykleb...@hammerspace.com>

[ Upstream commit d5aa6b22e2258f05317313ecc02efbb988ed6d38 ]

According to RFC5666, the correct netid for an IPv6 addressed RDMA
transport is "rdma6", which we've supported as a mount option since
Linux-4.7. The problem is when we try to load the module "xprtrdma6",
that will fail, since there is no modulealias of that name.

Fixes: 181342c5ebe8 ("xprtrdma: Add rdma6 option to support NFS/RDMA IPv6")
Signed-off-by: Trond Myklebust <trond.mykleb...@hammerspace.com>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 include/linux/sunrpc/xprt.h     |  1 +
 net/sunrpc/xprt.c               | 65 +++++++++++++++++++++++++--------
 net/sunrpc/xprtrdma/module.c    |  1 +
 net/sunrpc/xprtrdma/transport.c |  1 +
 net/sunrpc/xprtsock.c           |  4 ++
 5 files changed, 56 insertions(+), 16 deletions(-)

diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index 7fad83881ce19..9785715eea145 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -316,6 +316,7 @@ struct xprt_class {
        struct rpc_xprt *       (*setup)(struct xprt_create *);
        struct module           *owner;
        char                    name[32];
+       const char *            netid[];
 };
 
 /*
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index b852c34bb6373..7b1213be3e81a 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -143,31 +143,64 @@ out:
 }
 EXPORT_SYMBOL_GPL(xprt_unregister_transport);
 
+static void
+xprt_class_release(const struct xprt_class *t)
+{
+       module_put(t->owner);
+}
+
+static const struct xprt_class *
+xprt_class_find_by_netid_locked(const char *netid)
+{
+       const struct xprt_class *t;
+       unsigned int i;
+
+       list_for_each_entry(t, &xprt_list, list) {
+               for (i = 0; t->netid[i][0] != '\0'; i++) {
+                       if (strcmp(t->netid[i], netid) != 0)
+                               continue;
+                       if (!try_module_get(t->owner))
+                               continue;
+                       return t;
+               }
+       }
+       return NULL;
+}
+
+static const struct xprt_class *
+xprt_class_find_by_netid(const char *netid)
+{
+       const struct xprt_class *t;
+
+       spin_lock(&xprt_list_lock);
+       t = xprt_class_find_by_netid_locked(netid);
+       if (!t) {
+               spin_unlock(&xprt_list_lock);
+               request_module("rpc%s", netid);
+               spin_lock(&xprt_list_lock);
+               t = xprt_class_find_by_netid_locked(netid);
+       }
+       spin_unlock(&xprt_list_lock);
+       return t;
+}
+
 /**
  * xprt_load_transport - load a transport implementation
- * @transport_name: transport to load
+ * @netid: transport to load
  *
  * Returns:
  * 0:          transport successfully loaded
  * -ENOENT:    transport module not available
  */
-int xprt_load_transport(const char *transport_name)
+int xprt_load_transport(const char *netid)
 {
-       struct xprt_class *t;
-       int result;
+       const struct xprt_class *t;
 
-       result = 0;
-       spin_lock(&xprt_list_lock);
-       list_for_each_entry(t, &xprt_list, list) {
-               if (strcmp(t->name, transport_name) == 0) {
-                       spin_unlock(&xprt_list_lock);
-                       goto out;
-               }
-       }
-       spin_unlock(&xprt_list_lock);
-       result = request_module("xprt%s", transport_name);
-out:
-       return result;
+       t = xprt_class_find_by_netid(netid);
+       if (!t)
+               return -ENOENT;
+       xprt_class_release(t);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(xprt_load_transport);
 
diff --git a/net/sunrpc/xprtrdma/module.c b/net/sunrpc/xprtrdma/module.c
index 560712bd9fa2c..dd227de31a589 100644
--- a/net/sunrpc/xprtrdma/module.c
+++ b/net/sunrpc/xprtrdma/module.c
@@ -19,6 +19,7 @@ MODULE_DESCRIPTION("RPC/RDMA Transport");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_ALIAS("svcrdma");
 MODULE_ALIAS("xprtrdma");
+MODULE_ALIAS("rpcrdma6");
 
 static void __exit rpc_rdma_cleanup(void)
 {
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c
index b1b40a1be8c57..ead20e6754ab7 100644
--- a/net/sunrpc/xprtrdma/transport.c
+++ b/net/sunrpc/xprtrdma/transport.c
@@ -849,6 +849,7 @@ static struct xprt_class xprt_rdma = {
        .owner                  = THIS_MODULE,
        .ident                  = XPRT_TRANSPORT_RDMA,
        .setup                  = xprt_setup_rdma,
+       .netid                  = { "rdma", "rdma6", "" },
 };
 
 void xprt_rdma_cleanup(void)
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index f75b5b7c1fc2a..5124a21ecfa39 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -3208,6 +3208,7 @@ static struct xprt_class  xs_local_transport = {
        .owner          = THIS_MODULE,
        .ident          = XPRT_TRANSPORT_LOCAL,
        .setup          = xs_setup_local,
+       .netid          = { "" },
 };
 
 static struct xprt_class       xs_udp_transport = {
@@ -3216,6 +3217,7 @@ static struct xprt_class  xs_udp_transport = {
        .owner          = THIS_MODULE,
        .ident          = XPRT_TRANSPORT_UDP,
        .setup          = xs_setup_udp,
+       .netid          = { "udp", "udp6", "" },
 };
 
 static struct xprt_class       xs_tcp_transport = {
@@ -3224,6 +3226,7 @@ static struct xprt_class  xs_tcp_transport = {
        .owner          = THIS_MODULE,
        .ident          = XPRT_TRANSPORT_TCP,
        .setup          = xs_setup_tcp,
+       .netid          = { "tcp", "tcp6", "" },
 };
 
 static struct xprt_class       xs_bc_tcp_transport = {
@@ -3232,6 +3235,7 @@ static struct xprt_class  xs_bc_tcp_transport = {
        .owner          = THIS_MODULE,
        .ident          = XPRT_TRANSPORT_BC_TCP,
        .setup          = xs_setup_bc_tcp,
+       .netid          = { "" },
 };
 
 /**
-- 
2.27.0



Reply via email to