Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+27 −1
Original line number Diff line number Diff line
@@ -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;
	}
+6 −2
Original line number Diff line number Diff line
@@ -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);
+19 −1
Original line number Diff line number Diff line
@@ -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),