OSDN Git Service

RDMA/bnxt_re: Avoid system hang during device un-reg
authorSelvin Xavier <selvin.xavier@broadcom.com>
Fri, 16 Feb 2018 05:20:13 +0000 (21:20 -0800)
committerDoug Ledford <dledford@redhat.com>
Tue, 20 Feb 2018 16:59:47 +0000 (11:59 -0500)
BNXT_RE_FLAG_TASK_IN_PROG doesn't handle multiple work
requests posted together. Track schedule of multiple
workqueue items by maintaining a per device counter
and proceed with IB dereg only if this counter is zero.
flush_workqueue is no longer required from
NETDEV_UNREGISTER path.

Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/hw/bnxt_re/bnxt_re.h
drivers/infiniband/hw/bnxt_re/main.c

index ca32057..3eb7a83 100644 (file)
@@ -120,7 +120,6 @@ struct bnxt_re_dev {
 #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
 #define BNXT_RE_FLAG_ISSUE_ROCE_STATS          29
        struct net_device               *netdev;
        unsigned int                    version, major, minor;
@@ -158,6 +157,7 @@ struct bnxt_re_dev {
        atomic_t                        srq_count;
        atomic_t                        mr_count;
        atomic_t                        mw_count;
+       atomic_t                        sched_count;
        /* Max of 2 lossless traffic class supported per port */
        u16                             cosq[2];
 
index 7f9298d..33a4480 100644 (file)
@@ -656,7 +656,6 @@ static void bnxt_re_dev_remove(struct bnxt_re_dev *rdev)
        mutex_unlock(&bnxt_re_dev_lock);
 
        synchronize_rcu();
-       flush_workqueue(bnxt_re_wq);
 
        ib_dealloc_device(&rdev->ibdev);
        /* rdev is gone */
@@ -1441,7 +1440,7 @@ static void bnxt_re_task(struct work_struct *work)
                break;
        }
        smp_mb__before_atomic();
-       clear_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags);
+       atomic_dec(&rdev->sched_count);
        kfree(re_work);
 }
 
@@ -1503,7 +1502,7 @@ static int bnxt_re_netdev_event(struct notifier_block *notifier,
                /* 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))
+               if (atomic_read(&rdev->sched_count) > 0)
                        goto exit;
                bnxt_re_ib_unreg(rdev, false);
                bnxt_re_remove_one(rdev);
@@ -1523,7 +1522,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);
+                       atomic_inc(&rdev->sched_count);
                        queue_work(bnxt_re_wq, &re_work->work);
                }
        }