RDMA/cxgb4: Couple of abort fixes
- fix a race where the driver could end up sending a close_con_req after an abort_rpl. In c4iw_ep_disconnect(), send abort or close request with the ep mutex held. - fix a hang where driver fails to wake up when a connection is reset during a normal close. Wake up any waiters in the interrupt path, and correctly cleanup after rdma_fini() failures. Signed-off-by: Steve Wise <swise@opengridcomputing.com> Signed-off-by: Roland Dreier <roland@purestorage.com>
This commit is contained in:
parent
301c2c3f03
commit
8da7e7a552
|
@ -1463,9 +1463,9 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
|
||||||
struct c4iw_qp_attributes attrs;
|
struct c4iw_qp_attributes attrs;
|
||||||
int disconnect = 1;
|
int disconnect = 1;
|
||||||
int release = 0;
|
int release = 0;
|
||||||
int abort = 0;
|
|
||||||
struct tid_info *t = dev->rdev.lldi.tids;
|
struct tid_info *t = dev->rdev.lldi.tids;
|
||||||
unsigned int tid = GET_TID(hdr);
|
unsigned int tid = GET_TID(hdr);
|
||||||
|
int ret;
|
||||||
|
|
||||||
ep = lookup_tid(t, tid);
|
ep = lookup_tid(t, tid);
|
||||||
PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
|
PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
|
||||||
|
@ -1501,10 +1501,12 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
|
||||||
start_ep_timer(ep);
|
start_ep_timer(ep);
|
||||||
__state_set(&ep->com, CLOSING);
|
__state_set(&ep->com, CLOSING);
|
||||||
attrs.next_state = C4IW_QP_STATE_CLOSING;
|
attrs.next_state = C4IW_QP_STATE_CLOSING;
|
||||||
abort = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
|
ret = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
|
||||||
C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
|
C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
|
||||||
|
if (ret != -ECONNRESET) {
|
||||||
peer_close_upcall(ep);
|
peer_close_upcall(ep);
|
||||||
disconnect = 1;
|
disconnect = 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ABORTING:
|
case ABORTING:
|
||||||
disconnect = 0;
|
disconnect = 0;
|
||||||
|
@ -2109,15 +2111,16 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&ep->com.mutex);
|
|
||||||
if (close) {
|
if (close) {
|
||||||
if (abrupt)
|
if (abrupt) {
|
||||||
ret = abort_connection(ep, NULL, gfp);
|
close_complete_upcall(ep);
|
||||||
else
|
ret = send_abort(ep, NULL, gfp);
|
||||||
|
} else
|
||||||
ret = send_halfclose(ep, gfp);
|
ret = send_halfclose(ep, gfp);
|
||||||
if (ret)
|
if (ret)
|
||||||
fatal = 1;
|
fatal = 1;
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&ep->com.mutex);
|
||||||
if (fatal)
|
if (fatal)
|
||||||
release_ep_resources(ep);
|
release_ep_resources(ep);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -2301,6 +2304,31 @@ static int fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct cpl_abort_req_rss *req = cplhdr(skb);
|
||||||
|
struct c4iw_ep *ep;
|
||||||
|
struct tid_info *t = dev->rdev.lldi.tids;
|
||||||
|
unsigned int tid = GET_TID(req);
|
||||||
|
|
||||||
|
ep = lookup_tid(t, tid);
|
||||||
|
if (is_neg_adv_abort(req->status)) {
|
||||||
|
PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep,
|
||||||
|
ep->hwtid);
|
||||||
|
kfree_skb(skb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
PDBG("%s ep %p tid %u state %u\n", __func__, ep, ep->hwtid,
|
||||||
|
ep->com.state);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wake up any threads in rdma_init() or rdma_fini().
|
||||||
|
*/
|
||||||
|
c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
|
||||||
|
sched(dev, skb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Most upcalls from the T4 Core go to sched() to
|
* Most upcalls from the T4 Core go to sched() to
|
||||||
* schedule the processing on a work queue.
|
* schedule the processing on a work queue.
|
||||||
|
@ -2317,7 +2345,7 @@ c4iw_handler_func c4iw_handlers[NUM_CPL_CMDS] = {
|
||||||
[CPL_PASS_ESTABLISH] = sched,
|
[CPL_PASS_ESTABLISH] = sched,
|
||||||
[CPL_PEER_CLOSE] = sched,
|
[CPL_PEER_CLOSE] = sched,
|
||||||
[CPL_CLOSE_CON_RPL] = sched,
|
[CPL_CLOSE_CON_RPL] = sched,
|
||||||
[CPL_ABORT_REQ_RSS] = sched,
|
[CPL_ABORT_REQ_RSS] = peer_abort_intr,
|
||||||
[CPL_RDMA_TERMINATE] = sched,
|
[CPL_RDMA_TERMINATE] = sched,
|
||||||
[CPL_FW4_ACK] = sched,
|
[CPL_FW4_ACK] = sched,
|
||||||
[CPL_SET_TCB_RPL] = set_tcb_rpl,
|
[CPL_SET_TCB_RPL] = set_tcb_rpl,
|
||||||
|
|
|
@ -1207,11 +1207,8 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
|
||||||
c4iw_get_ep(&qhp->ep->com);
|
c4iw_get_ep(&qhp->ep->com);
|
||||||
}
|
}
|
||||||
ret = rdma_fini(rhp, qhp, ep);
|
ret = rdma_fini(rhp, qhp, ep);
|
||||||
if (ret) {
|
if (ret)
|
||||||
if (internal)
|
|
||||||
c4iw_get_ep(&qhp->ep->com);
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case C4IW_QP_STATE_TERMINATE:
|
case C4IW_QP_STATE_TERMINATE:
|
||||||
set_state(qhp, C4IW_QP_STATE_TERMINATE);
|
set_state(qhp, C4IW_QP_STATE_TERMINATE);
|
||||||
|
|
Loading…
Reference in New Issue