RDMA fixes 2017-12-31
Subsystems (2)
cover RDMA fixes 2017-12-31
Hi,
There are two small fixes, one fix to mlx4_ib_alloc_mr error flow, very similar to commit 45e6ae7ef21b ("IB/mlx5: Fix mlx5_ib_alloc_mr error flow") and another fix to race condition in IPoIB revealed by Enhanced IPoIB tests.
Thanks
The patches are available in the git repository at:
git.kernel.org/pub/scm/linux/kernel/git/leon/linux-rdma.git tags/rdma-rc-2017-12-31
Thanks
---------------------------------------
Erez Shitrit (1):
IB/ipoib: Fix race condition in neigh creation
Leon Romanovsky (1):
IB/mlx4: Fix mlx4_ib_alloc_mr error flow
drivers/infiniband/hw/mlx4/mr.c | 2 +- drivers/infiniband/ulp/ipoib/ipoib_main.c | 25 ++++++++++++++++++------- drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 5 ++++- 3 files changed, 23 insertions(+), 9 deletions(-)
--
2.15.1
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 20171231133315.28801-1-leon-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org
PATCH 1/2 IB/mlx4: Fix mlx4_ib_alloc_mr error flow
From: Leon Romanovsky <leonro-VPRAkNaXOzVWk0Htik3J/[email protected]>
ibmr.device is being set only after ib_alloc_mr() is successfully complete. Therefore, in case imlx4_mr_enable() returns with error, the error flow unwinder calls to mlx4_free_priv_pages(), which uses ibmr.device.
Such usage causes to NULL dereference oops and to fix it, the IB device should be set in the mr struct earlier stage (e.g. prior to calling mlx4_free_priv_pages()).
--- drivers/infiniband/hw/mlx4/mr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/hw/mlx4/mr.c +1 -1
@@ -642,7 +642,6 @@ struct ib_mr *mlx4_ib_alloc_mr(struct ib_pd *pd, goto err_free_mr; mr->max_pages = max_num_sg; - err =mlx4_mr_enable (dev->dev, &mr->mmr);if (err) goto err_free_pl;
@@ -653,6 +652,7 @@ struct ib_mr *mlx4_ib_alloc_mr(struct ib_pd *pd,return &mr->ibmr; err_free_pl: + mr->ibmr.device = pd->device;mlx4_free_priv_pages (mr); err_free_mr: (void )mlx4_mr_free (dev->dev, &mr->mmr);
--
2.15.1
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 2/2 IB/ipoib: Fix race condition in neigh creation
In reply to a message not in the archiveFrom: Erez Shitrit <erezsh-VPRAkNaXOzVWk0Htik3J/[email protected]>
When using enhanced mode for IPoIB, two threads may execute xmit in parallel to two different TX queues while the target is the same. In this case, both of them will add the same neighbor to the path's neigh link list and we might see the following message:
list_add double add: new=ffff88024767a348, prev=ffff88024767a348...
WARNING: lib/list_debug.c:31__list_add_valid+0x4e/0x70 ipoib_start_xmit+0x477/0x680 [ib_ipoib] dev_hard_start_xmit+0xb9/0x3e0 sch_direct_xmit+0xf9/0x250 __qdisc_run+0x176/0x5d0 __dev_queue_xmit+0x1f5/0xb10 __dev_queue_xmit+0x55/0xb10
Analysis:
Two SKB are scheduled to be transmitted from two cores.
In ipoib_start_xmit, both gets NULL when calling ipoib_neigh_get. Two calls to neigh_add_path are made. One thread takes the spin-lock and calls ipoib_neigh_alloc which creates the neigh structure, then (after the __path_find) the neigh is added to the path's neigh link list. When the second thread enters the critical section it also calls ipoib_neigh_alloc but in this case it gets the already allocated ipoib_neigh structure, which is already linked to the path's neigh link list and adds it again to the list. Which beside of triggering the list, it creates a loop in the linked list. This loop leads to endless loop inside path_rec_completion.
Solution:
Check list_empty(&neigh->list) before adding to the list. Add a similar fix in "ipoib_multicast.c::ipoib_mcast_send"
--- drivers/infiniband/ulp/ipoib/ipoib_main.c | 25 ++++++++++++++++++------- drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 5 ++++- 2 files changed, 22 insertions(+), 8 deletions(-)
drivers/infiniband/ulp/ipoib/ipoib_main.c +18 -7
@@ -902,8 +902,8 @@ static int path_rec_start(struct net_device *dev,return 0 ; } -static void neigh_add_path (struct sk_buff *skb,u8 *daddr, -struct net_device *dev) +static struct ipoib_neigh *neigh_add_path (struct sk_buff *skb,u8 *daddr, +struct net_device *dev) {struct ipoib_dev_priv *priv =ipoib_priv (dev);struct rdma_netdev *rn =netdev_priv (dev);
@@ -917,7 +917,15 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr,spin_unlock_irqrestore (&priv->lock, flags); ++dev->stats.tx_dropped;dev_kfree_skb_any (skb); -return ; +return NULL ; + } + +/* To avoid race condition, make sure that the +* neigh will be added only once. +*/ +if (unlikely (!list_empty (&neigh->list))) { +spin_unlock_irqrestore (&priv->lock, flags); +return neigh; } path =__path_find (dev, daddr +4 );
@@ -956,7 +964,7 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr, path->ah->last_send = rn->send (dev, skb, path->ah->ah,IPOIB_QPN (daddr));ipoib_neigh_put (neigh); -return ; +return NULL ; } }else { neigh->ah =NULL ;
@@ -973,7 +981,7 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr,spin_unlock_irqrestore (&priv->lock, flags);ipoib_neigh_put (neigh); -return ; +return NULL ; err_path:ipoib_neigh_free (neigh);
@@ -983,6 +991,8 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr,spin_unlock_irqrestore (&priv->lock, flags);ipoib_neigh_put (neigh); + +return NULL ; } static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
@@ -1091,8 +1101,9 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)case htons (ETH_P_TIPC ): neigh =ipoib_neigh_get (dev, phdr->hwaddr);if (unlikely (!neigh)) { -neigh_add_path (skb, phdr->hwaddr, dev); -return NETDEV_TX_OK ; + neigh =neigh_add_path (skb, phdr->hwaddr, dev); +if (likely (!neigh)) +return NETDEV_TX_OK ; }break ;case htons (ETH_P_ARP ):
drivers/infiniband/ulp/ipoib/ipoib_multicast.c +4 -1
@@ -816,7 +816,10 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb)spin_lock_irqsave (&priv->lock, flags);if (!neigh) { neigh =ipoib_neigh_alloc (daddr, dev); -if (neigh) { +/* Make sure that the neigh will be added only +* once to mcast list. +*/ +if (neigh &&list_empty (&neigh->list)) {kref_get (&mcast->ah->ref); neigh->ah = mcast->ah;list_add_tail (&neigh->list, &mcast->neigh_list);
--
2.15.1
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Jason Gunthorpe
AppliedQuoted 6 lines · Leon Romanovsky
Hi,
There are two small fixes, one fix to
mlx4_ib_alloc_mrerror flow, very similar to commit45e6ae7ef21b("IB/mlx5: Fixmlx5_ib_alloc_mrerror flow") and another fix to race condition in IPoIB revealed by Enhanced IPoIB tests.
Applied to for-rc
Thanks
Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html