1 From d6d57b2eff6aec8ef25a2b61c5216ad63a69f70e Mon Sep 17 00:00:00 2001
2 From: Raju Rangoju <rajur@chelsio.com>
3 Date: Wed, 6 Feb 2019 22:54:44 +0530
4 Subject: iw_cxgb4: fix srqidx leak during connection abort
6 [ Upstream commit f368ff188ae4b3ef6f740a15999ea0373261b619 ]
8 When an application aborts the connection by moving QP from RTS to ERROR,
9 then iw_cxgb4's modify_rc_qp() RTS->ERROR logic sets the
10 *srqidxp to 0 via t4_set_wq_in_error(&qhp->wq, 0), and aborts the
11 connection by calling c4iw_ep_disconnect().
13 c4iw_ep_disconnect() does the following:
14 1. sends up a close_complete_upcall(ep, -ECONNRESET) to libcxgb4.
15 2. sends abort request CPL to hw.
17 But, since the close_complete_upcall() is sent before sending the
18 ABORT_REQ to hw, libcxgb4 would fail to release the srqidx if the
19 connection holds one. Because, the srqidx is passed up to libcxgb4 only
20 after corresponding ABORT_RPL is processed by kernel in abort_rpl().
22 This patch handle the corner-case by moving the call to
23 close_complete_upcall() from c4iw_ep_disconnect() to abort_rpl(). So that
24 libcxgb4 is notified about the -ECONNRESET only after abort_rpl(), and
25 libcxgb4 can relinquish the srqidx properly.
27 Signed-off-by: Raju Rangoju <rajur@chelsio.com>
28 Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
29 Signed-off-by: Sasha Levin <sashal@kernel.org>
31 drivers/infiniband/hw/cxgb4/cm.c | 5 +++--
32 1 file changed, 3 insertions(+), 2 deletions(-)
34 diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
35 index 0f83cbec33f3..a68569ec86bf 100644
36 --- a/drivers/infiniband/hw/cxgb4/cm.c
37 +++ b/drivers/infiniband/hw/cxgb4/cm.c
38 @@ -1904,8 +1904,10 @@ static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
40 mutex_unlock(&ep->com.mutex);
44 + close_complete_upcall(ep, -ECONNRESET);
45 release_ep_resources(ep);
47 c4iw_put_ep(&ep->com);
50 @@ -3608,7 +3610,6 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
53 set_bit(EP_DISC_ABORT, &ep->com.history);
54 - close_complete_upcall(ep, -ECONNRESET);
57 set_bit(EP_DISC_CLOSE, &ep->com.history);