From 8fdd274a24c7e753b3c92108dfffd2a662e2c7c5 Mon Sep 17 00:00:00 2001 From: Jingxiang Ge Date: Sat, 12 Oct 2019 12:40:37 +0800 Subject: [PATCH] qcacld-3.0: Vdev trans return directly if psoc/driver is in transition Issue happen when: thread1: rmmod driver, wlan_hdd_pld_remove which will get psoc trans. then try to get rntl_lock in hdd_unregister_wext; thread2: trigger iw del interface, cfgops in kernel will get get rtnl_lock, in wlan_hdd_del_virtual_intf, vdev trans will be blocked by psoc trans in thread1. as thread1 it is also waiting for rtnl_lock, so both thread will be stuck. Fix is: In psoc trans, vdev trans and vdev ops is not allowed, which should return directly. Change-Id: I9cbd04bac438bb9483b4e89e73801fe71859e139 CRs-Fixed: 2583675 --- components/dsc/src/wlan_dsc_vdev.c | 10 +++++----- components/dsc/test/wlan_dsc_test.c | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/components/dsc/src/wlan_dsc_vdev.c b/components/dsc/src/wlan_dsc_vdev.c index edb9bd91b2..95d39692ea 100644 --- a/components/dsc/src/wlan_dsc_vdev.c +++ b/components/dsc/src/wlan_dsc_vdev.c @@ -115,11 +115,11 @@ void dsc_vdev_destroy(struct dsc_vdev **out_vdev) * This function checks if the vdev transition can occur or not by checking if * any other down the tree/up the tree transition/operation is taking place. * - * If there are any driver transition taking place, then the vdev trans/ops + * If there are any driver/psoc transition taking place, then the vdev trans/ops * should be rejected and not queued in the DSC queue. Return QDF_STATUS_E_INVAL * in this case. * - * If there any psoc or vdev trans/ops is taking place, then the vdev trans/ops + * If there are any vdev trans/ops taking place, then the vdev trans/ops * should be rejected and queued in the DSC queue so that it may be resumed * after the current trans/ops is completed. Return QDF_STATUS_E_AGAIN in this * case. @@ -128,11 +128,11 @@ void dsc_vdev_destroy(struct dsc_vdev **out_vdev) */ static QDF_STATUS __dsc_vdev_can_trans(struct dsc_vdev *vdev) { - if (__dsc_trans_active_or_queued(&vdev->psoc->driver->trans)) + if (__dsc_trans_active_or_queued(&vdev->psoc->driver->trans) || + __dsc_trans_active_or_queued(&vdev->psoc->trans)) return QDF_STATUS_E_INVAL; - if (__dsc_trans_active_or_queued(&vdev->psoc->trans) || - __dsc_trans_active_or_queued(&vdev->trans)) + if (__dsc_trans_active_or_queued(&vdev->trans)) return QDF_STATUS_E_AGAIN; return QDF_STATUS_SUCCESS; diff --git a/components/dsc/test/wlan_dsc_test.c b/components/dsc/test/wlan_dsc_test.c index 0332678906..5871cdf5b6 100644 --- a/components/dsc/test/wlan_dsc_test.c +++ b/components/dsc/test/wlan_dsc_test.c @@ -264,8 +264,8 @@ static uint32_t dsc_test_psoc_trans_blocks(void) /* ... children vdev trans/ops to fail */ dsc_for_each_psoc_vdev(psoc, vdev) { - action_expect(vdev, trans, QDF_STATUS_E_AGAIN, errors); - action_expect(vdev, op, QDF_STATUS_E_AGAIN, errors); + action_expect(vdev, trans, QDF_STATUS_E_INVAL, errors); + action_expect(vdev, op, QDF_STATUS_E_INVAL, errors); } /* a sibling psoc in transition should succeed and cause ... */ @@ -282,8 +282,8 @@ static uint32_t dsc_test_psoc_trans_blocks(void) /* ... children vdev trans/ops to fail */ dsc_for_each_psoc_vdev(psoc, vdev) { - action_expect(vdev, trans, QDF_STATUS_E_AGAIN, errors); - action_expect(vdev, op, QDF_STATUS_E_AGAIN, errors); + action_expect(vdev, trans, QDF_STATUS_E_INVAL, errors); + action_expect(vdev, op, QDF_STATUS_E_INVAL, errors); } /* teardown */