Commit 7a118df3 authored by Sean Hefty's avatar Sean Hefty Committed by Roland Dreier

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: default avatarSean Hefty <sean.hefty@intel.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent 68586b67
...@@ -47,6 +47,7 @@ struct addr_req { ...@@ -47,6 +47,7 @@ struct addr_req {
struct sockaddr src_addr; struct sockaddr src_addr;
struct sockaddr dst_addr; struct sockaddr dst_addr;
struct rdma_dev_addr *addr; struct rdma_dev_addr *addr;
struct rdma_addr_client *client;
void *context; void *context;
void (*callback)(int status, struct sockaddr *src_addr, void (*callback)(int status, struct sockaddr *src_addr,
struct rdma_dev_addr *addr, void *context); struct rdma_dev_addr *addr, void *context);
...@@ -61,6 +62,26 @@ static LIST_HEAD(req_list); ...@@ -61,6 +62,26 @@ static LIST_HEAD(req_list);
static DECLARE_WORK(work, process_req, NULL); static DECLARE_WORK(work, process_req, NULL);
static struct workqueue_struct *addr_wq; 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, int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
const unsigned char *dst_dev_addr) const unsigned char *dst_dev_addr)
{ {
...@@ -229,6 +250,7 @@ static void process_req(void *data) ...@@ -229,6 +250,7 @@ static void process_req(void *data)
list_del(&req->list); list_del(&req->list);
req->callback(req->status, &req->src_addr, req->addr, req->callback(req->status, &req->src_addr, req->addr,
req->context); req->context);
put_client(req->client);
kfree(req); kfree(req);
} }
} }
...@@ -264,7 +286,8 @@ static int addr_resolve_local(struct sockaddr_in *src_in, ...@@ -264,7 +286,8 @@ static int addr_resolve_local(struct sockaddr_in *src_in,
return ret; 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, struct rdma_dev_addr *addr, int timeout_ms,
void (*callback)(int status, struct sockaddr *src_addr, void (*callback)(int status, struct sockaddr *src_addr,
struct rdma_dev_addr *addr, void *context), struct rdma_dev_addr *addr, void *context),
...@@ -285,6 +308,8 @@ int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr, ...@@ -285,6 +308,8 @@ int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr,
req->addr = addr; req->addr = addr;
req->callback = callback; req->callback = callback;
req->context = context; req->context = context;
req->client = client;
atomic_inc(&client->refcount);
src_in = (struct sockaddr_in *) &req->src_addr; src_in = (struct sockaddr_in *) &req->src_addr;
dst_in = (struct sockaddr_in *) &req->dst_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, ...@@ -305,6 +330,7 @@ int rdma_resolve_ip(struct sockaddr *src_addr, struct sockaddr *dst_addr,
break; break;
default: default:
ret = req->status; ret = req->status;
atomic_dec(&client->refcount);
kfree(req); kfree(req);
break; break;
} }
......
...@@ -63,6 +63,7 @@ static struct ib_client cma_client = { ...@@ -63,6 +63,7 @@ static struct ib_client cma_client = {
}; };
static struct ib_sa_client sa_client; static struct ib_sa_client sa_client;
static struct rdma_addr_client addr_client;
static LIST_HEAD(dev_list); static LIST_HEAD(dev_list);
static LIST_HEAD(listen_any_list); static LIST_HEAD(listen_any_list);
static DEFINE_MUTEX(lock); static DEFINE_MUTEX(lock);
...@@ -1625,8 +1626,8 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, ...@@ -1625,8 +1626,8 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
if (cma_any_addr(dst_addr)) if (cma_any_addr(dst_addr))
ret = cma_resolve_loopback(id_priv); ret = cma_resolve_loopback(id_priv);
else else
ret = rdma_resolve_ip(&id->route.addr.src_addr, dst_addr, ret = rdma_resolve_ip(&addr_client, &id->route.addr.src_addr,
&id->route.addr.dev_addr, dst_addr, &id->route.addr.dev_addr,
timeout_ms, addr_handler, id_priv); timeout_ms, addr_handler, id_priv);
if (ret) if (ret)
goto err; goto err;
...@@ -2217,6 +2218,7 @@ static int cma_init(void) ...@@ -2217,6 +2218,7 @@ static int cma_init(void)
return -ENOMEM; return -ENOMEM;
ib_sa_register_client(&sa_client); ib_sa_register_client(&sa_client);
rdma_addr_register_client(&addr_client);
ret = ib_register_client(&cma_client); ret = ib_register_client(&cma_client);
if (ret) if (ret)
...@@ -2224,6 +2226,7 @@ static int cma_init(void) ...@@ -2224,6 +2226,7 @@ static int cma_init(void)
return 0; return 0;
err: err:
rdma_addr_unregister_client(&addr_client);
ib_sa_unregister_client(&sa_client); ib_sa_unregister_client(&sa_client);
destroy_workqueue(cma_wq); destroy_workqueue(cma_wq);
return ret; return ret;
...@@ -2232,6 +2235,7 @@ err: ...@@ -2232,6 +2235,7 @@ err:
static void cma_cleanup(void) static void cma_cleanup(void)
{ {
ib_unregister_client(&cma_client); ib_unregister_client(&cma_client);
rdma_addr_unregister_client(&addr_client);
ib_sa_unregister_client(&sa_client); ib_sa_unregister_client(&sa_client);
destroy_workqueue(cma_wq); destroy_workqueue(cma_wq);
idr_destroy(&sdp_ps); idr_destroy(&sdp_ps);
......
...@@ -36,6 +36,22 @@ ...@@ -36,6 +36,22 @@
#include <linux/socket.h> #include <linux/socket.h>
#include <rdma/ib_verbs.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 { struct rdma_dev_addr {
unsigned char src_dev_addr[MAX_ADDR_LEN]; unsigned char src_dev_addr[MAX_ADDR_LEN];
unsigned char dst_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); ...@@ -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_resolve_ip - Resolve source and destination IP addresses to
* RDMA hardware addresses. * RDMA hardware addresses.
* @client: Address client associated with request.
* @src_addr: An optional source address to use in the resolution. If a * @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 * source address is not provided, a usable address will be returned via
* the callback. * the callback.
...@@ -64,7 +81,8 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr); ...@@ -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. * or been canceled. A status of 0 indicates success.
* @context: User-specified context associated with the call. * @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, struct rdma_dev_addr *addr, int timeout_ms,
void (*callback)(int status, struct sockaddr *src_addr, void (*callback)(int status, struct sockaddr *src_addr,
struct rdma_dev_addr *addr, void *context), struct rdma_dev_addr *addr, void *context),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment