Skip to content

Commit

Permalink
bnxt_re: Fix race between the netdev register and unregister events
Browse files Browse the repository at this point in the history
Upon receipt of the NETDEV_REGISTER event from the netdev notifier chain,
the IB stack registration is spawned off to a workqueue since that also
requires an rtnl lock.
There could be 2 kinds of races between the NETDEV_REGISTER and the
NETDEV_UNREGISTER event handling.
a)The NETDEV_UNREGISTER event is received in rapid succession after
the NETDEV_REGISTER event even before the work queue got a chance to run.
b)The NETDEV_UNREGISTER event is received while the workqueue that handles
registration with the IB stack is still in progress.

Handle both the races with a bit flag that is set just before the work item
is queued and cleared in the workqueue after the event is handled just
before the workqueue item is freed.

While adding the new flag, it was noted that the flags are all used in
*_bit() operations which expect a bit number and not a literal constant
with a bit set.  So change the numbers to be bit numbers.

Signed-off-by: Somnath Kotur <somnath.kotur@broadcom.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
  • Loading branch information
skotur-brcm authored and dledford committed Sep 22, 2017
1 parent 027c892 commit d591730
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 5 deletions.
12 changes: 7 additions & 5 deletions drivers/infiniband/hw/bnxt_re/bnxt_re.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,13 @@ struct bnxt_re_dev {
struct ib_device ibdev;
struct list_head list;
unsigned long flags;
#define BNXT_RE_FLAG_NETDEV_REGISTERED 0
#define BNXT_RE_FLAG_IBDEV_REGISTERED 1
#define BNXT_RE_FLAG_GOT_MSIX 2
#define BNXT_RE_FLAG_RCFW_CHANNEL_EN 8
#define BNXT_RE_FLAG_QOS_WORK_REG 16
#define BNXT_RE_FLAG_NETDEV_REGISTERED 0
#define BNXT_RE_FLAG_IBDEV_REGISTERED 1
#define BNXT_RE_FLAG_GOT_MSIX 2
#define BNXT_RE_FLAG_HAVE_L2_REF 3
#define BNXT_RE_FLAG_RCFW_CHANNEL_EN 4
#define BNXT_RE_FLAG_QOS_WORK_REG 5
#define BNXT_RE_FLAG_TASK_IN_PROG 6
struct net_device *netdev;
unsigned int version, major, minor;
struct bnxt_en_dev *en_dev;
Expand Down
8 changes: 8 additions & 0 deletions drivers/infiniband/hw/bnxt_re/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1259,6 +1259,8 @@ static void bnxt_re_task(struct work_struct *work)
default:
break;
}
smp_mb__before_atomic();
clear_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags);
kfree(re_work);
}

Expand Down Expand Up @@ -1317,6 +1319,11 @@ static int bnxt_re_netdev_event(struct notifier_block *notifier,
break;

case NETDEV_UNREGISTER:
/* netdev notifier will call NETDEV_UNREGISTER again later since
* we are still holding the reference to the netdev
*/
if (test_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags))
goto exit;
bnxt_re_ib_unreg(rdev, false);
bnxt_re_remove_one(rdev);
bnxt_re_dev_unreg(rdev);
Expand All @@ -1335,6 +1342,7 @@ static int bnxt_re_netdev_event(struct notifier_block *notifier,
re_work->vlan_dev = (real_dev == netdev ?
NULL : netdev);
INIT_WORK(&re_work->work, bnxt_re_task);
set_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags);
queue_work(bnxt_re_wq, &re_work->work);
}
}
Expand Down

0 comments on commit d591730

Please sign in to comment.