diff options
author | Sean Hefty <sean.hefty@intel.com> | 2006-10-31 14:12:59 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2006-11-02 17:26:04 -0500 |
commit | 7a118df3ea23820b9922a1b51cd2f24e464f4c17 (patch) | |
tree | 723e979c84263c52971494b7ba69cbee25f602bc | |
parent | 68586b67ab1a2fd618f79e29a06f10ae886f4b46 (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.c | 28 | ||||
-rw-r--r-- | drivers/infiniband/core/cma.c | 8 | ||||
-rw-r--r-- | include/rdma/ib_addr.h | 20 |
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); | |||
61 | static DECLARE_WORK(work, process_req, NULL); | 62 | static DECLARE_WORK(work, process_req, NULL); |
62 | static struct workqueue_struct *addr_wq; | 63 | static struct workqueue_struct *addr_wq; |
63 | 64 | ||
65 | void rdma_addr_register_client(struct rdma_addr_client *client) | ||
66 | { | ||
67 | atomic_set(&client->refcount, 1); | ||
68 | init_completion(&client->comp); | ||
69 | } | ||
70 | EXPORT_SYMBOL(rdma_addr_register_client); | ||
71 | |||
72 | static inline void put_client(struct rdma_addr_client *client) | ||
73 | { | ||
74 | if (atomic_dec_and_test(&client->refcount)) | ||
75 | complete(&client->comp); | ||
76 | } | ||
77 | |||
78 | void rdma_addr_unregister_client(struct rdma_addr_client *client) | ||
79 | { | ||
80 | put_client(client); | ||
81 | wait_for_completion(&client->comp); | ||
82 | } | ||
83 | EXPORT_SYMBOL(rdma_addr_unregister_client); | ||
84 | |||
64 | int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev, | 85 | int 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 | ||
267 | int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr, | 289 | int 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 | ||
65 | static struct ib_sa_client sa_client; | 65 | static struct ib_sa_client sa_client; |
66 | static struct rdma_addr_client addr_client; | ||
66 | static LIST_HEAD(dev_list); | 67 | static LIST_HEAD(dev_list); |
67 | static LIST_HEAD(listen_any_list); | 68 | static LIST_HEAD(listen_any_list); |
68 | static DEFINE_MUTEX(lock); | 69 | static 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 | ||
2226 | err: | 2228 | err: |
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: | |||
2232 | static void cma_cleanup(void) | 2235 | static 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 | ||
39 | struct rdma_addr_client { | ||
40 | atomic_t refcount; | ||
41 | struct completion comp; | ||
42 | }; | ||
43 | |||
44 | /** | ||
45 | * rdma_addr_register_client - Register an address client. | ||
46 | */ | ||
47 | void 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 | */ | ||
53 | void rdma_addr_unregister_client(struct rdma_addr_client *client); | ||
54 | |||
39 | struct rdma_dev_addr { | 55 | struct 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 | */ |
67 | int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr, | 84 | int 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), |