Skip to content

Commit

Permalink
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/gi…
Browse files Browse the repository at this point in the history
…t/rdma/rdma

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
  • Loading branch information
Linus Torvalds committed Nov 1, 2019
2 parents 2858598 + b681a05 commit 4252a1a
Show file tree
Hide file tree
Showing 18 changed files with 127 additions and 124 deletions.
1 change: 1 addition & 0 deletions drivers/infiniband/core/core_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions drivers/infiniband/core/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
52 changes: 29 additions & 23 deletions drivers/infiniband/core/iwcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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:
Expand All @@ -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);
Expand Down Expand Up @@ -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);
cm_id_priv->qp = NULL;
}
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);
}
Expand All @@ -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);

Expand Down Expand Up @@ -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);
cm_id_priv->qp = NULL;
}
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;
Expand Down Expand Up @@ -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;

Expand All @@ -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)
Expand Down Expand Up @@ -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);
qp = cm_id_priv->qp;
cm_id_priv->qp = NULL;

if (cm_id_priv->qp) {
cm_id_priv->id.device->ops.iw_rem_ref(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;
Expand All @@ -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;
}

Expand Down
107 changes: 53 additions & 54 deletions drivers/infiniband/core/netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
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)
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -170,39 +156,46 @@ 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
* mistakenly call the .dump() function.
*/
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) {
struct netlink_dump_control c = {
.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;
}

/*
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion drivers/infiniband/core/nldev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion drivers/infiniband/core/uverbs.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ ib_uverbs_init_udata_buf_or_null(struct ib_udata *udata,

struct ib_uverbs_device {
atomic_t refcount;
int num_comp_vectors;
u32 num_comp_vectors;
struct completion comp;
struct device dev;
/* First group for device attributes, NULL terminated array */
Expand Down
9 changes: 5 additions & 4 deletions drivers/infiniband/core/verbs.c
Original file line number Diff line number Diff line change
Expand Up @@ -662,16 +662,17 @@ static bool find_gid_index(const union ib_gid *gid,
void *context)
{
struct find_gid_index_context *ctx = context;
u16 vlan_id = 0xffff;
int ret;

if (ctx->gid_type != gid_attr->gid_type)
return false;

if ((!!(ctx->vlan_id != 0xffff) == !is_vlan_dev(gid_attr->ndev)) ||
(is_vlan_dev(gid_attr->ndev) &&
vlan_dev_vlan_id(gid_attr->ndev) != ctx->vlan_id))
ret = rdma_read_gid_l2_fields(gid_attr, &vlan_id, NULL);
if (ret)
return false;

return true;
return ctx->vlan_id == vlan_id;
}

static const struct ib_gid_attr *
Expand Down
Loading

0 comments on commit 4252a1a

Please sign in to comment.