Commit 4252a1a9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull rdma fixes from Jason Gunthorpe:
 "A number of bug fixes and a regression fix:

   - Various issues from static analysis in hfi1, uverbs, hns, and cxgb4

   - Fix for deadlock in a case when the new auto RDMA module loading is
     used

   - Missing _irq notation in a prior -rc patch found by lockdep

   - Fix a locking and lifetime issue in siw

   - Minor functional bug fixes in cxgb4, mlx5, qedr

   - Fix a regression where vlan interfaces no longer worked with RDMA
     CM in some cases"

* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma:
  RDMA/hns: Prevent memory leaks of eq->buf_list
  RDMA/iw_cxgb4: Avoid freeing skb twice in arp failure case
  RDMA/mlx5: Use irq xarray locking for mkey_table
  IB/core: Avoid deadlock during netlink message handling
  RDMA/nldev: Skip counter if port doesn't match
  RDMA/uverbs: Prevent potential underflow
  IB/core: Use rdma_read_gid_l2_fields to compare GID L2 fields
  RDMA/qedr: Fix reported firmware version
  RDMA/siw: free siw_base_qp in kref release routine
  RDMA/iwcm: move iw_rem_ref() calls out of spinlock
  iw_cxgb4: fix ECN check on the passive accept
  IB/hfi1: Use a common pad buffer for 9B and 16B packets
  IB/hfi1: Avoid excessive retry for TID RDMA READ request
  RDMA/mlx5: Clear old rate limit when closing QP
parents 28585980 b681a052
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -199,6 +199,7 @@ void ib_mad_cleanup(void);
int ib_sa_init(void);
void ib_sa_cleanup(void);

void rdma_nl_init(void);
void rdma_nl_exit(void);

int ib_nl_handle_resolve_resp(struct sk_buff *skb,
+2 −0
Original line number Diff line number Diff line
@@ -2716,6 +2716,8 @@ static int __init ib_core_init(void)
		goto err_comp_unbound;
	}

	rdma_nl_init();

	ret = addr_init();
	if (ret) {
		pr_warn("Could't init IB address resolution\n");
+29 −23
Original line number Diff line number Diff line
@@ -372,6 +372,7 @@ EXPORT_SYMBOL(iw_cm_disconnect);
static void destroy_cm_id(struct iw_cm_id *cm_id)
{
	struct iwcm_id_private *cm_id_priv;
	struct ib_qp *qp;
	unsigned long flags;

	cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
@@ -389,6 +390,9 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
	set_bit(IWCM_F_DROP_EVENTS, &cm_id_priv->flags);

	spin_lock_irqsave(&cm_id_priv->lock, flags);
	qp = cm_id_priv->qp;
	cm_id_priv->qp = NULL;

	switch (cm_id_priv->state) {
	case IW_CM_STATE_LISTEN:
		cm_id_priv->state = IW_CM_STATE_DESTROYING;
@@ -401,7 +405,7 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
		cm_id_priv->state = IW_CM_STATE_DESTROYING;
		spin_unlock_irqrestore(&cm_id_priv->lock, flags);
		/* Abrupt close of the connection */
		(void)iwcm_modify_qp_err(cm_id_priv->qp);
		(void)iwcm_modify_qp_err(qp);
		spin_lock_irqsave(&cm_id_priv->lock, flags);
		break;
	case IW_CM_STATE_IDLE:
@@ -426,11 +430,9 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
		BUG();
		break;
	}
	if (cm_id_priv->qp) {
		cm_id_priv->id.device->ops.iw_rem_ref(cm_id_priv->qp);
		cm_id_priv->qp = NULL;
	}
	spin_unlock_irqrestore(&cm_id_priv->lock, flags);
	if (qp)
		cm_id_priv->id.device->ops.iw_rem_ref(qp);

	if (cm_id->mapped) {
		iwpm_remove_mapinfo(&cm_id->local_addr, &cm_id->m_local_addr);
@@ -671,11 +673,11 @@ int iw_cm_accept(struct iw_cm_id *cm_id,
		BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_RECV);
		cm_id_priv->state = IW_CM_STATE_IDLE;
		spin_lock_irqsave(&cm_id_priv->lock, flags);
		if (cm_id_priv->qp) {
			cm_id->device->ops.iw_rem_ref(qp);
		qp = cm_id_priv->qp;
		cm_id_priv->qp = NULL;
		}
		spin_unlock_irqrestore(&cm_id_priv->lock, flags);
		if (qp)
			cm_id->device->ops.iw_rem_ref(qp);
		clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
		wake_up_all(&cm_id_priv->connect_wait);
	}
@@ -696,7 +698,7 @@ int iw_cm_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
	struct iwcm_id_private *cm_id_priv;
	int ret;
	unsigned long flags;
	struct ib_qp *qp;
	struct ib_qp *qp = NULL;

	cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);

@@ -730,13 +732,13 @@ int iw_cm_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
		return 0;	/* success */

	spin_lock_irqsave(&cm_id_priv->lock, flags);
	if (cm_id_priv->qp) {
		cm_id->device->ops.iw_rem_ref(qp);
	qp = cm_id_priv->qp;
	cm_id_priv->qp = NULL;
	}
	cm_id_priv->state = IW_CM_STATE_IDLE;
err:
	spin_unlock_irqrestore(&cm_id_priv->lock, flags);
	if (qp)
		cm_id->device->ops.iw_rem_ref(qp);
	clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
	wake_up_all(&cm_id_priv->connect_wait);
	return ret;
@@ -878,6 +880,7 @@ static int cm_conn_est_handler(struct iwcm_id_private *cm_id_priv,
static int cm_conn_rep_handler(struct iwcm_id_private *cm_id_priv,
			       struct iw_cm_event *iw_event)
{
	struct ib_qp *qp = NULL;
	unsigned long flags;
	int ret;

@@ -896,11 +899,13 @@ static int cm_conn_rep_handler(struct iwcm_id_private *cm_id_priv,
		cm_id_priv->state = IW_CM_STATE_ESTABLISHED;
	} else {
		/* REJECTED or RESET */
		cm_id_priv->id.device->ops.iw_rem_ref(cm_id_priv->qp);
		qp = cm_id_priv->qp;
		cm_id_priv->qp = NULL;
		cm_id_priv->state = IW_CM_STATE_IDLE;
	}
	spin_unlock_irqrestore(&cm_id_priv->lock, flags);
	if (qp)
		cm_id_priv->id.device->ops.iw_rem_ref(qp);
	ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, iw_event);

	if (iw_event->private_data_len)
@@ -942,21 +947,18 @@ static void cm_disconnect_handler(struct iwcm_id_private *cm_id_priv,
static int cm_close_handler(struct iwcm_id_private *cm_id_priv,
				  struct iw_cm_event *iw_event)
{
	struct ib_qp *qp;
	unsigned long flags;
	int ret = 0;
	int ret = 0, notify_event = 0;
	spin_lock_irqsave(&cm_id_priv->lock, flags);

	if (cm_id_priv->qp) {
		cm_id_priv->id.device->ops.iw_rem_ref(cm_id_priv->qp);
	qp = cm_id_priv->qp;
	cm_id_priv->qp = NULL;
	}

	switch (cm_id_priv->state) {
	case IW_CM_STATE_ESTABLISHED:
	case IW_CM_STATE_CLOSING:
		cm_id_priv->state = IW_CM_STATE_IDLE;
		spin_unlock_irqrestore(&cm_id_priv->lock, flags);
		ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, iw_event);
		spin_lock_irqsave(&cm_id_priv->lock, flags);
		notify_event = 1;
		break;
	case IW_CM_STATE_DESTROYING:
		break;
@@ -965,6 +967,10 @@ static int cm_close_handler(struct iwcm_id_private *cm_id_priv,
	}
	spin_unlock_irqrestore(&cm_id_priv->lock, flags);

	if (qp)
		cm_id_priv->id.device->ops.iw_rem_ref(qp);
	if (notify_event)
		ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, iw_event);
	return ret;
}

+53 −54
Original line number Diff line number Diff line
@@ -42,9 +42,12 @@
#include <linux/module.h>
#include "core_priv.h"

static DEFINE_MUTEX(rdma_nl_mutex);
static struct {
	const struct rdma_nl_cbs *cb_table;
	/* Synchronizes between ongoing netlink commands and netlink client
	 * unregistration.
	 */
	struct rw_semaphore sem;
} rdma_nl_types[RDMA_NL_NUM_CLIENTS];

bool rdma_nl_chk_listeners(unsigned int group)
@@ -75,70 +78,53 @@ static bool is_nl_msg_valid(unsigned int type, unsigned int op)
	return (op < max_num_ops[type]) ? true : false;
}

static bool
is_nl_valid(const struct sk_buff *skb, unsigned int type, unsigned int op)
static const struct rdma_nl_cbs *
get_cb_table(const struct sk_buff *skb, unsigned int type, unsigned int op)
{
	const struct rdma_nl_cbs *cb_table;

	if (!is_nl_msg_valid(type, op))
		return false;

	/*
	 * Currently only NLDEV client is supporting netlink commands in
	 * non init_net net namespace.
	 */
	if (sock_net(skb->sk) != &init_net && type != RDMA_NL_NLDEV)
		return false;
		return NULL;

	if (!rdma_nl_types[type].cb_table) {
		mutex_unlock(&rdma_nl_mutex);
		request_module("rdma-netlink-subsys-%d", type);
		mutex_lock(&rdma_nl_mutex);
	}
	cb_table = READ_ONCE(rdma_nl_types[type].cb_table);
	if (!cb_table) {
		/*
		 * Didn't get valid reference of the table, attempt module
		 * load once.
		 */
		up_read(&rdma_nl_types[type].sem);

	cb_table = rdma_nl_types[type].cb_table;
		request_module("rdma-netlink-subsys-%d", type);

		down_read(&rdma_nl_types[type].sem);
		cb_table = READ_ONCE(rdma_nl_types[type].cb_table);
	}
	if (!cb_table || (!cb_table[op].dump && !cb_table[op].doit))
		return false;
	return true;
		return NULL;
	return cb_table;
}

void rdma_nl_register(unsigned int index,
		      const struct rdma_nl_cbs cb_table[])
{
	mutex_lock(&rdma_nl_mutex);
	if (!is_nl_msg_valid(index, 0)) {
		/*
		 * All clients are not interesting in success/failure of
		 * this call. They want to see the print to error log and
		 * continue their initialization. Print warning for them,
		 * because it is programmer's error to be here.
		 */
		mutex_unlock(&rdma_nl_mutex);
		WARN(true,
		     "The not-valid %u index was supplied to RDMA netlink\n",
		     index);
	if (WARN_ON(!is_nl_msg_valid(index, 0)) ||
	    WARN_ON(READ_ONCE(rdma_nl_types[index].cb_table)))
		return;
	}

	if (rdma_nl_types[index].cb_table) {
		mutex_unlock(&rdma_nl_mutex);
		WARN(true,
		     "The %u index is already registered in RDMA netlink\n",
		     index);
		return;
	}

	rdma_nl_types[index].cb_table = cb_table;
	mutex_unlock(&rdma_nl_mutex);
	/* Pairs with the READ_ONCE in is_nl_valid() */
	smp_store_release(&rdma_nl_types[index].cb_table, cb_table);
}
EXPORT_SYMBOL(rdma_nl_register);

void rdma_nl_unregister(unsigned int index)
{
	mutex_lock(&rdma_nl_mutex);
	down_write(&rdma_nl_types[index].sem);
	rdma_nl_types[index].cb_table = NULL;
	mutex_unlock(&rdma_nl_mutex);
	up_write(&rdma_nl_types[index].sem);
}
EXPORT_SYMBOL(rdma_nl_unregister);

@@ -170,15 +156,21 @@ static int rdma_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
	unsigned int index = RDMA_NL_GET_CLIENT(type);
	unsigned int op = RDMA_NL_GET_OP(type);
	const struct rdma_nl_cbs *cb_table;
	int err = -EINVAL;

	if (!is_nl_valid(skb, index, op))
	if (!is_nl_msg_valid(index, op))
		return -EINVAL;

	cb_table = rdma_nl_types[index].cb_table;
	down_read(&rdma_nl_types[index].sem);
	cb_table = get_cb_table(skb, index, op);
	if (!cb_table)
		goto done;

	if ((cb_table[op].flags & RDMA_NL_ADMIN_PERM) &&
	    !netlink_capable(skb, CAP_NET_ADMIN))
		return -EPERM;
	    !netlink_capable(skb, CAP_NET_ADMIN)) {
		err = -EPERM;
		goto done;
	}

	/*
	 * LS responses overload the 0x100 (NLM_F_ROOT) flag.  Don't
@@ -186,8 +178,8 @@ static int rdma_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
	 */
	if (index == RDMA_NL_LS) {
		if (cb_table[op].doit)
			return cb_table[op].doit(skb, nlh, extack);
		return -EINVAL;
			err = cb_table[op].doit(skb, nlh, extack);
		goto done;
	}
	/* FIXME: Convert IWCM to properly handle doit callbacks */
	if ((nlh->nlmsg_flags & NLM_F_DUMP) || index == RDMA_NL_IWCM) {
@@ -195,14 +187,15 @@ static int rdma_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
			.dump = cb_table[op].dump,
		};
		if (c.dump)
			return netlink_dump_start(skb->sk, skb, nlh, &c);
		return -EINVAL;
			err = netlink_dump_start(skb->sk, skb, nlh, &c);
		goto done;
	}

	if (cb_table[op].doit)
		return cb_table[op].doit(skb, nlh, extack);

	return 0;
		err = cb_table[op].doit(skb, nlh, extack);
done:
	up_read(&rdma_nl_types[index].sem);
	return err;
}

/*
@@ -263,9 +256,7 @@ static int rdma_nl_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,

static void rdma_nl_rcv(struct sk_buff *skb)
{
	mutex_lock(&rdma_nl_mutex);
	rdma_nl_rcv_skb(skb, &rdma_nl_rcv_msg);
	mutex_unlock(&rdma_nl_mutex);
}

int rdma_nl_unicast(struct net *net, struct sk_buff *skb, u32 pid)
@@ -297,6 +288,14 @@ int rdma_nl_multicast(struct net *net, struct sk_buff *skb,
}
EXPORT_SYMBOL(rdma_nl_multicast);

void rdma_nl_init(void)
{
	int idx;

	for (idx = 0; idx < RDMA_NL_NUM_CLIENTS; idx++)
		init_rwsem(&rdma_nl_types[idx].sem);
}

void rdma_nl_exit(void)
{
	int idx;
+1 −1
Original line number Diff line number Diff line
@@ -778,7 +778,7 @@ static int fill_res_counter_entry(struct sk_buff *msg, bool has_cap_net_admin,
		container_of(res, struct rdma_counter, res);

	if (port && port != counter->port)
		return 0;
		return -EAGAIN;

	/* Dump it even query failed */
	rdma_counter_query_stats(counter);
Loading