summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorSean Hefty <sean.hefty@intel.com>2006-10-31 19:12:59 (GMT)
committerRoland Dreier <rolandd@cisco.com>2006-11-02 22:26:04 (GMT)
commit7a118df3ea23820b9922a1b51cd2f24e464f4c17 (patch)
tree723e979c84263c52971494b7ba69cbee25f602bc /drivers
parent68586b67ab1a2fd618f79e29a06f10ae886f4b46 (diff)
downloadlinux-7a118df3ea23820b9922a1b51cd2f24e464f4c17.tar.xz
RDMA/addr: Use client registration to fix module unload race
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/infiniband/core/addr.c28
-rw-r--r--drivers/infiniband/core/cma.c8
2 files changed, 33 insertions, 3 deletions
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 60d3fbd..e11187e 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -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;
}
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index d8ca3c1..845090b 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -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);