mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 22:09:30 +02:00
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma
Pull rdma fixes from Jason Gunthorpe:
"Lots of bug fixes from the last weeks:
- Various error unwind bugs
- Several more races and bugs in siw and rxe, including remote
triggerable
- HFI1 corruption with its credit scheme
- Remove a bogus user triggerable dev_warn
- Lock __ethtool_get_link_ksettings() properly
- Fix a lockdep loop with diassociation
- Several storage related bugs, some triggerable remotely
- Do no leak physical addresses to userspace in bnxt_re
- Fix wrong irq context for the xarrays in erdma
- User triggerable race in ucma with multicast
- Race in ipoib with multicast flushing and destruction"
* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma: (28 commits)
RDMA/siw: Bound fragmented header copies by the remaining length
RDMA/efa: Keep EQ resources alive while IRQ is registered
RDMA/efa: Keep admin queues alive while IRQ is registered
RDMA/core: fix refcount bug in iwpm_get_nlmsg_request()
IB/IPoIB: Avoid restoring OPER_UP after multicast flush
RDMA/ucma: Serialize join and leave on copy_to_user failure
RDMA/rtrs-clt: Fix CQ pool leak when connect is interrupted
RDMA/irdma: Enforce local fence for IB_WR_REG_MR
RDMA/erdma: Use IRQ-safe XArray helpers for QP and CQ tables
RDMA/mad: Fix receive buffer leak when PKey enforcement fails
RDMA/uverbs: Fix potential leak of resources->collection in flow_resources_alloc()
RDMA/bnxt_re: Avoid exposing umdbr to userspace
RDMA/rtrs: guard against null kobj name
RDMA/bnxt_re: check create_singlethread_workqueue() in DCB setup
IB/isert: wait for deferred control PDU completions before releasing the connection
IB/iser: reject a remote invalidation of an unregistered direction
RDMA/srp: Fix srp_remove_target()
IB/mlx4: Fix use-after-free on pkey sysfs registration failure
RDMA/uverbs: Fix mmap_lock/disassociation_lock circular dependency
RDMA/core: Reject unregistering netdevs in ib_get_eth_speed
...
This commit is contained in:
@@ -314,10 +314,6 @@ struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq,
|
||||
if (!nlmsg_request)
|
||||
return NULL;
|
||||
|
||||
spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
|
||||
list_add_tail(&nlmsg_request->inprocess_list, &iwpm_nlmsg_req_list);
|
||||
spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
|
||||
|
||||
kref_init(&nlmsg_request->kref);
|
||||
kref_get(&nlmsg_request->kref);
|
||||
nlmsg_request->nlmsg_seq = nlmsg_seq;
|
||||
@@ -326,6 +322,11 @@ struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq,
|
||||
nlmsg_request->err_code = 0;
|
||||
sema_init(&nlmsg_request->sem, 1);
|
||||
down(&nlmsg_request->sem);
|
||||
|
||||
spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
|
||||
list_add_tail(&nlmsg_request->inprocess_list, &iwpm_nlmsg_req_list);
|
||||
spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
|
||||
|
||||
return nlmsg_request;
|
||||
}
|
||||
|
||||
|
||||
@@ -2059,6 +2059,8 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
|
||||
int ret;
|
||||
|
||||
INIT_LIST_HEAD(&mad_recv_wc->rmpp_list);
|
||||
list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list);
|
||||
|
||||
ret = ib_mad_enforce_security(mad_agent_priv,
|
||||
mad_recv_wc->wc->pkey_index);
|
||||
if (ret) {
|
||||
@@ -2067,7 +2069,6 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
|
||||
return;
|
||||
}
|
||||
|
||||
list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list);
|
||||
if (is_kernel_rmpp_data_response(mad_agent_priv, mad_recv_wc)) {
|
||||
spin_lock_irqsave(&mad_agent_priv->lock, flags);
|
||||
mad_send_wr = ib_find_send_mad(mad_agent_priv, mad_recv_wc);
|
||||
|
||||
@@ -69,7 +69,6 @@ void ib_uverbs_release_file(struct kref *ref)
|
||||
|
||||
if (file->disassociate_page)
|
||||
__free_pages(file->disassociate_page, 0);
|
||||
mutex_destroy(&file->disassociation_lock);
|
||||
mutex_destroy(&file->umap_lock);
|
||||
mutex_destroy(&file->ucontext_lock);
|
||||
kfree(file);
|
||||
|
||||
@@ -1556,9 +1556,10 @@ static ssize_t ucma_process_join(struct ucma_file *file,
|
||||
mutex_lock(&ctx->mutex);
|
||||
ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *)&mc->addr,
|
||||
join_state, mc);
|
||||
mutex_unlock(&ctx->mutex);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
mutex_unlock(&ctx->mutex);
|
||||
goto err_xa_erase;
|
||||
}
|
||||
|
||||
resp.id = mc->id;
|
||||
if (copy_to_user(u64_to_user_ptr(cmd->response),
|
||||
@@ -1566,6 +1567,7 @@ static ssize_t ucma_process_join(struct ucma_file *file,
|
||||
ret = -EFAULT;
|
||||
goto err_leave_multicast;
|
||||
}
|
||||
mutex_unlock(&ctx->mutex);
|
||||
|
||||
xa_store(&multicast_table, mc->id, mc, 0);
|
||||
|
||||
@@ -1573,7 +1575,6 @@ static ssize_t ucma_process_join(struct ucma_file *file,
|
||||
return 0;
|
||||
|
||||
err_leave_multicast:
|
||||
mutex_lock(&ctx->mutex);
|
||||
rdma_leave_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr);
|
||||
mutex_unlock(&ctx->mutex);
|
||||
ucma_cleanup_mc_events(mc);
|
||||
|
||||
@@ -26,6 +26,7 @@ out:
|
||||
return resources;
|
||||
|
||||
err:
|
||||
kfree(resources->collection);
|
||||
kfree(resources->counters);
|
||||
kfree(resources);
|
||||
|
||||
|
||||
@@ -644,12 +644,15 @@ static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&file->disassociation_lock);
|
||||
if (!down_read_trylock(&file->hw_destroy_rwsem)) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
vma->vm_ops = &rdma_umap_ops;
|
||||
ret = ucontext->device->ops.mmap(ucontext, vma);
|
||||
|
||||
mutex_unlock(&file->disassociation_lock);
|
||||
up_read(&file->hw_destroy_rwsem);
|
||||
out:
|
||||
srcu_read_unlock(&file->device->disassociate_srcu, srcu_key);
|
||||
return ret;
|
||||
@@ -671,7 +674,6 @@ static void rdma_umap_open(struct vm_area_struct *vma)
|
||||
/* We are racing with disassociation */
|
||||
if (!down_read_trylock(&ufile->hw_destroy_rwsem))
|
||||
goto out_zap;
|
||||
mutex_lock(&ufile->disassociation_lock);
|
||||
|
||||
/*
|
||||
* Disassociation already completed, the VMA should already be zapped.
|
||||
@@ -684,12 +686,10 @@ static void rdma_umap_open(struct vm_area_struct *vma)
|
||||
goto out_unlock;
|
||||
rdma_umap_priv_init(priv, vma, opriv->entry);
|
||||
|
||||
mutex_unlock(&ufile->disassociation_lock);
|
||||
up_read(&ufile->hw_destroy_rwsem);
|
||||
return;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&ufile->disassociation_lock);
|
||||
up_read(&ufile->hw_destroy_rwsem);
|
||||
out_zap:
|
||||
/*
|
||||
@@ -773,7 +773,7 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile)
|
||||
{
|
||||
struct rdma_umap_priv *priv, *next_priv;
|
||||
|
||||
mutex_lock(&ufile->disassociation_lock);
|
||||
lockdep_assert_held_write(&ufile->hw_destroy_rwsem);
|
||||
|
||||
while (1) {
|
||||
struct mm_struct *mm = NULL;
|
||||
@@ -799,10 +799,8 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile)
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&ufile->umap_lock);
|
||||
if (!mm) {
|
||||
mutex_unlock(&ufile->disassociation_lock);
|
||||
if (!mm)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The umap_lock is nested under mmap_lock since it used within
|
||||
@@ -832,8 +830,6 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile)
|
||||
mmap_read_unlock(mm);
|
||||
mmput(mm);
|
||||
}
|
||||
|
||||
mutex_unlock(&ufile->disassociation_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -851,8 +847,11 @@ void rdma_user_mmap_disassociate(struct ib_device *device)
|
||||
|
||||
mutex_lock(&uverbs_dev->lists_mutex);
|
||||
list_for_each_entry(ufile, &uverbs_dev->uverbs_file_list, list) {
|
||||
if (ufile->ucontext)
|
||||
if (ufile->ucontext) {
|
||||
down_write(&ufile->hw_destroy_rwsem);
|
||||
uverbs_user_mmap_disassociate(ufile);
|
||||
up_write(&ufile->hw_destroy_rwsem);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&uverbs_dev->lists_mutex);
|
||||
}
|
||||
@@ -927,8 +926,6 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp)
|
||||
mutex_init(&file->umap_lock);
|
||||
INIT_LIST_HEAD(&file->umaps);
|
||||
|
||||
mutex_init(&file->disassociation_lock);
|
||||
|
||||
filp->private_data = file;
|
||||
list_add_tail(&file->list, &dev->uverbs_file_list);
|
||||
mutex_unlock(&dev->lists_mutex);
|
||||
|
||||
@@ -2058,11 +2058,13 @@ int ib_get_eth_speed(struct ib_device *dev, u32 port_num, u16 *speed, u8 *width)
|
||||
return -ENODEV;
|
||||
|
||||
rtnl_lock();
|
||||
if (READ_ONCE(netdev->reg_state) != NETREG_REGISTERED) {
|
||||
dev_put(netdev);
|
||||
rtnl_unlock();
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = __ethtool_get_link_ksettings(netdev, &lksettings);
|
||||
rtnl_unlock();
|
||||
|
||||
dev_put(netdev);
|
||||
|
||||
if (!rc && lksettings.base.speed != (u32)SPEED_UNKNOWN) {
|
||||
netdev_speed = lksettings.base.speed;
|
||||
} else {
|
||||
@@ -2071,6 +2073,8 @@ int ib_get_eth_speed(struct ib_device *dev, u32 port_num, u16 *speed, u8 *width)
|
||||
pr_warn("%s speed is unknown, defaulting to %u\n",
|
||||
netdev->name, netdev_speed);
|
||||
}
|
||||
dev_put(netdev);
|
||||
rtnl_unlock();
|
||||
|
||||
ib_get_width_and_speed(netdev_speed, lksettings.lanes,
|
||||
speed, width);
|
||||
|
||||
@@ -356,9 +356,13 @@ static int bnxt_re_update_qp1_tos_dscp(struct bnxt_re_dev *rdev)
|
||||
return bnxt_qplib_modify_qp(&rdev->qplib_res, &qp->qplib_qp);
|
||||
}
|
||||
|
||||
static void bnxt_re_init_dcb_wq(struct bnxt_re_dev *rdev)
|
||||
static int bnxt_re_init_dcb_wq(struct bnxt_re_dev *rdev)
|
||||
{
|
||||
rdev->dcb_wq = create_singlethread_workqueue("bnxt_re_dcb_wq");
|
||||
if (!rdev->dcb_wq)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bnxt_re_uninit_dcb_wq(struct bnxt_re_dev *rdev)
|
||||
@@ -2339,7 +2343,9 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 op_type)
|
||||
}
|
||||
bnxt_re_debugfs_add_pdev(rdev);
|
||||
|
||||
bnxt_re_init_dcb_wq(rdev);
|
||||
rc = bnxt_re_init_dcb_wq(rdev);
|
||||
if (rc)
|
||||
goto fail;
|
||||
bnxt_re_net_register_async_event(rdev);
|
||||
|
||||
if (!rdev->is_virtfn)
|
||||
|
||||
@@ -462,7 +462,6 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_DBR_ALLOC)(struct uverbs_attr_bundle *a
|
||||
uobj->object = obj;
|
||||
uverbs_finalize_uobj_create(attrs, BNXT_RE_ALLOC_DBR_HANDLE);
|
||||
|
||||
dbr.umdbr = dpi->umdbr;
|
||||
dbr.dpi = dpi->dpi;
|
||||
ret = uverbs_copy_to_struct_or_zero(attrs, BNXT_RE_ALLOC_DBR_ATTR,
|
||||
&dbr, sizeof(dbr));
|
||||
@@ -525,7 +524,6 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_DEFAULT_DBR)(struct uverbs_attr_bun
|
||||
return PTR_ERR(ib_uctx);
|
||||
|
||||
uctx = container_of(ib_uctx, struct bnxt_re_ucontext, ib_uctx);
|
||||
dpi.umdbr = uctx->dpi.umdbr;
|
||||
dpi.dpi = uctx->dpi.dpi;
|
||||
|
||||
ret = uverbs_copy_to_struct_or_zero(attrs, BNXT_RE_DEFAULT_DBR_ATTR,
|
||||
@@ -543,7 +541,7 @@ DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_DBR_ALLOC,
|
||||
UA_MANDATORY),
|
||||
UVERBS_ATTR_PTR_OUT(BNXT_RE_ALLOC_DBR_ATTR,
|
||||
UVERBS_ATTR_STRUCT(struct bnxt_re_db_region,
|
||||
umdbr),
|
||||
reserved2),
|
||||
UA_MANDATORY),
|
||||
UVERBS_ATTR_PTR_OUT(BNXT_RE_ALLOC_DBR_OFFSET,
|
||||
UVERBS_ATTR_TYPE(u64),
|
||||
@@ -563,7 +561,7 @@ DECLARE_UVERBS_NAMED_OBJECT(BNXT_RE_OBJECT_DBR,
|
||||
DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_GET_DEFAULT_DBR,
|
||||
UVERBS_ATTR_PTR_OUT(BNXT_RE_DEFAULT_DBR_ATTR,
|
||||
UVERBS_ATTR_STRUCT(struct bnxt_re_db_region,
|
||||
umdbr),
|
||||
reserved2),
|
||||
UA_MANDATORY));
|
||||
|
||||
DECLARE_UVERBS_GLOBAL_METHODS(BNXT_RE_OBJECT_DEFAULT_DBR,
|
||||
|
||||
@@ -850,7 +850,7 @@ int efa_com_admin_init(struct efa_com_dev *edev,
|
||||
|
||||
aq->dmadev = edev->dmadev;
|
||||
aq->efa_dev = edev->efa_dev;
|
||||
set_bit(EFA_AQ_STATE_POLLING_BIT, &aq->state);
|
||||
efa_com_set_admin_polling_mode(edev, true);
|
||||
|
||||
sema_init(&aq->avail_cmds, aq->depth);
|
||||
|
||||
@@ -868,8 +868,6 @@ int efa_com_admin_init(struct efa_com_dev *edev,
|
||||
if (err)
|
||||
goto err_destroy_sq;
|
||||
|
||||
efa_com_set_admin_polling_mode(edev, false);
|
||||
|
||||
err = efa_com_admin_init_aenq(edev, aenq_handlers);
|
||||
if (err)
|
||||
goto err_destroy_cq;
|
||||
@@ -1254,7 +1252,7 @@ static void efa_com_destroy_eq(struct efa_com_dev *edev,
|
||||
err);
|
||||
}
|
||||
|
||||
static void efa_com_arm_eq(struct efa_com_dev *edev, struct efa_com_eq *eeq)
|
||||
void efa_com_arm_eq(struct efa_com_dev *edev, struct efa_com_eq *eeq)
|
||||
{
|
||||
u32 val = 0;
|
||||
|
||||
@@ -1343,7 +1341,6 @@ int efa_com_eq_init(struct efa_com_dev *edev, struct efa_com_eq *eeq,
|
||||
eeq->phase = 1;
|
||||
eeq->depth = params.depth;
|
||||
eeq->cb = cb;
|
||||
efa_com_arm_eq(edev, eeq);
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -169,6 +169,7 @@ int efa_com_admin_init(struct efa_com_dev *edev,
|
||||
void efa_com_admin_destroy(struct efa_com_dev *edev);
|
||||
int efa_com_eq_init(struct efa_com_dev *edev, struct efa_com_eq *eeq,
|
||||
efa_eqe_handler cb, u16 depth, u8 msix_vec);
|
||||
void efa_com_arm_eq(struct efa_com_dev *edev, struct efa_com_eq *eeq);
|
||||
void efa_com_eq_destroy(struct efa_com_dev *edev, struct efa_com_eq *eeq);
|
||||
int efa_com_dev_reset(struct efa_com_dev *edev,
|
||||
enum efa_regs_reset_reason_types reset_reason);
|
||||
|
||||
@@ -302,28 +302,30 @@ static void efa_set_host_info(struct efa_dev *dev)
|
||||
|
||||
static void efa_destroy_eq(struct efa_dev *dev, struct efa_eq *eq)
|
||||
{
|
||||
efa_com_eq_destroy(&dev->edev, &eq->eeq);
|
||||
efa_free_irq(dev, &eq->irq);
|
||||
efa_com_eq_destroy(&dev->edev, &eq->eeq);
|
||||
}
|
||||
|
||||
static int efa_create_eq(struct efa_dev *dev, struct efa_eq *eq, u32 msix_vec)
|
||||
{
|
||||
int err;
|
||||
|
||||
efa_setup_comp_irq(dev, eq, msix_vec);
|
||||
err = efa_request_irq(dev, &eq->irq);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = efa_com_eq_init(&dev->edev, &eq->eeq, efa_process_eqe,
|
||||
dev->dev_attr.max_eq_depth, msix_vec);
|
||||
if (err)
|
||||
goto err_free_comp_irq;
|
||||
return err;
|
||||
|
||||
efa_setup_comp_irq(dev, eq, msix_vec);
|
||||
err = efa_request_irq(dev, &eq->irq);
|
||||
if (err)
|
||||
goto err_destroy_eq;
|
||||
|
||||
efa_com_arm_eq(&dev->edev, &eq->eeq);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_comp_irq:
|
||||
efa_free_irq(dev, &eq->irq);
|
||||
err_destroy_eq:
|
||||
efa_com_eq_destroy(&dev->edev, &eq->eeq);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -619,18 +621,21 @@ static struct efa_dev *efa_probe_device(struct pci_dev *pdev)
|
||||
edev->aq.msix_vector_idx = dev->admin_msix_vector_idx;
|
||||
edev->aenq.msix_vector_idx = dev->admin_msix_vector_idx;
|
||||
|
||||
err = efa_set_mgmnt_irq(dev);
|
||||
err = efa_com_admin_init(edev, &aenq_handlers);
|
||||
if (err)
|
||||
goto err_disable_msix;
|
||||
|
||||
err = efa_com_admin_init(edev, &aenq_handlers);
|
||||
err = efa_set_mgmnt_irq(dev);
|
||||
if (err)
|
||||
goto err_free_mgmnt_irq;
|
||||
goto err_destroy_admin;
|
||||
|
||||
efa_com_set_admin_polling_mode(edev, false);
|
||||
|
||||
return dev;
|
||||
|
||||
err_free_mgmnt_irq:
|
||||
efa_free_irq(dev, &dev->admin_irq);
|
||||
err_destroy_admin:
|
||||
efa_com_dev_reset(edev, EFA_REGS_RESET_INIT_ERR);
|
||||
efa_com_admin_destroy(edev);
|
||||
err_disable_msix:
|
||||
efa_disable_msix(dev);
|
||||
err_reg_read_destroy:
|
||||
@@ -654,8 +659,8 @@ static void efa_remove_device(struct pci_dev *pdev,
|
||||
|
||||
edev = &dev->edev;
|
||||
efa_com_dev_reset(edev, reset_reason);
|
||||
efa_com_admin_destroy(edev);
|
||||
efa_free_irq(dev, &dev->admin_irq);
|
||||
efa_com_admin_destroy(edev);
|
||||
efa_disable_msix(dev);
|
||||
efa_com_mmio_reg_read_destroy(edev);
|
||||
devm_iounmap(&pdev->dev, edev->reg_bar);
|
||||
|
||||
@@ -572,8 +572,8 @@ static int erdma_ib_device_add(struct pci_dev *pdev)
|
||||
INIT_LIST_HEAD(&dev->cep_list);
|
||||
|
||||
spin_lock_init(&dev->lock);
|
||||
xa_init_flags(&dev->qp_xa, XA_FLAGS_ALLOC1);
|
||||
xa_init_flags(&dev->cq_xa, XA_FLAGS_ALLOC1);
|
||||
xa_init_flags(&dev->qp_xa, XA_FLAGS_ALLOC1 | XA_FLAGS_LOCK_IRQ);
|
||||
xa_init_flags(&dev->cq_xa, XA_FLAGS_ALLOC1 | XA_FLAGS_LOCK_IRQ);
|
||||
dev->next_alloc_cqn = 1;
|
||||
dev->next_alloc_qpn = 1;
|
||||
|
||||
|
||||
@@ -1021,15 +1021,15 @@ int erdma_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
|
||||
init_completion(&qp->safe_free);
|
||||
|
||||
if (qp->ibqp.qp_type == IB_QPT_GSI) {
|
||||
old_entry = xa_store(&dev->qp_xa, 1, qp, GFP_KERNEL);
|
||||
old_entry = xa_store_irq(&dev->qp_xa, 1, qp, GFP_KERNEL);
|
||||
if (xa_is_err(old_entry))
|
||||
ret = xa_err(old_entry);
|
||||
else
|
||||
qp->ibqp.qp_num = 1;
|
||||
} else {
|
||||
ret = xa_alloc_cyclic(&dev->qp_xa, &qp->ibqp.qp_num, qp,
|
||||
XA_LIMIT(1, dev->attrs.max_qp - 1),
|
||||
&dev->next_alloc_qpn, GFP_KERNEL);
|
||||
ret = xa_alloc_cyclic_irq(&dev->qp_xa, &qp->ibqp.qp_num, qp,
|
||||
XA_LIMIT(1, dev->attrs.max_qp - 1),
|
||||
&dev->next_alloc_qpn, GFP_KERNEL);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
@@ -1089,7 +1089,7 @@ err_out_cmd:
|
||||
else
|
||||
free_kernel_qp(qp);
|
||||
err_out_xa:
|
||||
xa_erase(&dev->qp_xa, QP_ID(qp));
|
||||
xa_erase_irq(&dev->qp_xa, QP_ID(qp));
|
||||
err_out:
|
||||
return ret;
|
||||
}
|
||||
@@ -1993,9 +1993,9 @@ int erdma_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
|
||||
refcount_set(&cq->refcount, 1);
|
||||
init_completion(&cq->free);
|
||||
|
||||
ret = xa_alloc_cyclic(&dev->cq_xa, &cq->cqn, cq,
|
||||
XA_LIMIT(1, dev->attrs.max_cq - 1),
|
||||
&dev->next_alloc_cqn, GFP_KERNEL);
|
||||
ret = xa_alloc_cyclic_irq(&dev->cq_xa, &cq->cqn, cq,
|
||||
XA_LIMIT(1, dev->attrs.max_cq - 1),
|
||||
&dev->next_alloc_cqn, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -2041,7 +2041,7 @@ err_free_res:
|
||||
}
|
||||
|
||||
err_out_xa:
|
||||
xa_erase(&dev->cq_xa, cq->cqn);
|
||||
xa_erase_irq(&dev->cq_xa, cq->cqn);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -326,6 +326,7 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
|
||||
void *memvirt = NULL;
|
||||
dma_addr_t memdma = 0;
|
||||
u8 subctxt, mapio = 0, vmf = 0, type;
|
||||
size_t memdmalen = 0;
|
||||
ssize_t memlen = 0;
|
||||
int ret = 0;
|
||||
u16 ctxt;
|
||||
@@ -371,7 +372,9 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
|
||||
mapio = 1;
|
||||
break;
|
||||
case PIO_CRED: {
|
||||
struct credit_return_base *cr = &dd->cr_base[uctxt->sc->node];
|
||||
u64 cr_page_offset;
|
||||
|
||||
if (flags & VM_WRITE) {
|
||||
ret = -EPERM;
|
||||
goto done;
|
||||
@@ -381,11 +384,18 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
|
||||
* second or third page allocated for credit returns (if number
|
||||
* of enabled contexts > 64 and 128 respectively).
|
||||
*/
|
||||
cr_page_offset = ((u64)uctxt->sc->hw_free -
|
||||
(u64)dd->cr_base[uctxt->numa_id].va) &
|
||||
PAGE_MASK;
|
||||
memvirt = dd->cr_base[uctxt->numa_id].va + cr_page_offset;
|
||||
memdma = dd->cr_base[uctxt->numa_id].dma + cr_page_offset;
|
||||
cr_page_offset = ((u64)uctxt->sc->hw_free - (u64)cr->va) &
|
||||
PAGE_MASK;
|
||||
/*
|
||||
* dma_mmap_coherent() describes the whole coherent buffer and
|
||||
* selects the page within it with vma->vm_pgoff, so pass the
|
||||
* base of the allocation and its length and let vm_pgoff pick
|
||||
* the page.
|
||||
*/
|
||||
vma->vm_pgoff = cr_page_offset >> PAGE_SHIFT;
|
||||
memvirt = cr->va;
|
||||
memdma = cr->dma;
|
||||
memdmalen = TXE_NUM_CONTEXTS * sizeof(struct credit_return);
|
||||
memlen = PAGE_SIZE;
|
||||
flags &= ~VM_MAYWRITE;
|
||||
flags |= VM_DONTCOPY | VM_DONTEXPAND;
|
||||
@@ -567,7 +577,8 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma)
|
||||
ret = 0;
|
||||
} else if (memdma) {
|
||||
ret = dma_mmap_coherent(&dd->pcidev->dev, vma,
|
||||
memvirt, memdma, memlen);
|
||||
memvirt, memdma,
|
||||
memdmalen ? memdmalen : memlen);
|
||||
} else if (mapio) {
|
||||
ret = io_remap_pfn_range(vma, vma->vm_start,
|
||||
PFN_DOWN(memaddr),
|
||||
|
||||
@@ -4281,7 +4281,7 @@ static int irdma_post_send(struct ib_qp *ibqp,
|
||||
stag_info.total_len = iwmr->ibmr.length;
|
||||
stag_info.reg_addr_pa = *palloc->level1.addr;
|
||||
stag_info.first_pm_pbl_index = palloc->level1.idx;
|
||||
stag_info.local_fence = ib_wr->send_flags & IB_SEND_FENCE;
|
||||
stag_info.local_fence = true;
|
||||
if (iwmr->npages > IRDMA_MIN_PAGES_PER_FMR)
|
||||
stag_info.chunk_size = 1;
|
||||
err = irdma_sc_mr_fast_register(&iwqp->sc_qp, &stag_info,
|
||||
|
||||
@@ -751,11 +751,13 @@ err_add:
|
||||
kobject_put(p);
|
||||
}
|
||||
kobject_put(dev->dev_ports_parent[slave]);
|
||||
dev->dev_ports_parent[slave] = NULL;
|
||||
|
||||
err_ports:
|
||||
kobject_put(dev->pkeys.device_parent[slave]);
|
||||
/* extra put for the device_parent create_and_add */
|
||||
kobject_put(dev->pkeys.device_parent[slave]);
|
||||
dev->pkeys.device_parent[slave] = NULL;
|
||||
|
||||
fail_dev:
|
||||
kobject_put(dev->iov_parent);
|
||||
@@ -785,6 +787,8 @@ static void unregister_pkey_tree(struct mlx4_ib_dev *device)
|
||||
return;
|
||||
|
||||
for (slave = device->dev->persist->num_vfs; slave >= 0; --slave) {
|
||||
if (!device->pkeys.device_parent[slave])
|
||||
continue;
|
||||
list_for_each_entry_safe(p, t,
|
||||
&device->pkeys.pkey_port_list[slave],
|
||||
entry) {
|
||||
|
||||
@@ -1683,11 +1683,8 @@ static int mlx5_ib_query_port_speed_rep(struct mlx5_ib_dev *dev, u32 port_num,
|
||||
struct mlx5_core_dev *mdev;
|
||||
u16 op_mod;
|
||||
|
||||
if (!dev->port[port_num - 1].rep) {
|
||||
mlx5_ib_warn(dev, "Representor doesn't exist for port %u\n",
|
||||
port_num);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!dev->port[port_num - 1].rep)
|
||||
return -ENODEV;
|
||||
|
||||
rep = dev->port[port_num - 1].rep;
|
||||
mdev = mlx5_eswitch_get_core_dev(rep->esw);
|
||||
|
||||
@@ -175,7 +175,9 @@ struct rxe_mcg *rxe_lookup_mcg(struct rxe_dev *rxe, union ib_gid *mgid)
|
||||
* @mgid: multicast address as a gid
|
||||
* @mcg: new mcg object
|
||||
*
|
||||
* Context: caller should hold rxe->mcg lock
|
||||
* Initializes the mcg fields. The mcg is private and not yet visible in
|
||||
* mcg_tree, so this may run without rxe->mcg_lock; __rxe_publish_mcg()
|
||||
* makes it visible under the lock once it is ready.
|
||||
*/
|
||||
static void __rxe_init_mcg(struct rxe_dev *rxe, union ib_gid *mgid,
|
||||
struct rxe_mcg *mcg)
|
||||
@@ -184,13 +186,22 @@ static void __rxe_init_mcg(struct rxe_dev *rxe, union ib_gid *mgid,
|
||||
memcpy(&mcg->mgid, mgid, sizeof(mcg->mgid));
|
||||
INIT_LIST_HEAD(&mcg->qp_list);
|
||||
mcg->rxe = rxe;
|
||||
}
|
||||
|
||||
/* caller holds a ref on mcg but that will be
|
||||
* dropped when mcg goes out of scope. We need to take a ref
|
||||
* on the pointer that will be saved in the red-black tree
|
||||
* by __rxe_insert_mcg and used to lookup mcg from mgid later.
|
||||
* Inserting mcg makes it visible to outside so this should
|
||||
* be done last after the object is ready.
|
||||
/**
|
||||
* __rxe_publish_mcg - make a fully initialized mcg visible in mcg_tree
|
||||
* @mcg: the mcg object
|
||||
*
|
||||
* Context: caller must hold rxe->mcg_lock and a reference on mcg
|
||||
*/
|
||||
static void __rxe_publish_mcg(struct rxe_mcg *mcg)
|
||||
{
|
||||
/* caller holds a ref on mcg but that will be dropped when mcg goes
|
||||
* out of scope. We need to take a ref on the pointer that will be
|
||||
* saved in the red-black tree by __rxe_insert_mcg and used to lookup
|
||||
* mcg from mgid later. Inserting mcg makes it visible to outside so
|
||||
* this is done last after the object is ready and the multicast
|
||||
* address has been programmed.
|
||||
*/
|
||||
kref_get(&mcg->ref_cnt);
|
||||
__rxe_insert_mcg(mcg);
|
||||
@@ -228,26 +239,37 @@ static struct rxe_mcg *rxe_get_mcg(struct rxe_dev *rxe, union ib_gid *mgid)
|
||||
err = -ENOMEM;
|
||||
goto err_dec;
|
||||
}
|
||||
__rxe_init_mcg(rxe, mgid, mcg);
|
||||
|
||||
/* program the multicast address while mcg is still private, before
|
||||
* it is inserted into mcg_tree. dev_mc_add() may sleep so this must
|
||||
* run outside mcg_lock. On failure mcg was never published, so a
|
||||
* plain free is correct and the tree is untouched.
|
||||
*/
|
||||
err = rxe_mcast_add(rxe, mgid);
|
||||
if (err) {
|
||||
kfree(mcg);
|
||||
goto err_dec;
|
||||
}
|
||||
|
||||
spin_lock_bh(&rxe->mcg_lock);
|
||||
/* re-check to see if someone else just added it */
|
||||
/* re-check to see if someone else just added it while we were adding
|
||||
* the multicast address; if so use theirs and drop ours
|
||||
*/
|
||||
tmp = __rxe_lookup_mcg(rxe, mgid);
|
||||
if (tmp) {
|
||||
spin_unlock_bh(&rxe->mcg_lock);
|
||||
rxe_mcast_del(rxe, mgid);
|
||||
atomic_dec(&rxe->mcg_num);
|
||||
kfree(mcg);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
__rxe_init_mcg(rxe, mgid, mcg);
|
||||
__rxe_publish_mcg(mcg);
|
||||
spin_unlock_bh(&rxe->mcg_lock);
|
||||
|
||||
/* add mcast address outside of lock */
|
||||
err = rxe_mcast_add(rxe, mgid);
|
||||
if (!err)
|
||||
return mcg;
|
||||
return mcg;
|
||||
|
||||
kfree(mcg);
|
||||
err_dec:
|
||||
atomic_dec(&rxe->mcg_num);
|
||||
return ERR_PTR(err);
|
||||
|
||||
@@ -33,7 +33,8 @@ int mr_check_range(struct rxe_mr *mr, u64 iova, size_t length)
|
||||
case IB_MR_TYPE_USER:
|
||||
case IB_MR_TYPE_MEM_REG:
|
||||
if (iova < mr->ibmr.iova ||
|
||||
iova + length > mr->ibmr.iova + mr->ibmr.length) {
|
||||
length > mr->ibmr.length ||
|
||||
iova - mr->ibmr.iova > mr->ibmr.length - length) {
|
||||
rxe_dbg_mr(mr, "iova/length out of range\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -120,19 +120,23 @@ int rxe_odp_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length,
|
||||
}
|
||||
|
||||
static inline bool rxe_check_pagefault(struct ib_umem_odp *umem_odp, u64 iova,
|
||||
int length)
|
||||
int length, bool write)
|
||||
{
|
||||
bool need_fault = false;
|
||||
u64 access = HMM_PFN_VALID;
|
||||
u64 addr;
|
||||
int idx;
|
||||
|
||||
if (write)
|
||||
access |= HMM_PFN_WRITE;
|
||||
|
||||
addr = iova & (~(BIT(umem_odp->page_shift) - 1));
|
||||
|
||||
/* Skim through all pages that are to be accessed. */
|
||||
while (addr < iova + length) {
|
||||
idx = (addr - ib_umem_start(umem_odp)) >> umem_odp->page_shift;
|
||||
|
||||
if (!(umem_odp->map.pfn_list[idx] & HMM_PFN_VALID)) {
|
||||
if ((umem_odp->map.pfn_list[idx] & access) != access) {
|
||||
need_fault = true;
|
||||
break;
|
||||
}
|
||||
@@ -155,6 +159,7 @@ static unsigned long rxe_odp_iova_to_page_offset(struct ib_umem_odp *umem_odp, u
|
||||
static int rxe_odp_map_range_and_lock(struct rxe_mr *mr, u64 iova, int length, u32 flags)
|
||||
{
|
||||
struct ib_umem_odp *umem_odp = to_ib_umem_odp(mr->umem);
|
||||
bool write = !(flags & RXE_PAGEFAULT_RDONLY);
|
||||
bool need_fault;
|
||||
int err;
|
||||
|
||||
@@ -163,7 +168,7 @@ static int rxe_odp_map_range_and_lock(struct rxe_mr *mr, u64 iova, int length, u
|
||||
|
||||
mutex_lock(&umem_odp->umem_mutex);
|
||||
|
||||
need_fault = rxe_check_pagefault(umem_odp, iova, length);
|
||||
need_fault = rxe_check_pagefault(umem_odp, iova, length, write);
|
||||
if (need_fault) {
|
||||
mutex_unlock(&umem_odp->umem_mutex);
|
||||
|
||||
@@ -173,7 +178,7 @@ static int rxe_odp_map_range_and_lock(struct rxe_mr *mr, u64 iova, int length, u
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
need_fault = rxe_check_pagefault(umem_odp, iova, length);
|
||||
need_fault = rxe_check_pagefault(umem_odp, iova, length, write);
|
||||
if (need_fault) {
|
||||
mutex_unlock(&umem_odp->umem_mutex);
|
||||
return -EFAULT;
|
||||
@@ -335,8 +340,9 @@ int rxe_odp_flush_pmem_iova(struct rxe_mr *mr, u64 iova,
|
||||
int err;
|
||||
u8 *va;
|
||||
|
||||
/* A flush never modifies memory; read-only access suffices. */
|
||||
err = rxe_odp_map_range_and_lock(mr, iova, length,
|
||||
RXE_PAGEFAULT_DEFAULT);
|
||||
RXE_PAGEFAULT_RDONLY);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
||||
@@ -1331,19 +1331,20 @@ static struct ib_mr *rxe_rereg_user_mr(struct ib_mr *ibmr, int flags,
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
if ((flags & IB_MR_REREG_ACCESS) &&
|
||||
(access & ~RXE_ACCESS_SUPPORTED_MR)) {
|
||||
rxe_err_mr(mr, "access = %#x not supported\n", access);
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
if (flags & IB_MR_REREG_PD) {
|
||||
rxe_put(old_pd);
|
||||
rxe_get(pd);
|
||||
mr->ibmr.pd = ibpd;
|
||||
}
|
||||
|
||||
if (flags & IB_MR_REREG_ACCESS) {
|
||||
if (access & ~RXE_ACCESS_SUPPORTED_MR) {
|
||||
rxe_err_mr(mr, "access = %#x not supported\n", access);
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
if (flags & IB_MR_REREG_ACCESS)
|
||||
mr->access = access;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1719,9 +1719,12 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
|
||||
SIW_QP_ATTR_STATE | SIW_QP_ATTR_LLP_HANDLE |
|
||||
SIW_QP_ATTR_ORD | SIW_QP_ATTR_IRD |
|
||||
SIW_QP_ATTR_MPA);
|
||||
if (rv) {
|
||||
qp->cep = NULL;
|
||||
siw_cep_put(cep);
|
||||
goto error_unlock;
|
||||
}
|
||||
up_write(&qp->state_lock);
|
||||
if (rv)
|
||||
goto error;
|
||||
|
||||
siw_dbg_cep(cep, "[QP %u]: send mpa reply, %d byte pdata\n",
|
||||
qp_id(qp), params->private_data_len);
|
||||
|
||||
@@ -1079,7 +1079,7 @@ static int siw_get_hdr(struct siw_rx_stream *srx)
|
||||
if (iwarp_pktinfo[opcode].hdr_len > sizeof(struct iwarp_ctrl_tagged)) {
|
||||
int hdrlen = iwarp_pktinfo[opcode].hdr_len;
|
||||
|
||||
bytes = min_t(int, hdrlen - MIN_DDP_HDR, srx->skb_new);
|
||||
bytes = min_t(int, hdrlen - srx->fpdu_part_rcvd, srx->skb_new);
|
||||
|
||||
skb_copy_bits(skb, srx->skb_offset,
|
||||
(char *)c_hdr + srx->fpdu_part_rcvd, bytes);
|
||||
|
||||
@@ -87,6 +87,7 @@ enum {
|
||||
IPOIB_FLAG_INITIALIZED = 1,
|
||||
IPOIB_FLAG_ADMIN_UP = 2,
|
||||
IPOIB_PKEY_ASSIGNED = 3,
|
||||
IPOIB_FLAG_MCAST_FLUSH = 4,
|
||||
IPOIB_FLAG_SUBINTERFACE = 5,
|
||||
IPOIB_STOP_REAPER = 7,
|
||||
IPOIB_FLAG_ADMIN_CM = 9,
|
||||
@@ -414,6 +415,12 @@ struct ipoib_dev_priv {
|
||||
const struct net_device_ops *rn_ops;
|
||||
};
|
||||
|
||||
static inline bool ipoib_mcast_allowed(struct ipoib_dev_priv *priv)
|
||||
{
|
||||
return test_bit(IPOIB_FLAG_OPER_UP, &priv->flags) &&
|
||||
!test_bit(IPOIB_FLAG_MCAST_FLUSH, &priv->flags);
|
||||
}
|
||||
|
||||
struct ipoib_ah {
|
||||
struct net_device *dev;
|
||||
struct ib_ah *ah;
|
||||
|
||||
@@ -1227,17 +1227,19 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
|
||||
}
|
||||
|
||||
if (level == IPOIB_FLUSH_LIGHT) {
|
||||
int oper_up;
|
||||
ipoib_mark_paths_invalid(dev);
|
||||
/* Set IPoIB operation as down to prevent races between:
|
||||
/* Set MCAST_FLUSH to prevent races between:
|
||||
* the flush flow which leaves MCG and on the fly joins
|
||||
* which can happen during that time. mcast restart task
|
||||
* should deal with join requests we missed.
|
||||
*
|
||||
* Do not clear OPER_UP for this; restoring it races with
|
||||
* ipoib_ib_dev_down() and can leave OPER_UP set after the
|
||||
* device is down.
|
||||
*/
|
||||
oper_up = test_and_clear_bit(IPOIB_FLAG_OPER_UP, &priv->flags);
|
||||
set_bit(IPOIB_FLAG_MCAST_FLUSH, &priv->flags);
|
||||
ipoib_mcast_dev_flush(dev);
|
||||
if (oper_up)
|
||||
set_bit(IPOIB_FLAG_OPER_UP, &priv->flags);
|
||||
clear_bit(IPOIB_FLAG_MCAST_FLUSH, &priv->flags);
|
||||
ipoib_reap_dead_ahs(priv);
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ static void __ipoib_mcast_schedule_join_thread(struct ipoib_dev_priv *priv,
|
||||
struct ipoib_mcast *mcast,
|
||||
bool delay)
|
||||
{
|
||||
if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags))
|
||||
if (!ipoib_mcast_allowed(priv))
|
||||
return;
|
||||
|
||||
/*
|
||||
@@ -469,7 +469,7 @@ static int ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast)
|
||||
int ret = 0;
|
||||
|
||||
if (!priv->broadcast ||
|
||||
!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags))
|
||||
!ipoib_mcast_allowed(priv))
|
||||
return -EINVAL;
|
||||
|
||||
init_completion(&mcast->done);
|
||||
@@ -555,7 +555,7 @@ void ipoib_mcast_join_task(struct work_struct *work)
|
||||
unsigned long delay_until = 0;
|
||||
struct ipoib_mcast *mcast = NULL;
|
||||
|
||||
if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags))
|
||||
if (!ipoib_mcast_allowed(priv))
|
||||
return;
|
||||
|
||||
if (ib_query_port(priv->ca, priv->port, &port_attr)) {
|
||||
@@ -577,7 +577,7 @@ void ipoib_mcast_join_task(struct work_struct *work)
|
||||
netif_addr_unlock_bh(dev);
|
||||
|
||||
spin_lock_irq(&priv->lock);
|
||||
if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags))
|
||||
if (!ipoib_mcast_allowed(priv))
|
||||
goto out;
|
||||
|
||||
if (!priv->broadcast) {
|
||||
@@ -749,7 +749,7 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb)
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags) ||
|
||||
if (!ipoib_mcast_allowed(priv) ||
|
||||
!priv->broadcast ||
|
||||
!test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) {
|
||||
++dev->stats.tx_dropped;
|
||||
@@ -871,7 +871,7 @@ void ipoib_mcast_restart_task(struct work_struct *work)
|
||||
LIST_HEAD(remove_list);
|
||||
struct ib_sa_mcmember_rec rec;
|
||||
|
||||
if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags))
|
||||
if (!ipoib_mcast_allowed(priv))
|
||||
/*
|
||||
* shortcut...on shutdown flush is called next, just
|
||||
* let it do all the work
|
||||
@@ -965,9 +965,9 @@ void ipoib_mcast_restart_task(struct work_struct *work)
|
||||
ipoib_mcast_remove_list(&remove_list);
|
||||
|
||||
/*
|
||||
* Double check that we are still up
|
||||
* Double check that we are still up and not flushing
|
||||
*/
|
||||
if (test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) {
|
||||
if (ipoib_mcast_allowed(priv)) {
|
||||
spin_lock_irq(&priv->lock);
|
||||
__ipoib_mcast_schedule_join_thread(priv, NULL, 0);
|
||||
spin_unlock_irq(&priv->lock);
|
||||
|
||||
@@ -598,11 +598,8 @@ static int iser_check_remote_inv(struct iser_conn *iser_conn, struct ib_wc *wc,
|
||||
iser_dbg("conn %p: remote invalidation for rkey %#x\n",
|
||||
iser_conn, rkey);
|
||||
|
||||
if (unlikely(!iser_conn->snd_w_inv)) {
|
||||
iser_err("conn %p: unexpected remote invalidation, terminating connection\n",
|
||||
iser_conn);
|
||||
return -EPROTO;
|
||||
}
|
||||
if (unlikely(!iser_conn->snd_w_inv))
|
||||
goto bad_inv;
|
||||
|
||||
task = iscsi_itt_to_ctask(iser_conn->iscsi_conn, hdr->itt);
|
||||
if (likely(task)) {
|
||||
@@ -611,12 +608,16 @@ static int iser_check_remote_inv(struct iser_conn *iser_conn, struct ib_wc *wc,
|
||||
|
||||
if (iser_task->dir[ISER_DIR_IN]) {
|
||||
desc = iser_task->rdma_reg[ISER_DIR_IN].desc;
|
||||
if (unlikely(!desc))
|
||||
goto bad_inv;
|
||||
if (unlikely(iser_inv_desc(desc, rkey)))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (iser_task->dir[ISER_DIR_OUT]) {
|
||||
desc = iser_task->rdma_reg[ISER_DIR_OUT].desc;
|
||||
if (unlikely(!desc))
|
||||
goto bad_inv;
|
||||
if (unlikely(iser_inv_desc(desc, rkey)))
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -627,6 +628,11 @@ static int iser_check_remote_inv(struct iser_conn *iser_conn, struct ib_wc *wc,
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
bad_inv:
|
||||
iser_err("conn %p: unexpected remote invalidation, terminating connection\n",
|
||||
iser_conn);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <target/target_core_fabric.h>
|
||||
#include <target/iscsi/iscsi_transport.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/wait_bit.h>
|
||||
|
||||
#include "ib_isert.h"
|
||||
|
||||
@@ -310,6 +311,7 @@ isert_init_conn(struct isert_conn *isert_conn)
|
||||
init_completion(&isert_conn->login_req_comp);
|
||||
init_waitqueue_head(&isert_conn->rem_wait);
|
||||
kref_init(&isert_conn->kref);
|
||||
atomic_set(&isert_conn->ctrl_comp_cnt, 0);
|
||||
mutex_init(&isert_conn->mutex);
|
||||
INIT_WORK(&isert_conn->release_work, isert_release_work);
|
||||
}
|
||||
@@ -1694,6 +1696,8 @@ isert_do_control_comp(struct work_struct *work)
|
||||
struct isert_conn *isert_conn = isert_cmd->conn;
|
||||
struct ib_device *ib_dev = isert_conn->cm_id->device;
|
||||
struct iscsit_cmd *cmd = isert_cmd->iscsit_cmd;
|
||||
/* The switch below may free isert_cmd. */
|
||||
bool counted = isert_cmd->ctrl_counted;
|
||||
|
||||
isert_dbg("Cmd %p i_state %d\n", isert_cmd, cmd->i_state);
|
||||
|
||||
@@ -1715,6 +1719,14 @@ isert_do_control_comp(struct work_struct *work)
|
||||
dump_stack();
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* The count is what keeps isert_conn alive, so drop it last. The wait
|
||||
* queue lives in the global hash table, not in isert_conn, so this is
|
||||
* safe even if the waiter has already freed the connection.
|
||||
*/
|
||||
if (counted && atomic_dec_and_test(&isert_conn->ctrl_comp_cnt))
|
||||
wake_up_var(&isert_conn->ctrl_comp_cnt);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1758,6 +1770,12 @@ isert_send_done(struct ib_cq *cq, struct ib_wc *wc)
|
||||
case ISTATE_SEND_TEXTRSP:
|
||||
isert_unmap_tx_desc(tx_desc, ib_dev);
|
||||
|
||||
/* Paired with the wait in isert_wait_conn(). */
|
||||
isert_cmd->ctrl_counted =
|
||||
isert_cmd->iscsit_cmd->i_state != ISTATE_SEND_LOGOUTRSP;
|
||||
if (isert_cmd->ctrl_counted)
|
||||
atomic_inc(&isert_conn->ctrl_comp_cnt);
|
||||
|
||||
INIT_WORK(&isert_cmd->comp_work, isert_do_control_comp);
|
||||
queue_work(isert_comp_wq, &isert_cmd->comp_work);
|
||||
return;
|
||||
@@ -2602,6 +2620,10 @@ static void isert_wait_conn(struct iscsit_conn *conn)
|
||||
isert_wait4cmds(conn);
|
||||
isert_wait4logout(isert_conn);
|
||||
|
||||
/* Paired with the count taken in isert_send_done(). */
|
||||
wait_var_event(&isert_conn->ctrl_comp_cnt,
|
||||
!atomic_read(&isert_conn->ctrl_comp_cnt));
|
||||
|
||||
queue_work(isert_release_wq, &isert_conn->release_work);
|
||||
}
|
||||
|
||||
|
||||
@@ -153,6 +153,7 @@ struct isert_cmd {
|
||||
struct work_struct comp_work;
|
||||
struct scatterlist sg;
|
||||
bool ctx_init_done;
|
||||
bool ctrl_counted;
|
||||
};
|
||||
|
||||
static inline struct isert_cmd *tx_desc_to_cmd(struct iser_tx_desc *desc)
|
||||
@@ -187,6 +188,7 @@ struct isert_conn {
|
||||
struct mutex mutex;
|
||||
struct kref kref;
|
||||
struct work_struct release_work;
|
||||
atomic_t ctrl_comp_cnt;
|
||||
bool logout_posted;
|
||||
bool snd_w_inv;
|
||||
wait_queue_head_t rem_wait;
|
||||
|
||||
@@ -55,7 +55,7 @@ DECLARE_EVENT_CLASS(rtrs_clt_conn_class,
|
||||
__entry->max_reconnect_attempts = clt->max_reconnect_attempts;
|
||||
__entry->fail_cnt = clt_path->stats->reconnects.fail_cnt;
|
||||
__entry->success_cnt = clt_path->stats->reconnects.successful_cnt;
|
||||
memcpy(__entry->sessname, kobject_name(&clt_path->kobj), NAME_MAX);
|
||||
strscpy(__entry->sessname, kobject_name(&clt_path->kobj) ?: "", NAME_MAX);
|
||||
),
|
||||
|
||||
TP_printk("RTRS-CLT: sess='%s' state=%s attempts='%d' max-attempts='%d' fail='%d' success='%d'",
|
||||
|
||||
@@ -1732,6 +1732,8 @@ static void destroy_con_cq_qp(struct rtrs_clt_con *con)
|
||||
/*
|
||||
* Be careful here: destroy_con_cq_qp() can be called even
|
||||
* create_con_cq_qp() failed, see comments there.
|
||||
* Caller must set con->destroyed under this lock first so a
|
||||
* racing ADDR_RESOLVED cannot ib_cq_pool_get() after we PUT/SKIP.
|
||||
*/
|
||||
lockdep_assert_held(&con->con_mutex);
|
||||
rtrs_cq_qp_destroy(&con->c);
|
||||
@@ -1766,6 +1768,10 @@ static int rtrs_rdma_addr_resolved(struct rtrs_clt_con *con)
|
||||
int err;
|
||||
|
||||
mutex_lock(&con->con_mutex);
|
||||
if (con->destroyed) {
|
||||
mutex_unlock(&con->con_mutex);
|
||||
return -ECONNABORTED;
|
||||
}
|
||||
err = create_con_cq_qp(con);
|
||||
mutex_unlock(&con->con_mutex);
|
||||
if (err) {
|
||||
@@ -2221,6 +2227,7 @@ static void rtrs_clt_stop_and_destroy_conns(struct rtrs_clt_path *clt_path)
|
||||
break;
|
||||
con = to_clt_con(clt_path->s.con[cid]);
|
||||
mutex_lock(&con->con_mutex);
|
||||
con->destroyed = true;
|
||||
destroy_con_cq_qp(con);
|
||||
mutex_unlock(&con->con_mutex);
|
||||
destroy_cm(con);
|
||||
@@ -2387,6 +2394,7 @@ destroy:
|
||||
if (con->c.cm_id) {
|
||||
stop_cm(con);
|
||||
mutex_lock(&con->con_mutex);
|
||||
con->destroyed = true;
|
||||
destroy_con_cq_qp(con);
|
||||
mutex_unlock(&con->con_mutex);
|
||||
destroy_cm(con);
|
||||
|
||||
@@ -75,6 +75,8 @@ struct rtrs_clt_con {
|
||||
unsigned int cpu;
|
||||
struct mutex con_mutex;
|
||||
int cm_err;
|
||||
/* Set under con_mutex before CQ/QP teardown. */
|
||||
bool destroyed;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,7 +61,7 @@ TRACE_EVENT(send_io_resp_imm,
|
||||
__entry->msg_id = id->msg_id;
|
||||
__entry->wr_cnt = atomic_read(&con->c.wr_cnt);
|
||||
__entry->signal_interval = s->signal_interval;
|
||||
memcpy(__entry->sessname, kobject_name(&srv_path->kobj), NAME_MAX);
|
||||
strscpy(__entry->sessname, kobject_name(&srv_path->kobj) ?: "", NAME_MAX);
|
||||
),
|
||||
|
||||
TP_printk("sess='%s' state='%s' dir=%s err='%d' inval='%d' glob-inval='%d' msgid='%u' wrcnt='%d' sig-interval='%u'",
|
||||
|
||||
@@ -1038,15 +1038,20 @@ static void srp_del_scsi_host_attr(struct Scsi_Host *shost)
|
||||
|
||||
static void srp_remove_target(struct srp_target_port *target)
|
||||
{
|
||||
struct scsi_device *sdev;
|
||||
struct srp_rdma_ch *ch;
|
||||
int i;
|
||||
|
||||
WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED);
|
||||
|
||||
srp_del_scsi_host_attr(target->scsi_host);
|
||||
srp_rport_get(target->rport);
|
||||
srp_remove_host(target->scsi_host);
|
||||
scsi_remove_host(target->scsi_host);
|
||||
/*
|
||||
* Remove all logical units. This must happen before the
|
||||
* srp_disconnect_target() call because scsi_remove_device() may trigger
|
||||
* submission of SCSI commands. See also sd_shutdown().
|
||||
*/
|
||||
shost_for_each_device(sdev, target->scsi_host)
|
||||
scsi_remove_device(sdev);
|
||||
srp_stop_rport_timers(target->rport);
|
||||
srp_disconnect_target(target);
|
||||
kobj_ns_drop(KOBJ_NS_TYPE_NET, to_ns_common(target->net));
|
||||
@@ -1055,7 +1060,8 @@ static void srp_remove_target(struct srp_target_port *target)
|
||||
srp_free_ch_ib(target, ch);
|
||||
}
|
||||
cancel_work_sync(&target->tl_err_work);
|
||||
srp_rport_put(target->rport);
|
||||
srp_remove_host(target->scsi_host);
|
||||
scsi_remove_host(target->scsi_host);
|
||||
kfree(target->ch);
|
||||
target->ch = NULL;
|
||||
|
||||
|
||||
@@ -180,8 +180,6 @@ struct ib_uverbs_file {
|
||||
struct page *disassociate_page;
|
||||
|
||||
struct xarray idr;
|
||||
|
||||
struct mutex disassociation_lock;
|
||||
};
|
||||
|
||||
extern const struct uverbs_obj_type_class uverbs_idr_class;
|
||||
|
||||
@@ -250,7 +250,7 @@ struct bnxt_re_query_device_ex_resp {
|
||||
struct bnxt_re_db_region {
|
||||
__u32 dpi;
|
||||
__u32 reserved;
|
||||
__aligned_u64 umdbr;
|
||||
__aligned_u64 reserved2;
|
||||
};
|
||||
|
||||
enum bnxt_re_obj_dbr_alloc_attrs {
|
||||
|
||||
Reference in New Issue
Block a user