mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-25 05:04:09 +08:00
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>
This commit is contained in:
parent
68586b67ab
commit
7a118df3ea
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -36,6 +36,22 @@
|
||||
#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),
|
||||
|
Loading…
Reference in New Issue
Block a user