SUNRPC: Close a race with transport setup and module put
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Tue, 10 Nov 2020 17:58:22 +0000 (12:58 -0500)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 2 Dec 2020 19:05:52 +0000 (14:05 -0500)
After we've looked up the transport module, we need to ensure it can't
go away until we've finished running the transport setup code.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
net/sunrpc/xprt.c

index 57f09ea3ef2af761e726579c6e7a1a70693f9b48..bf490d0c98c6a62a2da2e59a9c812c9c85fff23b 100644 (file)
@@ -157,6 +157,32 @@ xprt_class_release(const struct xprt_class *t)
        module_put(t->owner);
 }
 
+static const struct xprt_class *
+xprt_class_find_by_ident_locked(int ident)
+{
+       const struct xprt_class *t;
+
+       list_for_each_entry(t, &xprt_list, list) {
+               if (t->ident != ident)
+                       continue;
+               if (!try_module_get(t->owner))
+                       continue;
+               return t;
+       }
+       return NULL;
+}
+
+static const struct xprt_class *
+xprt_class_find_by_ident(int ident)
+{
+       const struct xprt_class *t;
+
+       spin_lock(&xprt_list_lock);
+       t = xprt_class_find_by_ident_locked(ident);
+       spin_unlock(&xprt_list_lock);
+       return t;
+}
+
 static const struct xprt_class *
 xprt_class_find_by_netid_locked(const char *netid)
 {
@@ -1929,21 +1955,17 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net)
 struct rpc_xprt *xprt_create_transport(struct xprt_create *args)
 {
        struct rpc_xprt *xprt;
-       struct xprt_class *t;
+       const struct xprt_class *t;
 
-       spin_lock(&xprt_list_lock);
-       list_for_each_entry(t, &xprt_list, list) {
-               if (t->ident == args->ident) {
-                       spin_unlock(&xprt_list_lock);
-                       goto found;
-               }
+       t = xprt_class_find_by_ident(args->ident);
+       if (!t) {
+               dprintk("RPC: transport (%d) not supported\n", args->ident);
+               return ERR_PTR(-EIO);
        }
-       spin_unlock(&xprt_list_lock);
-       dprintk("RPC: transport (%d) not supported\n", args->ident);
-       return ERR_PTR(-EIO);
 
-found:
        xprt = t->setup(args);
+       xprt_class_release(t);
+
        if (IS_ERR(xprt))
                goto out;
        if (args->flags & XPRT_CREATE_NO_IDLE_TIMEOUT)