Jelajahi Sumber

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
Jingxiang Ge 5 tahun lalu
induk
melakukan
8fdd274a24

+ 5 - 5
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;

+ 4 - 4
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 */