Commit 0457e515 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull rdma fixes from Jason Gunthorpe:
 "Some medium sized bugs in the various drivers. A couple are more
  recent regressions:

   - Fix two panics in hfi1 and two allocation problems

   - Send the IGMP to the correct address in cma

   - Squash a syzkaller bug related to races reading the multicast list

   - Memory leak in siw and cm

   - Fix a corner case spec compliance for HFI/QIB

   - Correct the implementation of fences in siw

   - Error unwind bug in mlx4"

* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma:
  RDMA/mlx4: Don't continue event handler after memory allocation failure
  RDMA/siw: Fix broken RDMA Read Fence/Resume logic.
  IB/rdmavt: Validate remote_addr during loopback atomic tests
  IB/cm: Release previously acquired reference counter in the cm_id_priv
  RDMA/siw: Fix refcounting leak in siw_create_qp()
  RDMA/ucma: Protect mc during concurrent multicast leaves
  RDMA/cma: Use correct address when leaving multicast group
  IB/hfi1: Fix tstats alloc and dealloc
  IB/hfi1: Fix AIP early init panic
  IB/hfi1: Fix alloc failure with larger txqueuelen
  IB/hfi1: Fix panic with larger ipoib send_queue_size
parents fc93310c f3136c4c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -3322,7 +3322,7 @@ static int cm_lap_handler(struct cm_work *work)
	ret = cm_init_av_by_path(param->alternate_path, NULL, &alt_av);
	if (ret) {
		rdma_destroy_ah_attr(&ah_attr);
		return -EINVAL;
		goto deref;
	}

	spin_lock_irq(&cm_id_priv->lock);
+12 −10
Original line number Diff line number Diff line
@@ -67,8 +67,8 @@ static const char * const cma_events[] = {
	[RDMA_CM_EVENT_TIMEWAIT_EXIT]	 = "timewait exit",
};

static void cma_set_mgid(struct rdma_id_private *id_priv, struct sockaddr *addr,
			 union ib_gid *mgid);
static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid,
			      enum ib_gid_type gid_type);

const char *__attribute_const__ rdma_event_msg(enum rdma_cm_event_type event)
{
@@ -1846,17 +1846,19 @@ static void destroy_mc(struct rdma_id_private *id_priv,
		if (dev_addr->bound_dev_if)
			ndev = dev_get_by_index(dev_addr->net,
						dev_addr->bound_dev_if);
		if (ndev) {
		if (ndev && !send_only) {
			enum ib_gid_type gid_type;
			union ib_gid mgid;

			cma_set_mgid(id_priv, (struct sockaddr *)&mc->addr,
				     &mgid);

			if (!send_only)
			gid_type = id_priv->cma_dev->default_gid_type
					   [id_priv->id.port_num -
					    rdma_start_port(
						    id_priv->cma_dev->device)];
			cma_iboe_set_mgid((struct sockaddr *)&mc->addr, &mgid,
					  gid_type);
			cma_igmp_send(ndev, &mgid, false);

			dev_put(ndev);
		}
		dev_put(ndev);

		cancel_work_sync(&mc->iboe_join.work);
	}
+23 −11
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ struct ucma_context {
	u64			uid;

	struct list_head	list;
	struct list_head	mc_list;
	struct work_struct	close_work;
};

@@ -105,6 +106,7 @@ struct ucma_multicast {

	u64			uid;
	u8			join_state;
	struct list_head	list;
	struct sockaddr_storage	addr;
};

@@ -198,6 +200,7 @@ static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file)

	INIT_WORK(&ctx->close_work, ucma_close_id);
	init_completion(&ctx->comp);
	INIT_LIST_HEAD(&ctx->mc_list);
	/* So list_del() will work if we don't do ucma_finish_ctx() */
	INIT_LIST_HEAD(&ctx->list);
	ctx->file = file;
@@ -484,19 +487,19 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf,

static void ucma_cleanup_multicast(struct ucma_context *ctx)
{
	struct ucma_multicast *mc;
	unsigned long index;
	struct ucma_multicast *mc, *tmp;

	xa_for_each(&multicast_table, index, mc) {
		if (mc->ctx != ctx)
			continue;
	xa_lock(&multicast_table);
	list_for_each_entry_safe(mc, tmp, &ctx->mc_list, list) {
		list_del(&mc->list);
		/*
		 * At this point mc->ctx->ref is 0 so the mc cannot leave the
		 * lock on the reader and this is enough serialization
		 */
		xa_erase(&multicast_table, index);
		__xa_erase(&multicast_table, mc->id);
		kfree(mc);
	}
	xa_unlock(&multicast_table);
}

static void ucma_cleanup_mc_events(struct ucma_multicast *mc)
@@ -1469,12 +1472,16 @@ static ssize_t ucma_process_join(struct ucma_file *file,
	mc->uid = cmd->uid;
	memcpy(&mc->addr, addr, cmd->addr_size);

	if (xa_alloc(&multicast_table, &mc->id, NULL, xa_limit_32b,
	xa_lock(&multicast_table);
	if (__xa_alloc(&multicast_table, &mc->id, NULL, xa_limit_32b,
		     GFP_KERNEL)) {
		ret = -ENOMEM;
		goto err_free_mc;
	}

	list_add_tail(&mc->list, &ctx->mc_list);
	xa_unlock(&multicast_table);

	mutex_lock(&ctx->mutex);
	ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *)&mc->addr,
				  join_state, mc);
@@ -1500,8 +1507,11 @@ static ssize_t ucma_process_join(struct ucma_file *file,
	mutex_unlock(&ctx->mutex);
	ucma_cleanup_mc_events(mc);
err_xa_erase:
	xa_erase(&multicast_table, mc->id);
	xa_lock(&multicast_table);
	list_del(&mc->list);
	__xa_erase(&multicast_table, mc->id);
err_free_mc:
	xa_unlock(&multicast_table);
	kfree(mc);
err_put_ctx:
	ucma_put_ctx(ctx);
@@ -1569,15 +1579,17 @@ static ssize_t ucma_leave_multicast(struct ucma_file *file,
		mc = ERR_PTR(-EINVAL);
	else if (!refcount_inc_not_zero(&mc->ctx->ref))
		mc = ERR_PTR(-ENXIO);
	else
		__xa_erase(&multicast_table, mc->id);
	xa_unlock(&multicast_table);

	if (IS_ERR(mc)) {
		xa_unlock(&multicast_table);
		ret = PTR_ERR(mc);
		goto out;
	}

	list_del(&mc->list);
	__xa_erase(&multicast_table, mc->id);
	xa_unlock(&multicast_table);

	mutex_lock(&mc->ctx->mutex);
	rdma_leave_multicast(mc->ctx->cm_id, (struct sockaddr *) &mc->addr);
	mutex_unlock(&mc->ctx->mutex);
+1 −1
Original line number Diff line number Diff line
@@ -55,7 +55,7 @@ union hfi1_ipoib_flow {
 */
struct ipoib_txreq {
	struct sdma_txreq           txreq;
	struct hfi1_sdma_header     sdma_hdr;
	struct hfi1_sdma_header     *sdma_hdr;
	int                         sdma_status;
	int                         complete;
	struct hfi1_ipoib_dev_priv *priv;
+15 −12
Original line number Diff line number Diff line
@@ -22,26 +22,35 @@ static int hfi1_ipoib_dev_init(struct net_device *dev)
	int ret;

	dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
	if (!dev->tstats)
		return -ENOMEM;

	ret = priv->netdev_ops->ndo_init(dev);
	if (ret)
		return ret;
		goto out_ret;

	ret = hfi1_netdev_add_data(priv->dd,
				   qpn_from_mac(priv->netdev->dev_addr),
				   dev);
	if (ret < 0) {
		priv->netdev_ops->ndo_uninit(dev);
		return ret;
		goto out_ret;
	}

	return 0;
out_ret:
	free_percpu(dev->tstats);
	dev->tstats = NULL;
	return ret;
}

static void hfi1_ipoib_dev_uninit(struct net_device *dev)
{
	struct hfi1_ipoib_dev_priv *priv = hfi1_ipoib_priv(dev);

	free_percpu(dev->tstats);
	dev->tstats = NULL;

	hfi1_netdev_remove_data(priv->dd, qpn_from_mac(priv->netdev->dev_addr));

	priv->netdev_ops->ndo_uninit(dev);
@@ -166,12 +175,7 @@ static void hfi1_ipoib_netdev_dtor(struct net_device *dev)
	hfi1_ipoib_rxq_deinit(priv->netdev);

	free_percpu(dev->tstats);
}

static void hfi1_ipoib_free_rdma_netdev(struct net_device *dev)
{
	hfi1_ipoib_netdev_dtor(dev);
	free_netdev(dev);
	dev->tstats = NULL;
}

static void hfi1_ipoib_set_id(struct net_device *dev, int id)
@@ -211,24 +215,23 @@ static int hfi1_ipoib_setup_rn(struct ib_device *device,
	priv->port_num = port_num;
	priv->netdev_ops = netdev->netdev_ops;

	netdev->netdev_ops = &hfi1_ipoib_netdev_ops;

	ib_query_pkey(device, port_num, priv->pkey_index, &priv->pkey);

	rc = hfi1_ipoib_txreq_init(priv);
	if (rc) {
		dd_dev_err(dd, "IPoIB netdev TX init - failed(%d)\n", rc);
		hfi1_ipoib_free_rdma_netdev(netdev);
		return rc;
	}

	rc = hfi1_ipoib_rxq_init(netdev);
	if (rc) {
		dd_dev_err(dd, "IPoIB netdev RX init - failed(%d)\n", rc);
		hfi1_ipoib_free_rdma_netdev(netdev);
		hfi1_ipoib_txreq_deinit(priv);
		return rc;
	}

	netdev->netdev_ops = &hfi1_ipoib_netdev_ops;

	netdev->priv_destructor = hfi1_ipoib_netdev_dtor;
	netdev->needs_free_netdev = true;

Loading