diff options
author | Bharat Potnuri <bharat@chelsio.com> | 2017-11-09 13:17:33 +0100 |
---|---|---|
committer | Doug Ledford <dledford@redhat.com> | 2017-11-13 22:59:22 +0100 |
commit | 1c8f1da5d851b92aeb81dbbb9ebd516f6e2588f5 (patch) | |
tree | bc7aef9d910cdadabdfa55066b60ccad35c67714 /drivers/infiniband/hw/cxgb4/provider.c | |
parent | RDMA/bnxt_re: report vlan_id and sl in qp1 recv completion (diff) | |
download | linux-1c8f1da5d851b92aeb81dbbb9ebd516f6e2588f5.tar.xz linux-1c8f1da5d851b92aeb81dbbb9ebd516f6e2588f5.zip |
iw_cxgb4: Fix possible circular dependency locking warning
Locking sequence of iw_cxgb4 and RoCE drivers in ib_register_device() is
slightly different and this leads to possible circular dependency locking
warning when both the devices are brought up.
Here is the locking sequence upto ib_register_device():
iw_cxgb4: rtnl_mutex(net stack) --> uld_mutex --> device_mutex
RoCE drivers: device_mutex --> rtnl_mutex
Here is the possibility of cross locking:
CPU #0 (iw_cxgb4) CPU #1 (RoCE drivers)
-> on interface up cxgb4_up()
executed with rtnl_mutex held
-> hold uld_mutex and try
registering ib device
-> In ib_register_device() hold
device_mutex
-> hold device mutex in
ib_register_device
-> try acquiring rtnl_mutex in
ib_enum_roce_netdev()
Current patch schedules the ib_register_device() functionality of
iw_cxgb4 to a workqueue to prevent the possible cross-locking.
Also rename the labels in c4iw_reister_device().
Signed-off-by: Potnuri Bharat Teja <bharat@chelsio.com>
Reviewed-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
Diffstat (limited to 'drivers/infiniband/hw/cxgb4/provider.c')
-rw-r--r-- | drivers/infiniband/hw/cxgb4/provider.c | 26 |
1 files changed, 17 insertions, 9 deletions
diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c index 30206a57dbe7..1b5c6cd2ac4d 100644 --- a/drivers/infiniband/hw/cxgb4/provider.c +++ b/drivers/infiniband/hw/cxgb4/provider.c @@ -531,10 +531,12 @@ static void get_dev_fw_str(struct ib_device *dev, char *str) FW_HDR_FW_VER_BUILD_G(c4iw_dev->rdev.lldi.fw_vers)); } -int c4iw_register_device(struct c4iw_dev *dev) +void c4iw_register_device(struct work_struct *work) { int ret; int i; + struct uld_ctx *ctx = container_of(work, struct uld_ctx, reg_work); + struct c4iw_dev *dev = ctx->dev; pr_debug("c4iw_dev %p\n", dev); strlcpy(dev->ibdev.name, "cxgb4_%d", IB_DEVICE_NAME_MAX); @@ -609,8 +611,10 @@ int c4iw_register_device(struct c4iw_dev *dev) dev->ibdev.get_dev_fw_str = get_dev_fw_str; dev->ibdev.iwcm = kmalloc(sizeof(struct iw_cm_verbs), GFP_KERNEL); - if (!dev->ibdev.iwcm) - return -ENOMEM; + if (!dev->ibdev.iwcm) { + ret = -ENOMEM; + goto err_dealloc_ctx; + } dev->ibdev.iwcm->connect = c4iw_connect; dev->ibdev.iwcm->accept = c4iw_accept_cr; @@ -625,20 +629,24 @@ int c4iw_register_device(struct c4iw_dev *dev) ret = ib_register_device(&dev->ibdev, NULL); if (ret) - goto bail1; + goto err_kfree_iwcm; for (i = 0; i < ARRAY_SIZE(c4iw_class_attributes); ++i) { ret = device_create_file(&dev->ibdev.dev, c4iw_class_attributes[i]); if (ret) - goto bail2; + goto err_unregister_device; } - return 0; -bail2: + return; +err_unregister_device: ib_unregister_device(&dev->ibdev); -bail1: +err_kfree_iwcm: kfree(dev->ibdev.iwcm); - return ret; +err_dealloc_ctx: + pr_err("%s - Failed registering iwarp device: %d\n", + pci_name(ctx->lldi.pdev), ret); + c4iw_dealloc(ctx); + return; } void c4iw_unregister_device(struct c4iw_dev *dev) |