mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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.org Signed-off-by: Leon Romanovsky <leonro@nvidia.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
This commit is contained in:
		
							parent
							
								
									2a7cec5381
								
							
						
					
					
						commit
						732d41c545
					
				
					 1 changed files with 45 additions and 22 deletions
				
			
		| 
						 | 
					@ -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,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue