Commit b9c0f4bd authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull rdma fixes from Jason Gunthorpe:
 "The good news is people are testing rc1 in the RDMA world - the bad
  news is testing of the for-next area is not as good as I had hoped, as
  we really should have caught at least the rdma_connect_locked() issue
  before now.

  Notable merge window regressions that didn't get caught/fixed in time
  for rc1:

   - Fix in kernel users of rxe, they were broken by the rapid fix to
     undo the uABI breakage in rxe from another patch

   - EFA userspace needs to read the GID table but was broken with the
     new GID table logic

   - Fix user triggerable deadlock in mlx5 using devlink reload

   - Fix deadlock in several ULPs using rdma_connect from the CM handler
     callbacks

   - Memory leak in qedr"

* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma:
  RDMA/qedr: Fix memory leak in iWARP CM
  RDMA: Add rdma_connect_locked()
  RDMA/uverbs: Fix false error in query gid IOCTL
  RDMA/mlx5: Fix devlink deadlock on net namespace deletion
  RDMA/rxe: Fix small problem in network_type patch
parents 598a5976 a2267f8a
Loading
Loading
Loading
Loading
+38 −10
Original line number Diff line number Diff line
@@ -405,10 +405,10 @@ static int cma_comp_exch(struct rdma_id_private *id_priv,
	/*
	 * The FSM uses a funny double locking where state is protected by both
	 * the handler_mutex and the spinlock. State is not allowed to change
	 * away from a handler_mutex protected value without also holding
	 * to/from a handler_mutex protected value without also holding
	 * handler_mutex.
	 */
	if (comp == RDMA_CM_CONNECT)
	if (comp == RDMA_CM_CONNECT || exch == RDMA_CM_CONNECT)
		lockdep_assert_held(&id_priv->handler_mutex);

	spin_lock_irqsave(&id_priv->lock, flags);
@@ -4038,17 +4038,23 @@ out:
	return ret;
}

int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
/**
 * rdma_connect_locked - Initiate an active connection request.
 * @id: Connection identifier to connect.
 * @conn_param: Connection information used for connected QPs.
 *
 * Same as rdma_connect() but can only be called from the
 * RDMA_CM_EVENT_ROUTE_RESOLVED handler callback.
 */
int rdma_connect_locked(struct rdma_cm_id *id,
			struct rdma_conn_param *conn_param)
{
	struct rdma_id_private *id_priv =
		container_of(id, struct rdma_id_private, id);
	int ret;

	mutex_lock(&id_priv->handler_mutex);
	if (!cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_CONNECT)) {
		ret = -EINVAL;
		goto err_unlock;
	}
	if (!cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_CONNECT))
		return -EINVAL;

	if (!id->qp) {
		id_priv->qp_num = conn_param->qp_num;
@@ -4066,11 +4072,33 @@ int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
		ret = -ENOSYS;
	if (ret)
		goto err_state;
	mutex_unlock(&id_priv->handler_mutex);
	return 0;
err_state:
	cma_comp_exch(id_priv, RDMA_CM_CONNECT, RDMA_CM_ROUTE_RESOLVED);
err_unlock:
	return ret;
}
EXPORT_SYMBOL(rdma_connect_locked);

/**
 * rdma_connect - Initiate an active connection request.
 * @id: Connection identifier to connect.
 * @conn_param: Connection information used for connected QPs.
 *
 * Users must have resolved a route for the rdma_cm_id to connect with by having
 * called rdma_resolve_route before calling this routine.
 *
 * This call will either connect to a remote QP or obtain remote QP information
 * for unconnected rdma_cm_id's.  The actual operation is based on the
 * rdma_cm_id's port space.
 */
int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
{
	struct rdma_id_private *id_priv =
		container_of(id, struct rdma_id_private, id);
	int ret;

	mutex_lock(&id_priv->handler_mutex);
	ret = rdma_connect_locked(id, conn_param);
	mutex_unlock(&id_priv->handler_mutex);
	return ret;
}
+0 −3
Original line number Diff line number Diff line
@@ -401,9 +401,6 @@ static int UVERBS_HANDLER(UVERBS_METHOD_QUERY_GID_ENTRY)(
	if (!rdma_is_port_valid(ib_dev, port_num))
		return -EINVAL;

	if (!rdma_ib_or_roce(ib_dev, port_num))
		return -EOPNOTSUPP;

	gid_attr = rdma_get_gid_attr(ib_dev, port_num, gid_index);
	if (IS_ERR(gid_attr))
		return PTR_ERR(gid_attr);
+4 −2
Original line number Diff line number Diff line
@@ -3305,7 +3305,8 @@ static int mlx5_add_netdev_notifier(struct mlx5_ib_dev *dev, u8 port_num)
	int err;

	dev->port[port_num].roce.nb.notifier_call = mlx5_netdev_event;
	err = register_netdevice_notifier(&dev->port[port_num].roce.nb);
	err = register_netdevice_notifier_net(mlx5_core_net(dev->mdev),
					      &dev->port[port_num].roce.nb);
	if (err) {
		dev->port[port_num].roce.nb.notifier_call = NULL;
		return err;
@@ -3317,7 +3318,8 @@ static int mlx5_add_netdev_notifier(struct mlx5_ib_dev *dev, u8 port_num)
static void mlx5_remove_netdev_notifier(struct mlx5_ib_dev *dev, u8 port_num)
{
	if (dev->port[port_num].roce.nb.notifier_call) {
		unregister_netdevice_notifier(&dev->port[port_num].roce.nb);
		unregister_netdevice_notifier_net(mlx5_core_net(dev->mdev),
						  &dev->port[port_num].roce.nb);
		dev->port[port_num].roce.nb.notifier_call = NULL;
	}
}
+1 −0
Original line number Diff line number Diff line
@@ -727,6 +727,7 @@ int qedr_iw_destroy_listen(struct iw_cm_id *cm_id)
						    listener->qed_handle);

	cm_id->rem_ref(cm_id);
	kfree(listener);
	return rc;
}

+31 −4
Original line number Diff line number Diff line
@@ -16,15 +16,24 @@ void rxe_init_av(struct rdma_ah_attr *attr, struct rxe_av *av)

int rxe_av_chk_attr(struct rxe_dev *rxe, struct rdma_ah_attr *attr)
{
	const struct ib_global_route *grh = rdma_ah_read_grh(attr);
	struct rxe_port *port;
	int type;

	port = &rxe->port;

	if (rdma_ah_get_ah_flags(attr) & IB_AH_GRH) {
		u8 sgid_index = rdma_ah_read_grh(attr)->sgid_index;
		if (grh->sgid_index > port->attr.gid_tbl_len) {
			pr_warn("invalid sgid index = %d\n",
					grh->sgid_index);
			return -EINVAL;
		}

		if (sgid_index > port->attr.gid_tbl_len) {
			pr_warn("invalid sgid index = %d\n", sgid_index);
		type = rdma_gid_attr_network_type(grh->sgid_attr);
		if (type < RDMA_NETWORK_IPV4 ||
		    type > RDMA_NETWORK_IPV6) {
			pr_warn("invalid network type for rdma_rxe = %d\n",
					type);
			return -EINVAL;
		}
	}
@@ -65,11 +74,29 @@ void rxe_av_to_attr(struct rxe_av *av, struct rdma_ah_attr *attr)
void rxe_av_fill_ip_info(struct rxe_av *av, struct rdma_ah_attr *attr)
{
	const struct ib_gid_attr *sgid_attr = attr->grh.sgid_attr;
	int ibtype;
	int type;

	rdma_gid2ip((struct sockaddr *)&av->sgid_addr, &sgid_attr->gid);
	rdma_gid2ip((struct sockaddr *)&av->dgid_addr,
		    &rdma_ah_read_grh(attr)->dgid);
	av->network_type = rdma_gid_attr_network_type(sgid_attr);

	ibtype = rdma_gid_attr_network_type(sgid_attr);

	switch (ibtype) {
	case RDMA_NETWORK_IPV4:
		type = RXE_NETWORK_TYPE_IPV4;
		break;
	case RDMA_NETWORK_IPV6:
		type = RXE_NETWORK_TYPE_IPV4;
		break;
	default:
		/* not reached - checked in rxe_av_chk_attr */
		type = 0;
		break;
	}

	av->network_type = type;
}

struct rxe_av *rxe_get_av(struct rxe_pkt_info *pkt)
Loading