Skip to content

Commit

Permalink
RDMA/cxgb4: Fix endpoint timeout race condition
Browse files Browse the repository at this point in the history
The endpoint timeout logic had a race that could cause an endpoint
object to be freed while it was still on the timedout list.  This
can happen if the timer is stopped after it had fired, but before
the timedout thread processed the endpoint timeout.

Signed-off-by: Vipul Pandya <vipul@chelsio.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
  • Loading branch information
Vipul Pandya authored and Roland Dreier committed Feb 14, 2013
1 parent e8e5b92 commit 1ec779c
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 13 deletions.
29 changes: 16 additions & 13 deletions drivers/infiniband/hw/cxgb4/cm.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,12 @@ static void start_ep_timer(struct c4iw_ep *ep)
{
PDBG("%s ep %p\n", __func__, ep);
if (timer_pending(&ep->timer)) {
PDBG("%s stopped / restarted timer ep %p\n", __func__, ep);
del_timer_sync(&ep->timer);
} else
c4iw_get_ep(&ep->com);
pr_err("%s timer already started! ep %p\n",
__func__, ep);
return;
}
clear_bit(TIMEOUT, &ep->com.flags);
c4iw_get_ep(&ep->com);
ep->timer.expires = jiffies + ep_timeout_secs * HZ;
ep->timer.data = (unsigned long)ep;
ep->timer.function = ep_timeout;
Expand All @@ -171,14 +173,10 @@ static void start_ep_timer(struct c4iw_ep *ep)

static void stop_ep_timer(struct c4iw_ep *ep)
{
PDBG("%s ep %p\n", __func__, ep);
if (!timer_pending(&ep->timer)) {
WARN(1, "%s timer stopped when its not running! "
"ep %p state %u\n", __func__, ep, ep->com.state);
return;
}
PDBG("%s ep %p stopping\n", __func__, ep);
del_timer_sync(&ep->timer);
c4iw_put_ep(&ep->com);
if (!test_and_set_bit(TIMEOUT, &ep->com.flags))
c4iw_put_ep(&ep->com);
}

static int c4iw_l2t_send(struct c4iw_rdev *rdev, struct sk_buff *skb,
Expand Down Expand Up @@ -3191,11 +3189,16 @@ static DECLARE_WORK(skb_work, process_work);
static void ep_timeout(unsigned long arg)
{
struct c4iw_ep *ep = (struct c4iw_ep *)arg;
int kickit = 0;

spin_lock(&timeout_lock);
list_add_tail(&ep->entry, &timeout_list);
if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) {
list_add_tail(&ep->entry, &timeout_list);
kickit = 1;
}
spin_unlock(&timeout_lock);
queue_work(workq, &skb_work);
if (kickit)
queue_work(workq, &skb_work);
}

/*
Expand Down
1 change: 1 addition & 0 deletions drivers/infiniband/hw/cxgb4/iw_cxgb4.h
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,7 @@ enum c4iw_ep_flags {
ABORT_REQ_IN_PROGRESS = 1,
RELEASE_RESOURCES = 2,
CLOSE_SENT = 3,
TIMEOUT = 4,
QP_REFERENCED = 5,
};

Expand Down

0 comments on commit 1ec779c

Please sign in to comment.