Commit d9594d99 authored by Steve Wise's avatar Steve Wise Committed by Roland Dreier

RDMA/cxgb4: Reset wait condition atomically

The driver was never really waiting for RDMA_WR/FINI completions
because the condition variable used to determine if the completion
happened was never reset, and this condition variable is reused for
both connection setup and teardown.  This causes various driver
crashes under heavy loads due to releasing resources too early.

The fix is to use atomic bits to correctly reset the condition
immediately after the completion is detected.
Signed-off-by: default avatarSteve Wise <swise@opengridcomputing.com>
Signed-off-by: default avatarRoland Dreier <roland@purestorage.com>
parent 85d215b0
...@@ -1198,9 +1198,7 @@ static int pass_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb) ...@@ -1198,9 +1198,7 @@ static int pass_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
} }
PDBG("%s ep %p status %d error %d\n", __func__, ep, PDBG("%s ep %p status %d error %d\n", __func__, ep,
rpl->status, status2errno(rpl->status)); rpl->status, status2errno(rpl->status));
ep->com.wr_wait.ret = status2errno(rpl->status); c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
ep->com.wr_wait.done = 1;
wake_up(&ep->com.wr_wait.wait);
return 0; return 0;
} }
...@@ -1234,9 +1232,7 @@ static int close_listsrv_rpl(struct c4iw_dev *dev, struct sk_buff *skb) ...@@ -1234,9 +1232,7 @@ static int close_listsrv_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
struct c4iw_listen_ep *ep = lookup_stid(t, stid); struct c4iw_listen_ep *ep = lookup_stid(t, stid);
PDBG("%s ep %p\n", __func__, ep); PDBG("%s ep %p\n", __func__, ep);
ep->com.wr_wait.ret = status2errno(rpl->status); c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
ep->com.wr_wait.done = 1;
wake_up(&ep->com.wr_wait.wait);
return 0; return 0;
} }
...@@ -1492,17 +1488,13 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb) ...@@ -1492,17 +1488,13 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
* in rdma connection migration (see c4iw_accept_cr()). * in rdma connection migration (see c4iw_accept_cr()).
*/ */
__state_set(&ep->com, CLOSING); __state_set(&ep->com, CLOSING);
ep->com.wr_wait.done = 1;
ep->com.wr_wait.ret = -ECONNRESET;
PDBG("waking up ep %p tid %u\n", ep, ep->hwtid); PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
wake_up(&ep->com.wr_wait.wait); c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
break; break;
case MPA_REP_SENT: case MPA_REP_SENT:
__state_set(&ep->com, CLOSING); __state_set(&ep->com, CLOSING);
ep->com.wr_wait.done = 1;
ep->com.wr_wait.ret = -ECONNRESET;
PDBG("waking up ep %p tid %u\n", ep, ep->hwtid); PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
wake_up(&ep->com.wr_wait.wait); c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
break; break;
case FPDU_MODE: case FPDU_MODE:
start_ep_timer(ep); start_ep_timer(ep);
...@@ -1579,9 +1571,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb) ...@@ -1579,9 +1571,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
/* /*
* Wake up any threads in rdma_init() or rdma_fini(). * Wake up any threads in rdma_init() or rdma_fini().
*/ */
ep->com.wr_wait.done = 1; c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
ep->com.wr_wait.ret = -ECONNRESET;
wake_up(&ep->com.wr_wait.wait);
mutex_lock(&ep->com.mutex); mutex_lock(&ep->com.mutex);
switch (ep->com.state) { switch (ep->com.state) {
...@@ -2294,14 +2284,8 @@ static int fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb) ...@@ -2294,14 +2284,8 @@ static int fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb)
ret = (int)((be64_to_cpu(rpl->data[0]) >> 8) & 0xff); ret = (int)((be64_to_cpu(rpl->data[0]) >> 8) & 0xff);
wr_waitp = (struct c4iw_wr_wait *)(__force unsigned long) rpl->data[1]; wr_waitp = (struct c4iw_wr_wait *)(__force unsigned long) rpl->data[1];
PDBG("%s wr_waitp %p ret %u\n", __func__, wr_waitp, ret); PDBG("%s wr_waitp %p ret %u\n", __func__, wr_waitp, ret);
if (wr_waitp) { if (wr_waitp)
if (ret) c4iw_wake_up(wr_waitp, ret ? -ret : 0);
wr_waitp->ret = -ret;
else
wr_waitp->ret = 0;
wr_waitp->done = 1;
wake_up(&wr_waitp->wait);
}
kfree_skb(skb); kfree_skb(skb);
break; break;
case 2: case 2:
......
...@@ -131,42 +131,54 @@ static inline int c4iw_num_stags(struct c4iw_rdev *rdev) ...@@ -131,42 +131,54 @@ static inline int c4iw_num_stags(struct c4iw_rdev *rdev)
#define C4IW_WR_TO (10*HZ) #define C4IW_WR_TO (10*HZ)
enum {
REPLY_READY = 0,
};
struct c4iw_wr_wait { struct c4iw_wr_wait {
wait_queue_head_t wait; wait_queue_head_t wait;
int done; unsigned long status;
int ret; int ret;
}; };
static inline void c4iw_init_wr_wait(struct c4iw_wr_wait *wr_waitp) static inline void c4iw_init_wr_wait(struct c4iw_wr_wait *wr_waitp)
{ {
wr_waitp->ret = 0; wr_waitp->ret = 0;
wr_waitp->done = 0; wr_waitp->status = 0;
init_waitqueue_head(&wr_waitp->wait); init_waitqueue_head(&wr_waitp->wait);
} }
static inline void c4iw_wake_up(struct c4iw_wr_wait *wr_waitp, int ret)
{
wr_waitp->ret = ret;
set_bit(REPLY_READY, &wr_waitp->status);
wake_up(&wr_waitp->wait);
}
static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev, static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
struct c4iw_wr_wait *wr_waitp, struct c4iw_wr_wait *wr_waitp,
u32 hwtid, u32 qpid, u32 hwtid, u32 qpid,
const char *func) const char *func)
{ {
unsigned to = C4IW_WR_TO; unsigned to = C4IW_WR_TO;
do { int ret;
wait_event_timeout(wr_waitp->wait, wr_waitp->done, to); do {
if (!wr_waitp->done) { ret = wait_event_timeout(wr_waitp->wait,
test_and_clear_bit(REPLY_READY, &wr_waitp->status), to);
if (!ret) {
printk(KERN_ERR MOD "%s - Device %s not responding - " printk(KERN_ERR MOD "%s - Device %s not responding - "
"tid %u qpid %u\n", func, "tid %u qpid %u\n", func,
pci_name(rdev->lldi.pdev), hwtid, qpid); pci_name(rdev->lldi.pdev), hwtid, qpid);
to = to << 2; to = to << 2;
} }
} while (!wr_waitp->done); } while (!ret);
if (wr_waitp->ret) if (wr_waitp->ret)
PDBG("%s: FW reply %d tid %u qpid %u\n", PDBG("%s: FW reply %d tid %u qpid %u\n",
pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid); pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid);
return wr_waitp->ret; return wr_waitp->ret;
} }
struct c4iw_dev { struct c4iw_dev {
struct ib_device ibdev; struct ib_device ibdev;
struct c4iw_rdev rdev; struct c4iw_rdev rdev;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment