aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Hefty <sean.hefty@intel.com>2006-10-31 14:12:59 -0500
committerRoland Dreier <rolandd@cisco.com>2006-11-02 17:26:04 -0500
commit7a118df3ea23820b9922a1b51cd2f24e464f4c17 (patch)
tree723e979c84263c52971494b7ba69cbee25f602bc
parent68586b67ab1a2fd618f79e29a06f10ae886f4b46 (diff)
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>
-rw-r--r--drivers/infiniband/core/addr.c28
-rw-r--r--drivers/infiniband/core/cma.c8
-rw-r--r--include/rdma/ib_addr.h20
3 files changed, 52 insertions, 4 deletions
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 60d3fbdd216c..e11187ecc931 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -47,6 +47,7 @@ struct addr_req {
47 struct sockaddr src_addr; 47 struct sockaddr src_addr;
48 struct sockaddr dst_addr; 48 struct sockaddr dst_addr;
49 struct rdma_dev_addr *addr; 49 struct rdma_dev_addr *addr;
50 struct rdma_addr_client *client;
50 void *context; 51 void *context;
51 void (*callback)(int status, struct sockaddr *src_addr, 52 void (*callback)(int status, struct sockaddr *src_addr,
52 struct rdma_dev_addr *addr, void *context); 53 struct rdma_dev_addr *addr, void *context);
@@ -61,6 +62,26 @@ static LIST_HEAD(req_list);
61static DECLARE_WORK(work, process_req, NULL); 62static DECLARE_WORK(work, process_req, NULL);
62static struct workqueue_struct *addr_wq; 63static struct workqueue_struct *addr_wq;
63 64
65void rdma_addr_register_client(struct rdma_addr_client *client)
66{
67 atomic_set(&client->refcount, 1);
68 init_completion(&client->comp);
69}
70EXPORT_SYMBOL(rdma_addr_register_client);
71
72static inline void put_client(struct rdma_addr_client *client)
73{
74 if (atomic_dec_and_test(&client->refcount))
75 complete(&client->comp);
76}
77
78void rdma_addr_unregister_client(struct rdma_addr_client *client)
79{
80 put_client(client);
81 wait_for_completion(&client->comp);
82}
83EXPORT_SYMBOL(rdma_addr_unregister_client);
84
64int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev, 85int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
65 const unsigned char *dst_dev_addr) 86 const unsigned char *dst_dev_addr)
66{ 87{
@@ -229,6 +250,7 @@ static void process_req(void *data)
229 list_del(&req->list); 250 list_del(&req->list);
230 req->callback(req->status, &req->src_addr, req->addr, 251 req->callback(req->status, &req->src_addr, req->addr,
231 req->context); 252 req->context);
253 put_client(req->client);
232 kfree(req); 254 kfree(req);
233 } 255 }
234} 256}
@@ -264,7 +286,8 @@ static int addr_resolve_local(struct sockaddr_in *src_in,
264 return ret; 286 return ret;
265} 287}
266 288
267int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr, 289int rdma_resolve_ip(struct rdma_addr_client *client,
290 struct sockaddr *src_addr, struct sockaddr *dst_addr,
268 struct rdma_dev_addr *addr, int timeout_ms, 291 struct rdma_dev_addr *addr, int timeout_ms,
269 void (*callback)(int status, struct sockaddr *src_addr, 292 void (*callback)(int status, struct sockaddr *src_addr,
270 struct rdma_dev_addr *addr, void *context), 293 struct rdma_dev_addr *addr, void *context),
@@ -285,6 +308,8 @@ int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr,
285 req->addr = addr; 308 req->addr = addr;
286 req->callback = callback; 309 req->callback = callback;
287 req->context = context; 310 req->context = context;
311 req->client = client;
312 atomic_inc(&client->refcount);
288 313
289 src_in = (struct sockaddr_in *) &req->src_addr; 314 src_in = (struct sockaddr_in *) &req->src_addr;
290 dst_in = (struct sockaddr_in *) &req->dst_addr; 315 dst_in = (struct sockaddr_in *) &req->dst_addr;
@@ -305,6 +330,7 @@ int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr,
305 break; 330 break;
306 default: 331 default:
307 ret = req->status; 332 ret = req->status;
333 atomic_dec(&client->refcount);
308 kfree(req); 334 kfree(req);
309 break; 335 break;
310 } 336 }
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index d8ca3c1368b5..845090b0859c 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -63,6 +63,7 @@ static struct ib_client cma_client = {
63}; 63};
64 64
65static struct ib_sa_client sa_client; 65static struct ib_sa_client sa_client;
66static struct rdma_addr_client addr_client;
66static LIST_HEAD(dev_list); 67static LIST_HEAD(dev_list);
67static LIST_HEAD(listen_any_list); 68static LIST_HEAD(listen_any_list);
68static DEFINE_MUTEX(lock); 69static DEFINE_MUTEX(lock);
@@ -1625,8 +1626,8 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
1625 if (cma_any_addr(dst_addr)) 1626 if (cma_any_addr(dst_addr))
1626 ret = cma_resolve_loopback(id_priv); 1627 ret = cma_resolve_loopback(id_priv);
1627 else 1628 else
1628 ret = rdma_resolve_ip(&id->route.addr.src_addr, dst_addr, 1629 ret = rdma_resolve_ip(&addr_client, &id->route.addr.src_addr,
1629 &id->route.addr.dev_addr, 1630 dst_addr, &id->route.addr.dev_addr,
1630 timeout_ms, addr_handler, id_priv); 1631 timeout_ms, addr_handler, id_priv);
1631 if (ret) 1632 if (ret)
1632 goto err; 1633 goto err;
@@ -2217,6 +2218,7 @@ static int cma_init(void)
2217 return -ENOMEM; 2218 return -ENOMEM;
2218 2219
2219 ib_sa_register_client(&sa_client); 2220 ib_sa_register_client(&sa_client);
2221 rdma_addr_register_client(&addr_client);
2220 2222
2221 ret = ib_register_client(&cma_client); 2223 ret = ib_register_client(&cma_client);
2222 if (ret) 2224 if (ret)
@@ -2224,6 +2226,7 @@ static int cma_init(void)
2224 return 0; 2226 return 0;
2225 2227
2226err: 2228err:
2229 rdma_addr_unregister_client(&addr_client);
2227 ib_sa_unregister_client(&sa_client); 2230 ib_sa_unregister_client(&sa_client);
2228 destroy_workqueue(cma_wq); 2231 destroy_workqueue(cma_wq);
2229 return ret; 2232 return ret;
@@ -2232,6 +2235,7 @@ err:
2232static void cma_cleanup(void) 2235static void cma_cleanup(void)
2233{ 2236{
2234 ib_unregister_client(&cma_client); 2237 ib_unregister_client(&cma_client);
2238 rdma_addr_unregister_client(&addr_client);
2235 ib_sa_unregister_client(&sa_client); 2239 ib_sa_unregister_client(&sa_client);
2236 destroy_workqueue(cma_wq); 2240 destroy_workqueue(cma_wq);
2237 idr_destroy(&sdp_ps); 2241 idr_destroy(&sdp_ps);
diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h
index 81b62307621d..c094e5012862 100644
--- a/include/rdma/ib_addr.h
+++ b/include/rdma/ib_addr.h
@@ -36,6 +36,22 @@
36#include <linux/socket.h> 36#include <linux/socket.h>
37#include <rdma/ib_verbs.h> 37#include <rdma/ib_verbs.h>
38 38
39struct rdma_addr_client {
40 atomic_t refcount;
41 struct completion comp;
42};
43
44/**
45 * rdma_addr_register_client - Register an address client.
46 */
47void rdma_addr_register_client(struct rdma_addr_client *client);
48
49/**
50 * rdma_addr_unregister_client - Deregister an address client.
51 * @client: Client object to deregister.
52 */
53void rdma_addr_unregister_client(struct rdma_addr_client *client);
54
39struct rdma_dev_addr { 55struct rdma_dev_addr {
40 unsigned char src_dev_addr[MAX_ADDR_LEN]; 56 unsigned char src_dev_addr[MAX_ADDR_LEN];
41 unsigned char dst_dev_addr[MAX_ADDR_LEN]; 57 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);
52/** 68/**
53 * rdma_resolve_ip - Resolve source and destination IP addresses to 69 * rdma_resolve_ip - Resolve source and destination IP addresses to
54 * RDMA hardware addresses. 70 * RDMA hardware addresses.
71 * @client: Address client associated with request.
55 * @src_addr: An optional source address to use in the resolution. If a 72 * @src_addr: An optional source address to use in the resolution. If a
56 * source address is not provided, a usable address will be returned via 73 * source address is not provided, a usable address will be returned via
57 * the callback. 74 * the callback.
@@ -64,7 +81,8 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr);
64 * or been canceled. A status of 0 indicates success. 81 * or been canceled. A status of 0 indicates success.
65 * @context: User-specified context associated with the call. 82 * @context: User-specified context associated with the call.
66 */ 83 */
67int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr, 84int rdma_resolve_ip(struct rdma_addr_client *client,
85 struct sockaddr *src_addr, struct sockaddr *dst_addr,
68 struct rdma_dev_addr *addr, int timeout_ms, 86 struct rdma_dev_addr *addr, int timeout_ms,
69 void (*callback)(int status, struct sockaddr *src_addr, 87 void (*callback)(int status, struct sockaddr *src_addr,
70 struct rdma_dev_addr *addr, void *context), 88 struct rdma_dev_addr *addr, void *context),