Commit 732d41c5 authored by Jason Gunthorpe's avatar Jason Gunthorpe

RDMA/cma: Make the locking for automatic state transition more clear

Re-organize things so the state variable is not read unlocked. The first
attempt to go directly from ADDR_BOUND immediately tells us if the ID is
already bound, if we can't do that then the attempt inside
rdma_bind_addr() to go from IDLE to ADDR_BOUND confirms the ID needs
binding.

Link: https://lore.kernel.org/r/20200902081122.745412-3-leon@kernel.orgSigned-off-by: default avatarLeon Romanovsky <leonro@nvidia.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent 2a7cec53
...@@ -3248,32 +3248,54 @@ static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, ...@@ -3248,32 +3248,54 @@ static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
return rdma_bind_addr(id, src_addr); return rdma_bind_addr(id, src_addr);
} }
int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, /*
const struct sockaddr *dst_addr, unsigned long timeout_ms) * If required, resolve the source address for bind and leave the id_priv in
* state RDMA_CM_ADDR_BOUND. This oddly uses the state to determine the prior
* calls made by ULP, a previously bound ID will not be re-bound and src_addr is
* ignored.
*/
static int resolve_prepare_src(struct rdma_id_private *id_priv,
struct sockaddr *src_addr,
const struct sockaddr *dst_addr)
{ {
struct rdma_id_private *id_priv;
int ret; int ret;
id_priv = container_of(id, struct rdma_id_private, id);
memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr)); memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr));
if (id_priv->state == RDMA_CM_IDLE) { if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY)) {
ret = cma_bind_addr(id, src_addr, dst_addr); /* For a well behaved ULP state will be RDMA_CM_IDLE */
if (ret) { ret = cma_bind_addr(&id_priv->id, src_addr, dst_addr);
memset(cma_dst_addr(id_priv), 0, if (ret)
rdma_addr_size(dst_addr)); goto err_dst;
return ret; if (WARN_ON(!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND,
RDMA_CM_ADDR_QUERY))) {
ret = -EINVAL;
goto err_dst;
} }
} }
if (cma_family(id_priv) != dst_addr->sa_family) { if (cma_family(id_priv) != dst_addr->sa_family) {
memset(cma_dst_addr(id_priv), 0, rdma_addr_size(dst_addr)); ret = -EINVAL;
return -EINVAL; goto err_state;
} }
return 0;
if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY)) { err_state:
memset(cma_dst_addr(id_priv), 0, rdma_addr_size(dst_addr)); cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND);
return -EINVAL; err_dst:
} memset(cma_dst_addr(id_priv), 0, rdma_addr_size(dst_addr));
return ret;
}
int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
const struct sockaddr *dst_addr, unsigned long timeout_ms)
{
struct rdma_id_private *id_priv =
container_of(id, struct rdma_id_private, id);
int ret;
ret = resolve_prepare_src(id_priv, src_addr, dst_addr);
if (ret)
return ret;
if (cma_any_addr(dst_addr)) { if (cma_any_addr(dst_addr)) {
ret = cma_resolve_loopback(id_priv); ret = cma_resolve_loopback(id_priv);
...@@ -3646,20 +3668,21 @@ static int cma_check_linklocal(struct rdma_dev_addr *dev_addr, ...@@ -3646,20 +3668,21 @@ static int cma_check_linklocal(struct rdma_dev_addr *dev_addr,
int rdma_listen(struct rdma_cm_id *id, int backlog) int rdma_listen(struct rdma_cm_id *id, int backlog)
{ {
struct rdma_id_private *id_priv; struct rdma_id_private *id_priv =
container_of(id, struct rdma_id_private, id);
int ret; int ret;
id_priv = container_of(id, struct rdma_id_private, id); if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_LISTEN)) {
if (id_priv->state == RDMA_CM_IDLE) { /* For a well behaved ULP state will be RDMA_CM_IDLE */
id->route.addr.src_addr.ss_family = AF_INET; id->route.addr.src_addr.ss_family = AF_INET;
ret = rdma_bind_addr(id, cma_src_addr(id_priv)); ret = rdma_bind_addr(id, cma_src_addr(id_priv));
if (ret) if (ret)
return ret; return ret;
if (WARN_ON(!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND,
RDMA_CM_LISTEN)))
return -EINVAL;
} }
if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_LISTEN))
return -EINVAL;
if (id_priv->reuseaddr) { if (id_priv->reuseaddr) {
ret = cma_bind_listen(id_priv); ret = cma_bind_listen(id_priv);
if (ret) if (ret)
......
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