If verndor driver is attempted for removal while xprtrdma still has an
active mount, the removal of driver may never complete and can cause
unseen races or in worst case system crash.

To solve this, xprtrdma module should get reference of struct ib_device
structure for every mount. Reference is taken after local device address
resolution is completed successfuly.

reference to the struct ib_device pointer is put just before cm_id destruction.

Signed-off-by: Devesh Sharma <devesh.sha...@emulex.com>
---
 net/sunrpc/xprtrdma/verbs.c     |   17 +++++++++++++++--
 net/sunrpc/xprtrdma/xprt_rdma.h |    1 +
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
index 6ead5df..b00e55e 100644
--- a/net/sunrpc/xprtrdma/verbs.c
+++ b/net/sunrpc/xprtrdma/verbs.c
@@ -457,6 +457,11 @@ rpcrdma_create_id(struct rpcrdma_xprt *xprt,
        }
        wait_for_completion_interruptible_timeout(&ia->ri_done,
                                msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT) + 1);
+       if (!ia->ri_async_rc && !try_module_get(id->device->owner)) {
+               dprintk("RPC:       %s: Failed to get device module\n",
+                       __func__);
+               ia->ri_async_rc = -ENODEV;
+       }
        rc = ia->ri_async_rc;
        if (rc)
                goto out;
@@ -466,16 +471,18 @@ rpcrdma_create_id(struct rpcrdma_xprt *xprt,
        if (rc) {
                dprintk("RPC:       %s: rdma_resolve_route() failed %i\n",
                        __func__, rc);
-               goto out;
+               goto out_put;
        }
        wait_for_completion_interruptible_timeout(&ia->ri_done,
                                msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT) + 1);
        rc = ia->ri_async_rc;
        if (rc)
-               goto out;
+               goto out_put;
 
        return id;
 
+out_put:
+       module_put(id->device->owner);
 out:
        rdma_destroy_id(id);
        return ERR_PTR(rc);
@@ -613,6 +620,7 @@ rpcrdma_ia_open(struct rpcrdma_xprt *xprt, struct sockaddr 
*addr, int memreg)
        rwlock_init(&ia->ri_qplock);
        return 0;
 out2:
+       module_put(ia->ri_id->device->owner);
        rdma_destroy_id(ia->ri_id);
        ia->ri_id = NULL;
 out1:
@@ -638,9 +646,11 @@ rpcrdma_ia_close(struct rpcrdma_ia *ia)
        if (ia->ri_id != NULL && !IS_ERR(ia->ri_id)) {
                if (ia->ri_id->qp)
                        rdma_destroy_qp(ia->ri_id);
+               module_put(ia->ri_id->device->owner);
                rdma_destroy_id(ia->ri_id);
                ia->ri_id = NULL;
        }
+
        if (ia->ri_pd != NULL && !IS_ERR(ia->ri_pd)) {
                rc = ib_dealloc_pd(ia->ri_pd);
                dprintk("RPC:       %s: ib_dealloc_pd returned %i\n",
@@ -886,6 +896,7 @@ retry:
                if (ia->ri_id->device != id->device) {
                        printk("RPC:       %s: can't reconnect on "
                                "different device!\n", __func__);
+                       module_put(id->device->owner);
                        rdma_destroy_id(id);
                        rc = -ENETUNREACH;
                        goto out;
@@ -895,6 +906,7 @@ retry:
                if (rc) {
                        dprintk("RPC:       %s: rdma_create_qp failed %i\n",
                                __func__, rc);
+                       module_put(id->device->owner);
                        rdma_destroy_id(id);
                        rc = -ENETUNREACH;
                        goto out;
@@ -906,6 +918,7 @@ retry:
                write_unlock(&ia->ri_qplock);
 
                rdma_destroy_qp(old);
+               module_put(old->device->owner);
                rdma_destroy_id(old);
        } else {
                dprintk("RPC:       %s: connecting...\n", __func__);
diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h
index c419498..b35fa21 100644
--- a/net/sunrpc/xprtrdma/xprt_rdma.h
+++ b/net/sunrpc/xprtrdma/xprt_rdma.h
@@ -44,6 +44,7 @@
 #include <linux/spinlock.h>            /* spinlock_t, etc */
 #include <linux/atomic.h>                      /* atomic_t, etc */
 #include <linux/workqueue.h>           /* struct work_struct */
+#include <linux/module.h>              /* try_module_get()/module_put() */
 
 #include <rdma/rdma_cm.h>              /* RDMA connection api */
 #include <rdma/ib_verbs.h>             /* RDMA verbs api */
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to