Third RDMA 5.7 rc pull request

A few bug fixes:
 
 - Incorrect error unwind in qib and pvrdma
 
 - User triggerable NULL pointer crash in mlx5 with ODP prefetch
 
 - syzkaller RCU race in uverbs
 
 - Rare double free crash in ipoib
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEfB7FMLh+8QxL+6i3OG33FX4gmxoFAl7RDU8ACgkQOG33FX4g
 mxrhnQ/8DLbe0xnNpEoHjllcb2CfEIQQQoHgoXZU6NF0EaXwXiM4G2SwVVP4cftN
 7oSGcvrp0YnBrGHp10unu3UX0IUpaw867jNyNC6QKj5RPinHR6IUjJYC4PugAtoc
 RQbyb5Y6Y0PEIhn15vhCOTEwvRDgu9GlXEe6ks0W5143rDF0L96Pr8BJC34HRGUp
 sx+aAkNCT9guuWUNBn5u3XDsboo+XjbeyDwywe9dzCmLKatWEd+y2XdPORGu4OvQ
 +7jtYTj/nGe4wWB3q5uIrFbD2eml8TcGStLKtF4hcijVk2L09xKyIL9dKHWuqc/0
 0tzD2iYvIh31BEIloucC2UXAY2gBSp8t03yDxruuAtDWXsxoS5ic/4Lo2H/mKIoy
 AYIcFJSMr05ujukl6jAHALAUBKLCsYY4Emwk14V970r6ltQNhnC9eps3E4/vbwRf
 SrhlaVFaMUfHdClNwc5mVloo/XJ6AbkTMFJLHUmcxYBXLT/42/0iNfctW03sFZ+K
 0lq0oGbAA52DHy6kUZ122n0b4B8no/W7CP6cvSiQGgAszUcLG9q+o+U/9VPZmBtG
 nfXzMv6QMHxASKCbetqDJ8WqI6LgzYkWJxOVe7DvpeqHLAFxqNYBh3y6by2lm4Dh
 gfJt1CMH4qFtXbjP1HfMV9RFVj74PJgQZfI/ILmh9kPLeXKVy5s=
 =uF5R
 -----END PGP SIGNATURE-----

Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma

Pull rdma fixes from Jason Gunthorpe:
 "Nothing profound here, just a last set of long standing bug fixes:

   - Incorrect error unwind in qib and pvrdma

   - User triggerable NULL pointer crash in mlx5 with ODP prefetch

   - syzkaller RCU race in uverbs

   - Rare double free crash in ipoib"

* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma:
  IB/ipoib: Fix double free of skb in case of multicast traffic in CM mode
  RDMA/core: Fix double destruction of uobject
  RDMA/pvrdma: Fix missing pci disable in pvrdma_pci_probe()
  RDMA/mlx5: Fix NULL pointer dereference in destroy_prefetch_work
  IB/qib: Call kobject_put() when kobject_init_and_add() fails
This commit is contained in:
Linus Torvalds 2020-05-29 13:35:45 -07:00
commit 6ff64d2537
9 changed files with 47 additions and 25 deletions

View File

@ -153,9 +153,9 @@ static int uverbs_destroy_uobject(struct ib_uobject *uobj,
uobj->context = NULL; uobj->context = NULL;
/* /*
* For DESTROY the usecnt is held write locked, the caller is expected * For DESTROY the usecnt is not changed, the caller is expected to
* to put it unlock and put the object when done with it. Only DESTROY * manage it via uobj_put_destroy(). Only DESTROY can remove the IDR
* can remove the IDR handle. * handle.
*/ */
if (reason != RDMA_REMOVE_DESTROY) if (reason != RDMA_REMOVE_DESTROY)
atomic_set(&uobj->usecnt, 0); atomic_set(&uobj->usecnt, 0);
@ -187,7 +187,7 @@ static int uverbs_destroy_uobject(struct ib_uobject *uobj,
/* /*
* This calls uverbs_destroy_uobject() using the RDMA_REMOVE_DESTROY * This calls uverbs_destroy_uobject() using the RDMA_REMOVE_DESTROY
* sequence. It should only be used from command callbacks. On success the * sequence. It should only be used from command callbacks. On success the
* caller must pair this with rdma_lookup_put_uobject(LOOKUP_WRITE). This * caller must pair this with uobj_put_destroy(). This
* version requires the caller to have already obtained an * version requires the caller to have already obtained an
* LOOKUP_DESTROY uobject kref. * LOOKUP_DESTROY uobject kref.
*/ */
@ -198,6 +198,13 @@ int uobj_destroy(struct ib_uobject *uobj, struct uverbs_attr_bundle *attrs)
down_read(&ufile->hw_destroy_rwsem); down_read(&ufile->hw_destroy_rwsem);
/*
* Once the uobject is destroyed by RDMA_REMOVE_DESTROY then it is left
* write locked as the callers put it back with UVERBS_LOOKUP_DESTROY.
* This is because any other concurrent thread can still see the object
* in the xarray due to RCU. Leaving it locked ensures nothing else will
* touch it.
*/
ret = uverbs_try_lock_object(uobj, UVERBS_LOOKUP_WRITE); ret = uverbs_try_lock_object(uobj, UVERBS_LOOKUP_WRITE);
if (ret) if (ret)
goto out_unlock; goto out_unlock;
@ -216,7 +223,7 @@ int uobj_destroy(struct ib_uobject *uobj, struct uverbs_attr_bundle *attrs)
/* /*
* uobj_get_destroy destroys the HW object and returns a handle to the uobj * uobj_get_destroy destroys the HW object and returns a handle to the uobj
* with a NULL object pointer. The caller must pair this with * with a NULL object pointer. The caller must pair this with
* uverbs_put_destroy. * uobj_put_destroy().
*/ */
struct ib_uobject *__uobj_get_destroy(const struct uverbs_api_object *obj, struct ib_uobject *__uobj_get_destroy(const struct uverbs_api_object *obj,
u32 id, struct uverbs_attr_bundle *attrs) u32 id, struct uverbs_attr_bundle *attrs)
@ -250,8 +257,7 @@ int __uobj_perform_destroy(const struct uverbs_api_object *obj, u32 id,
uobj = __uobj_get_destroy(obj, id, attrs); uobj = __uobj_get_destroy(obj, id, attrs);
if (IS_ERR(uobj)) if (IS_ERR(uobj))
return PTR_ERR(uobj); return PTR_ERR(uobj);
uobj_put_destroy(uobj);
rdma_lookup_put_uobject(uobj, UVERBS_LOOKUP_WRITE);
return 0; return 0;
} }

View File

@ -1439,6 +1439,7 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
if (is_odp_mr(mr)) { if (is_odp_mr(mr)) {
to_ib_umem_odp(mr->umem)->private = mr; to_ib_umem_odp(mr->umem)->private = mr;
init_waitqueue_head(&mr->q_deferred_work);
atomic_set(&mr->num_deferred_work, 0); atomic_set(&mr->num_deferred_work, 0);
err = xa_err(xa_store(&dev->odp_mkeys, err = xa_err(xa_store(&dev->odp_mkeys,
mlx5_base_mkey(mr->mmkey.key), &mr->mmkey, mlx5_base_mkey(mr->mmkey.key), &mr->mmkey,

View File

@ -760,7 +760,7 @@ int qib_create_port_files(struct ib_device *ibdev, u8 port_num,
qib_dev_err(dd, qib_dev_err(dd,
"Skipping linkcontrol sysfs info, (err %d) port %u\n", "Skipping linkcontrol sysfs info, (err %d) port %u\n",
ret, port_num); ret, port_num);
goto bail; goto bail_link;
} }
kobject_uevent(&ppd->pport_kobj, KOBJ_ADD); kobject_uevent(&ppd->pport_kobj, KOBJ_ADD);
@ -770,7 +770,7 @@ int qib_create_port_files(struct ib_device *ibdev, u8 port_num,
qib_dev_err(dd, qib_dev_err(dd,
"Skipping sl2vl sysfs info, (err %d) port %u\n", "Skipping sl2vl sysfs info, (err %d) port %u\n",
ret, port_num); ret, port_num);
goto bail_link; goto bail_sl;
} }
kobject_uevent(&ppd->sl2vl_kobj, KOBJ_ADD); kobject_uevent(&ppd->sl2vl_kobj, KOBJ_ADD);
@ -780,7 +780,7 @@ int qib_create_port_files(struct ib_device *ibdev, u8 port_num,
qib_dev_err(dd, qib_dev_err(dd,
"Skipping diag_counters sysfs info, (err %d) port %u\n", "Skipping diag_counters sysfs info, (err %d) port %u\n",
ret, port_num); ret, port_num);
goto bail_sl; goto bail_diagc;
} }
kobject_uevent(&ppd->diagc_kobj, KOBJ_ADD); kobject_uevent(&ppd->diagc_kobj, KOBJ_ADD);
@ -793,7 +793,7 @@ int qib_create_port_files(struct ib_device *ibdev, u8 port_num,
qib_dev_err(dd, qib_dev_err(dd,
"Skipping Congestion Control sysfs info, (err %d) port %u\n", "Skipping Congestion Control sysfs info, (err %d) port %u\n",
ret, port_num); ret, port_num);
goto bail_diagc; goto bail_cc;
} }
kobject_uevent(&ppd->pport_cc_kobj, KOBJ_ADD); kobject_uevent(&ppd->pport_cc_kobj, KOBJ_ADD);
@ -854,6 +854,7 @@ void qib_verbs_unregister_sysfs(struct qib_devdata *dd)
&cc_table_bin_attr); &cc_table_bin_attr);
kobject_put(&ppd->pport_cc_kobj); kobject_put(&ppd->pport_cc_kobj);
} }
kobject_put(&ppd->diagc_kobj);
kobject_put(&ppd->sl2vl_kobj); kobject_put(&ppd->sl2vl_kobj);
kobject_put(&ppd->pport_kobj); kobject_put(&ppd->pport_kobj);
} }

View File

@ -829,7 +829,7 @@ static int pvrdma_pci_probe(struct pci_dev *pdev,
!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) { !(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
dev_err(&pdev->dev, "PCI BAR region not MMIO\n"); dev_err(&pdev->dev, "PCI BAR region not MMIO\n");
ret = -ENOMEM; ret = -ENOMEM;
goto err_free_device; goto err_disable_pdev;
} }
ret = pci_request_regions(pdev, DRV_NAME); ret = pci_request_regions(pdev, DRV_NAME);

View File

@ -377,8 +377,12 @@ struct ipoib_dev_priv {
struct ipoib_rx_buf *rx_ring; struct ipoib_rx_buf *rx_ring;
struct ipoib_tx_buf *tx_ring; struct ipoib_tx_buf *tx_ring;
/* cyclic ring variables for managing tx_ring, for UD only */
unsigned int tx_head; unsigned int tx_head;
unsigned int tx_tail; unsigned int tx_tail;
/* cyclic ring variables for counting overall outstanding send WRs */
unsigned int global_tx_head;
unsigned int global_tx_tail;
struct ib_sge tx_sge[MAX_SKB_FRAGS + 1]; struct ib_sge tx_sge[MAX_SKB_FRAGS + 1];
struct ib_ud_wr tx_wr; struct ib_ud_wr tx_wr;
struct ib_wc send_wc[MAX_SEND_CQE]; struct ib_wc send_wc[MAX_SEND_CQE];

View File

@ -756,7 +756,8 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
return; return;
} }
if ((priv->tx_head - priv->tx_tail) == ipoib_sendq_size - 1) { if ((priv->global_tx_head - priv->global_tx_tail) ==
ipoib_sendq_size - 1) {
ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n", ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n",
tx->qp->qp_num); tx->qp->qp_num);
netif_stop_queue(dev); netif_stop_queue(dev);
@ -786,7 +787,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
} else { } else {
netif_trans_update(dev); netif_trans_update(dev);
++tx->tx_head; ++tx->tx_head;
++priv->tx_head; ++priv->global_tx_head;
} }
} }
@ -820,10 +821,11 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
netif_tx_lock(dev); netif_tx_lock(dev);
++tx->tx_tail; ++tx->tx_tail;
++priv->tx_tail; ++priv->global_tx_tail;
if (unlikely(netif_queue_stopped(dev) && if (unlikely(netif_queue_stopped(dev) &&
(priv->tx_head - priv->tx_tail) <= ipoib_sendq_size >> 1 && ((priv->global_tx_head - priv->global_tx_tail) <=
ipoib_sendq_size >> 1) &&
test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))) test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)))
netif_wake_queue(dev); netif_wake_queue(dev);
@ -1232,8 +1234,9 @@ static void ipoib_cm_tx_destroy(struct ipoib_cm_tx *p)
dev_kfree_skb_any(tx_req->skb); dev_kfree_skb_any(tx_req->skb);
netif_tx_lock_bh(p->dev); netif_tx_lock_bh(p->dev);
++p->tx_tail; ++p->tx_tail;
++priv->tx_tail; ++priv->global_tx_tail;
if (unlikely(priv->tx_head - priv->tx_tail == ipoib_sendq_size >> 1) && if (unlikely((priv->global_tx_head - priv->global_tx_tail) <=
ipoib_sendq_size >> 1) &&
netif_queue_stopped(p->dev) && netif_queue_stopped(p->dev) &&
test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
netif_wake_queue(p->dev); netif_wake_queue(p->dev);

View File

@ -407,9 +407,11 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
dev_kfree_skb_any(tx_req->skb); dev_kfree_skb_any(tx_req->skb);
++priv->tx_tail; ++priv->tx_tail;
++priv->global_tx_tail;
if (unlikely(netif_queue_stopped(dev) && if (unlikely(netif_queue_stopped(dev) &&
((priv->tx_head - priv->tx_tail) <= ipoib_sendq_size >> 1) && ((priv->global_tx_head - priv->global_tx_tail) <=
ipoib_sendq_size >> 1) &&
test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))) test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)))
netif_wake_queue(dev); netif_wake_queue(dev);
@ -634,7 +636,8 @@ int ipoib_send(struct net_device *dev, struct sk_buff *skb,
else else
priv->tx_wr.wr.send_flags &= ~IB_SEND_IP_CSUM; priv->tx_wr.wr.send_flags &= ~IB_SEND_IP_CSUM;
/* increase the tx_head after send success, but use it for queue state */ /* increase the tx_head after send success, but use it for queue state */
if (priv->tx_head - priv->tx_tail == ipoib_sendq_size - 1) { if ((priv->global_tx_head - priv->global_tx_tail) ==
ipoib_sendq_size - 1) {
ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n"); ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n");
netif_stop_queue(dev); netif_stop_queue(dev);
} }
@ -662,6 +665,7 @@ int ipoib_send(struct net_device *dev, struct sk_buff *skb,
rc = priv->tx_head; rc = priv->tx_head;
++priv->tx_head; ++priv->tx_head;
++priv->global_tx_head;
} }
return rc; return rc;
} }
@ -807,6 +811,7 @@ int ipoib_ib_dev_stop_default(struct net_device *dev)
ipoib_dma_unmap_tx(priv, tx_req); ipoib_dma_unmap_tx(priv, tx_req);
dev_kfree_skb_any(tx_req->skb); dev_kfree_skb_any(tx_req->skb);
++priv->tx_tail; ++priv->tx_tail;
++priv->global_tx_tail;
} }
for (i = 0; i < ipoib_recvq_size; ++i) { for (i = 0; i < ipoib_recvq_size; ++i) {

View File

@ -1184,9 +1184,11 @@ static void ipoib_timeout(struct net_device *dev, unsigned int txqueue)
ipoib_warn(priv, "transmit timeout: latency %d msecs\n", ipoib_warn(priv, "transmit timeout: latency %d msecs\n",
jiffies_to_msecs(jiffies - dev_trans_start(dev))); jiffies_to_msecs(jiffies - dev_trans_start(dev)));
ipoib_warn(priv, "queue stopped %d, tx_head %u, tx_tail %u\n", ipoib_warn(priv,
netif_queue_stopped(dev), "queue stopped %d, tx_head %u, tx_tail %u, global_tx_head %u, global_tx_tail %u\n",
priv->tx_head, priv->tx_tail); netif_queue_stopped(dev), priv->tx_head, priv->tx_tail,
priv->global_tx_head, priv->global_tx_tail);
/* XXX reset QP, etc. */ /* XXX reset QP, etc. */
} }
@ -1701,7 +1703,7 @@ static int ipoib_dev_init_default(struct net_device *dev)
goto out_rx_ring_cleanup; goto out_rx_ring_cleanup;
} }
/* priv->tx_head, tx_tail & tx_outstanding are already 0 */ /* priv->tx_head, tx_tail and global_tx_tail/head are already 0 */
if (ipoib_transport_dev_init(dev, priv->ca)) { if (ipoib_transport_dev_init(dev, priv->ca)) {
pr_warn("%s: ipoib_transport_dev_init failed\n", pr_warn("%s: ipoib_transport_dev_init failed\n",

View File

@ -88,7 +88,7 @@ struct ib_uobject *__uobj_get_destroy(const struct uverbs_api_object *obj,
static inline void uobj_put_destroy(struct ib_uobject *uobj) static inline void uobj_put_destroy(struct ib_uobject *uobj)
{ {
rdma_lookup_put_uobject(uobj, UVERBS_LOOKUP_WRITE); rdma_lookup_put_uobject(uobj, UVERBS_LOOKUP_DESTROY);
} }
static inline void uobj_put_read(struct ib_uobject *uobj) static inline void uobj_put_read(struct ib_uobject *uobj)