소스 검색

qcacmn: Fix deadlock in wlan_pdev_chan_match due to cross locking

wlan_pdev_chan_match used to take current vdev lock on current
iterating vdev and then on vdev for which channel set is triggered.
If two cores happed to try setting channel on two different vdevs,
cross locking may occur. Fix this by releasing one lock and then
acquiring other lock.

Change-Id: Ic1a6ca448c6d535e949102bc5a8a45971c8babd2
CRs-Fixed: 2460054
Om Prakash Tripathi 5 년 전
부모
커밋
03db80d4e7
1개의 변경된 파일30개의 추가작업 그리고 31개의 파일을 삭제
  1. 30 31
      umac/cmn_services/utils/src/wlan_utility.c

+ 30 - 31
umac/cmn_services/utils/src/wlan_utility.c

@@ -311,7 +311,7 @@ static void wlan_pdev_chan_match(struct wlan_objmgr_pdev *pdev, void *object,
 {
 	struct wlan_objmgr_vdev *comp_vdev = (struct wlan_objmgr_vdev *)object;
 	struct wlan_vdev_ch_check_filter *ch_filter = arg;
-	struct wlan_channel *vdev_chan;
+	struct wlan_channel vdev_chan, *chan;
 	struct wlan_channel *iter_vdev_chan;
 
 	if (ch_filter->flag)
@@ -321,39 +321,38 @@ static void wlan_pdev_chan_match(struct wlan_objmgr_pdev *pdev, void *object,
 		return;
 
 	wlan_vdev_obj_lock(comp_vdev);
-	wlan_vdev_obj_lock(ch_filter->vdev);
-
-	vdev_chan = wlan_vdev_get_active_channel(comp_vdev);
-	if (vdev_chan) {
-		iter_vdev_chan = wlan_vdev_mlme_get_des_chan(
-							ch_filter->vdev);
-		if (wlan_chan_eq(vdev_chan, iter_vdev_chan)
-						!= QDF_STATUS_SUCCESS) {
-			ch_filter->flag = 1;
-
-			qdf_nofl_err("==> iter vdev id: %d: ieee %d, mode %d",
-				     wlan_vdev_get_id(comp_vdev),
-				     vdev_chan->ch_ieee,
-				     vdev_chan->ch_phymode);
-			qdf_nofl_err("fl %016llx, fl-ext %08x, s1 %d, s2 %d ",
-				     vdev_chan->ch_flags, vdev_chan->ch_flagext,
-				     vdev_chan->ch_freq_seg1,
-				     vdev_chan->ch_freq_seg2);
-
-			qdf_nofl_err("==> base vdev id: %d: ieee %d mode %d",
-				     wlan_vdev_get_id(ch_filter->vdev),
-				     iter_vdev_chan->ch_ieee,
-				     iter_vdev_chan->ch_phymode);
-			qdf_nofl_err("fl %016llx, fl-ext %08x s1 %d, s2 %d",
-				     iter_vdev_chan->ch_flags,
-				     iter_vdev_chan->ch_flagext,
-				     iter_vdev_chan->ch_freq_seg1,
-				     iter_vdev_chan->ch_freq_seg2);
-		}
+	chan = wlan_vdev_get_active_channel(comp_vdev);
+	if (!chan) {
+		wlan_vdev_obj_unlock(comp_vdev);
+		return;
 	}
+	wlan_chan_copy(&vdev_chan, chan);
+	wlan_vdev_obj_unlock(comp_vdev);
 
+	wlan_vdev_obj_lock(ch_filter->vdev);
+	iter_vdev_chan = wlan_vdev_mlme_get_des_chan(ch_filter->vdev);
+	if (wlan_chan_eq(&vdev_chan, iter_vdev_chan)
+		!= QDF_STATUS_SUCCESS) {
+		ch_filter->flag = 1;
+		qdf_nofl_err("==> iter vdev id: %d: ieee %d, mode %d",
+			     wlan_vdev_get_id(comp_vdev),
+			     vdev_chan.ch_ieee,
+			     vdev_chan.ch_phymode);
+		qdf_nofl_err("fl %016llx, fl-ext %08x, s1 %d, s2 %d ",
+			     vdev_chan.ch_flags, vdev_chan.ch_flagext,
+			     vdev_chan.ch_freq_seg1,
+			     vdev_chan.ch_freq_seg2);
+		qdf_nofl_err("==> base vdev id: %d: ieee %d mode %d",
+			     wlan_vdev_get_id(ch_filter->vdev),
+			     iter_vdev_chan->ch_ieee,
+			     iter_vdev_chan->ch_phymode);
+		qdf_nofl_err("fl %016llx, fl-ext %08x s1 %d, s2 %d",
+			     iter_vdev_chan->ch_flags,
+			     iter_vdev_chan->ch_flagext,
+			     iter_vdev_chan->ch_freq_seg1,
+			     iter_vdev_chan->ch_freq_seg2);
+	}
 	wlan_vdev_obj_unlock(ch_filter->vdev);
-	wlan_vdev_obj_unlock(comp_vdev);
 }
 
 QDF_STATUS wlan_util_pdev_vdevs_deschan_match(struct wlan_objmgr_pdev *pdev,