RDMA/addr: Use client registration to fix module unload race
authorSean Hefty <sean.hefty@intel.com>
Tue, 31 Oct 2006 19:12:59 +0000 (11:12 -0800)
committerRoland Dreier <rolandd@cisco.com>
Thu, 2 Nov 2006 22:26:04 +0000 (14:26 -0800)
Require registration with ib_addr module to prevent caller from
unloading while a callback is in progress.

Signed-off-by: Sean Hefty <sean.hefty@intel.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/infiniband/core/addr.c
drivers/infiniband/core/cma.c
include/rdma/ib_addr.h

index 60d3fbd..e11187e 100644 (file)
@@ -47,6 +47,7 @@ struct addr_req {
        struct sockaddr src_addr;
        struct sockaddr dst_addr;
        struct rdma_dev_addr *addr;
+       struct rdma_addr_client *client;
        void *context;
        void (*callback)(int status, struct sockaddr *src_addr,
                         struct rdma_dev_addr *addr, void *context);
@@ -61,6 +62,26 @@ static LIST_HEAD(req_list);
 static DECLARE_WORK(work, process_req, NULL);
 static struct workqueue_struct *addr_wq;
 
+void rdma_addr_register_client(struct rdma_addr_client *client)
+{
+       atomic_set(&client->refcount, 1);
+       init_completion(&client->comp);
+}
+EXPORT_SYMBOL(rdma_addr_register_client);
+
+static inline void put_client(struct rdma_addr_client *client)
+{
+       if (atomic_dec_and_test(&client->refcount))
+               complete(&client->comp);
+}
+
+void rdma_addr_unregister_client(struct rdma_addr_client *client)
+{
+       put_client(client);
+       wait_for_completion(&client->comp);
+}
+EXPORT_SYMBOL(rdma_addr_unregister_client);
+
 int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
                     const unsigned char *dst_dev_addr)
 {
@@ -229,6 +250,7 @@ static void process_req(void *data)
                list_del(&req->list);
                req->callback(req->status, &req->src_addr, req->addr,
                              req->context);
+               put_client(req->client);
                kfree(req);
        }
 }
@@ -264,7 +286,8 @@ static int addr_resolve_local(struct sockaddr_in *src_in,
        return ret;
 }
 
-int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr,
+int rdma_resolve_ip(struct rdma_addr_client *client,
+                   struct sockaddr *src_addr, struct sockaddr *dst_addr,
                    struct rdma_dev_addr *addr, int timeout_ms,
                    void (*callback)(int status, struct sockaddr *src_addr,
                                     struct rdma_dev_addr *addr, void *context),
@@ -285,6 +308,8 @@ int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr,
        req->addr = addr;
        req->callback = callback;
        req->context = context;
+       req->client = client;
+       atomic_inc(&client->refcount);
 
        src_in = (struct sockaddr_in *) &req->src_addr;
        dst_in = (struct sockaddr_in *) &req->dst_addr;
@@ -305,6 +330,7 @@ int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr,
                break;
        default:
                ret = req->status;
+               atomic_dec(&client->refcount);
                kfree(req);
                break;
        }
index d8ca3c1..845090b 100644 (file)
@@ -63,6 +63,7 @@ static struct ib_client cma_client = {
 };
 
 static struct ib_sa_client sa_client;
+static struct rdma_addr_client addr_client;
 static LIST_HEAD(dev_list);
 static LIST_HEAD(listen_any_list);
 static DEFINE_MUTEX(lock);
@@ -1625,8 +1626,8 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
        if (cma_any_addr(dst_addr))
                ret = cma_resolve_loopback(id_priv);
        else
-               ret = rdma_resolve_ip(&id->route.addr.src_addr, dst_addr,
-                                     &id->route.addr.dev_addr,
+               ret = rdma_resolve_ip(&addr_client, &id->route.addr.src_addr,
+                                     dst_addr, &id->route.addr.dev_addr,
                                      timeout_ms, addr_handler, id_priv);
        if (ret)
                goto err;
@@ -2217,6 +2218,7 @@ static int cma_init(void)
                return -ENOMEM;
 
        ib_sa_register_client(&sa_client);
+       rdma_addr_register_client(&addr_client);
 
        ret = ib_register_client(&cma_client);
        if (ret)
@@ -2224,6 +2226,7 @@ static int cma_init(void)
        return 0;
 
 err:
+       rdma_addr_unregister_client(&addr_client);
        ib_sa_unregister_client(&sa_client);
        destroy_workqueue(cma_wq);
        return ret;
@@ -2232,6 +2235,7 @@ err:
 static void cma_cleanup(void)
 {
        ib_unregister_client(&cma_client);
+       rdma_addr_unregister_client(&addr_client);
        ib_sa_unregister_client(&sa_client);
        destroy_workqueue(cma_wq);
        idr_destroy(&sdp_ps);
index 81b6230..c094e50 100644 (file)
 #include <linux/socket.h>
 #include <rdma/ib_verbs.h>
 
+struct rdma_addr_client {
+       atomic_t refcount;
+       struct completion comp;
+};
+
+/**
+ * rdma_addr_register_client - Register an address client.
+ */
+void rdma_addr_register_client(struct rdma_addr_client *client);
+
+/**
+ * rdma_addr_unregister_client - Deregister an address client.
+ * @client: Client object to deregister.
+ */
+void rdma_addr_unregister_client(struct rdma_addr_client *client);
+
 struct rdma_dev_addr {
        unsigned char src_dev_addr[MAX_ADDR_LEN];
        unsigned char dst_dev_addr[MAX_ADDR_LEN];
@@ -52,6 +68,7 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr);
 /**
  * rdma_resolve_ip - Resolve source and destination IP addresses to
  *   RDMA hardware addresses.
+ * @client: Address client associated with request.
  * @src_addr: An optional source address to use in the resolution.  If a
  *   source address is not provided, a usable address will be returned via
  *   the callback.
@@ -64,7 +81,8 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr);
  *   or been canceled.  A status of 0 indicates success.
  * @context: User-specified context associated with the call.
  */
-int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr,
+int rdma_resolve_ip(struct rdma_addr_client *client,
+                   struct sockaddr *src_addr, struct sockaddr *dst_addr,
                    struct rdma_dev_addr *addr, int timeout_ms,
                    void (*callback)(int status, struct sockaddr *src_addr,
                                     struct rdma_dev_addr *addr, void *context),