diff options
Diffstat (limited to 'drivers/infiniband/core/cma.c')
| -rw-r--r-- | drivers/infiniband/core/cma.c | 83 | 
1 files changed, 54 insertions, 29 deletions
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 68c997be2429..19f1730a4f24 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -39,7 +39,7 @@  #include <linux/mutex.h>  #include <linux/random.h>  #include <linux/igmp.h> -#include <linux/idr.h> +#include <linux/xarray.h>  #include <linux/inetdevice.h>  #include <linux/slab.h>  #include <linux/module.h> @@ -191,10 +191,10 @@ static struct workqueue_struct *cma_wq;  static unsigned int cma_pernet_id;  struct cma_pernet { -	struct idr tcp_ps; -	struct idr udp_ps; -	struct idr ipoib_ps; -	struct idr ib_ps; +	struct xarray tcp_ps; +	struct xarray udp_ps; +	struct xarray ipoib_ps; +	struct xarray ib_ps;  };  static struct cma_pernet *cma_pernet(struct net *net) @@ -202,7 +202,8 @@ static struct cma_pernet *cma_pernet(struct net *net)  	return net_generic(net, cma_pernet_id);  } -static struct idr *cma_pernet_idr(struct net *net, enum rdma_ucm_port_space ps) +static +struct xarray *cma_pernet_xa(struct net *net, enum rdma_ucm_port_space ps)  {  	struct cma_pernet *pernet = cma_pernet(net); @@ -247,25 +248,25 @@ struct class_port_info_context {  static int cma_ps_alloc(struct net *net, enum rdma_ucm_port_space ps,  			struct rdma_bind_list *bind_list, int snum)  { -	struct idr *idr = cma_pernet_idr(net, ps); +	struct xarray *xa = cma_pernet_xa(net, ps); -	return idr_alloc(idr, bind_list, snum, snum + 1, GFP_KERNEL); +	return xa_insert(xa, snum, bind_list, GFP_KERNEL);  }  static struct rdma_bind_list *cma_ps_find(struct net *net,  					  enum rdma_ucm_port_space ps, int snum)  { -	struct idr *idr = cma_pernet_idr(net, ps); +	struct xarray *xa = cma_pernet_xa(net, ps); -	return idr_find(idr, snum); +	return xa_load(xa, snum);  }  static void cma_ps_remove(struct net *net, enum rdma_ucm_port_space ps,  			  int snum)  { -	struct idr *idr = cma_pernet_idr(net, ps); +	struct xarray *xa = cma_pernet_xa(net, ps); -	idr_remove(idr, snum); +	xa_erase(xa, snum);  }  enum { @@ -615,6 +616,9 @@ cma_validate_port(struct ib_device *device, u8 port,  	int dev_type = dev_addr->dev_type;  	struct net_device *ndev = NULL; +	if (!rdma_dev_access_netns(device, id_priv->id.route.addr.dev_addr.net)) +		return ERR_PTR(-ENODEV); +  	if ((dev_type == ARPHRD_INFINIBAND) && !rdma_protocol_ib(device, port))  		return ERR_PTR(-ENODEV); @@ -1173,18 +1177,31 @@ static inline bool cma_any_addr(const struct sockaddr *addr)  	return cma_zero_addr(addr) || cma_loopback_addr(addr);  } -static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst) +static int cma_addr_cmp(const struct sockaddr *src, const struct sockaddr *dst)  {  	if (src->sa_family != dst->sa_family)  		return -1;  	switch (src->sa_family) {  	case AF_INET: -		return ((struct sockaddr_in *) src)->sin_addr.s_addr != -		       ((struct sockaddr_in *) dst)->sin_addr.s_addr; -	case AF_INET6: -		return ipv6_addr_cmp(&((struct sockaddr_in6 *) src)->sin6_addr, -				     &((struct sockaddr_in6 *) dst)->sin6_addr); +		return ((struct sockaddr_in *)src)->sin_addr.s_addr != +		       ((struct sockaddr_in *)dst)->sin_addr.s_addr; +	case AF_INET6: { +		struct sockaddr_in6 *src_addr6 = (struct sockaddr_in6 *)src; +		struct sockaddr_in6 *dst_addr6 = (struct sockaddr_in6 *)dst; +		bool link_local; + +		if (ipv6_addr_cmp(&src_addr6->sin6_addr, +					  &dst_addr6->sin6_addr)) +			return 1; +		link_local = ipv6_addr_type(&dst_addr6->sin6_addr) & +			     IPV6_ADDR_LINKLOCAL; +		/* Link local must match their scope_ids */ +		return link_local ? (src_addr6->sin6_scope_id != +				     dst_addr6->sin6_scope_id) : +				    0; +	} +  	default:  		return ib_addr_cmp(&((struct sockaddr_ib *) src)->sib_addr,  				   &((struct sockaddr_ib *) dst)->sib_addr); @@ -1469,6 +1486,7 @@ static struct net_device *  roce_get_net_dev_by_cm_event(const struct ib_cm_event *ib_event)  {  	const struct ib_gid_attr *sgid_attr = NULL; +	struct net_device *ndev;  	if (ib_event->event == IB_CM_REQ_RECEIVED)  		sgid_attr = ib_event->param.req_rcvd.ppath_sgid_attr; @@ -1477,8 +1495,15 @@ roce_get_net_dev_by_cm_event(const struct ib_cm_event *ib_event)  	if (!sgid_attr)  		return NULL; -	dev_hold(sgid_attr->ndev); -	return sgid_attr->ndev; + +	rcu_read_lock(); +	ndev = rdma_read_gid_attr_ndev_rcu(sgid_attr); +	if (IS_ERR(ndev)) +		ndev = NULL; +	else +		dev_hold(ndev); +	rcu_read_unlock(); +	return ndev;  }  static struct net_device *cma_get_net_dev(const struct ib_cm_event *ib_event, @@ -3247,7 +3272,7 @@ static int cma_alloc_port(enum rdma_ucm_port_space ps,  		goto err;  	bind_list->ps = ps; -	bind_list->port = (unsigned short)ret; +	bind_list->port = snum;  	cma_bind_port(bind_list, id_priv);  	return 0;  err: @@ -4655,10 +4680,10 @@ static int cma_init_net(struct net *net)  {  	struct cma_pernet *pernet = cma_pernet(net); -	idr_init(&pernet->tcp_ps); -	idr_init(&pernet->udp_ps); -	idr_init(&pernet->ipoib_ps); -	idr_init(&pernet->ib_ps); +	xa_init(&pernet->tcp_ps); +	xa_init(&pernet->udp_ps); +	xa_init(&pernet->ipoib_ps); +	xa_init(&pernet->ib_ps);  	return 0;  } @@ -4667,10 +4692,10 @@ static void cma_exit_net(struct net *net)  {  	struct cma_pernet *pernet = cma_pernet(net); -	idr_destroy(&pernet->tcp_ps); -	idr_destroy(&pernet->udp_ps); -	idr_destroy(&pernet->ipoib_ps); -	idr_destroy(&pernet->ib_ps); +	WARN_ON(!xa_empty(&pernet->tcp_ps)); +	WARN_ON(!xa_empty(&pernet->udp_ps)); +	WARN_ON(!xa_empty(&pernet->ipoib_ps)); +	WARN_ON(!xa_empty(&pernet->ib_ps));  }  static struct pernet_operations cma_pernet_operations = {  |