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
This commit is contained in:

committed by
nshrivas

parent
6c1cdf307a
commit
03db80d4e7
@@ -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_objmgr_vdev *comp_vdev = (struct wlan_objmgr_vdev *)object;
|
||||||
struct wlan_vdev_ch_check_filter *ch_filter = arg;
|
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;
|
struct wlan_channel *iter_vdev_chan;
|
||||||
|
|
||||||
if (ch_filter->flag)
|
if (ch_filter->flag)
|
||||||
@@ -321,25 +321,27 @@ static void wlan_pdev_chan_match(struct wlan_objmgr_pdev *pdev, void *object,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
wlan_vdev_obj_lock(comp_vdev);
|
wlan_vdev_obj_lock(comp_vdev);
|
||||||
wlan_vdev_obj_lock(ch_filter->vdev);
|
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);
|
||||||
|
|
||||||
vdev_chan = wlan_vdev_get_active_channel(comp_vdev);
|
wlan_vdev_obj_lock(ch_filter->vdev);
|
||||||
if (vdev_chan) {
|
iter_vdev_chan = wlan_vdev_mlme_get_des_chan(ch_filter->vdev);
|
||||||
iter_vdev_chan = wlan_vdev_mlme_get_des_chan(
|
if (wlan_chan_eq(&vdev_chan, iter_vdev_chan)
|
||||||
ch_filter->vdev);
|
|
||||||
if (wlan_chan_eq(vdev_chan, iter_vdev_chan)
|
|
||||||
!= QDF_STATUS_SUCCESS) {
|
!= QDF_STATUS_SUCCESS) {
|
||||||
ch_filter->flag = 1;
|
ch_filter->flag = 1;
|
||||||
|
|
||||||
qdf_nofl_err("==> iter vdev id: %d: ieee %d, mode %d",
|
qdf_nofl_err("==> iter vdev id: %d: ieee %d, mode %d",
|
||||||
wlan_vdev_get_id(comp_vdev),
|
wlan_vdev_get_id(comp_vdev),
|
||||||
vdev_chan->ch_ieee,
|
vdev_chan.ch_ieee,
|
||||||
vdev_chan->ch_phymode);
|
vdev_chan.ch_phymode);
|
||||||
qdf_nofl_err("fl %016llx, fl-ext %08x, s1 %d, s2 %d ",
|
qdf_nofl_err("fl %016llx, fl-ext %08x, s1 %d, s2 %d ",
|
||||||
vdev_chan->ch_flags, vdev_chan->ch_flagext,
|
vdev_chan.ch_flags, vdev_chan.ch_flagext,
|
||||||
vdev_chan->ch_freq_seg1,
|
vdev_chan.ch_freq_seg1,
|
||||||
vdev_chan->ch_freq_seg2);
|
vdev_chan.ch_freq_seg2);
|
||||||
|
|
||||||
qdf_nofl_err("==> base vdev id: %d: ieee %d mode %d",
|
qdf_nofl_err("==> base vdev id: %d: ieee %d mode %d",
|
||||||
wlan_vdev_get_id(ch_filter->vdev),
|
wlan_vdev_get_id(ch_filter->vdev),
|
||||||
iter_vdev_chan->ch_ieee,
|
iter_vdev_chan->ch_ieee,
|
||||||
@@ -350,10 +352,7 @@ static void wlan_pdev_chan_match(struct wlan_objmgr_pdev *pdev, void *object,
|
|||||||
iter_vdev_chan->ch_freq_seg1,
|
iter_vdev_chan->ch_freq_seg1,
|
||||||
iter_vdev_chan->ch_freq_seg2);
|
iter_vdev_chan->ch_freq_seg2);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
wlan_vdev_obj_unlock(ch_filter->vdev);
|
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,
|
QDF_STATUS wlan_util_pdev_vdevs_deschan_match(struct wlan_objmgr_pdev *pdev,
|
||||||
|
Reference in New Issue
Block a user