History

mac80211: fix mesh deadlock

The patch "cfg80211/mac80211: use cfg80211 wdev mutex in mac80211" introduced several deadlocks by converting the ifmsh->mtx to wdev->mtx. Solve these by: 1. drop the cancel_work_sync() in ieee80211_stop_mesh(). Instead make the mesh work conditional on whether the mesh is running or not. 2. lock the mesh work with sdata_lock() to protect beacon updates and prevent races with wdev->mesh_id_len or cfg80211.

Thomas Pedersen committed 13 years ago

Commit ecccd071 parent 780b40d2 files · +18 −18Browse files

Unified · Split

2 files
  1. net/mac80211/mesh.c +17 −12
  2. net/mac80211/mesh_plink.c +1 −6
net/mac80211/mesh.c+17−12
@@ -579,9 +579,7 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata) · 578 unmodified lines
579579 mesh_path_expire(sdata);
580580
581581 changed = mesh_accept_plinks_update(sdata);
582− sdata_lock(sdata);
583582 ieee80211_mbss_info_change_notify(sdata, changed);
584− sdata_unlock(sdata);
585583
586584 mod_timer(&ifmsh->housekeeping_timer,
587585 round_jiffies(jiffies +
@@ -788,12 +786,10 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) · 200 unmodified lines
788786 sdata->vif.bss_conf.enable_beacon = false;
789787 clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
790788 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
791− sdata_lock(sdata);
792789 bcn = rcu_dereference_protected(ifmsh->beacon,
793790 lockdep_is_held(&sdata->wdev.mtx));
794791 rcu_assign_pointer(ifmsh->beacon, NULL);
795792 kfree_rcu(bcn, rcu_head);
796− sdata_unlock(sdata);
797793
798794 /* flush STAs and mpaths on this iface */
799795 sta_info_flush(sdata);
@@ -806,14 +802,6 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) · 6 unmodified lines
806802 del_timer_sync(&sdata->u.mesh.housekeeping_timer);
807803 del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
808804 del_timer_sync(&sdata->u.mesh.mesh_path_timer);
809− /*
810− * If the timer fired while we waited for it, it will have
811− * requeued the work. Now the work will be running again
812− * but will not rearm the timer again because it checks
813− * whether the interface is running, which, at this point,
814− * it no longer is.
815− */
816− cancel_work_sync(&sdata->work);
817805
818806 local->fif_other_bss--;
819807 atomic_dec(&local->iff_allmultis);
@@ -954,6 +942,12 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, · 134 unmodified lines
954942 struct ieee80211_mgmt *mgmt;
955943 u16 stype;
956944
945+ sdata_lock(sdata);
946+
947+ /* mesh already went down */
948+ if (!sdata->wdev.mesh_id_len)
949+ goto out;
950+
957951 rx_status = IEEE80211_SKB_RXCB(skb);
958952 mgmt = (struct ieee80211_mgmt *) skb->data;
959953 stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
@@ -971,12 +965,20 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, · 11 unmodified lines
971965 ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status);
972966 break;
973967 }
968+out:
969+ sdata_unlock(sdata);
974970 }
975971
976972 void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
977973 {
978974 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
979975
976+ sdata_lock(sdata);
977+
978+ /* mesh already went down */
979+ if (!sdata->wdev.mesh_id_len)
980+ goto out;
981+
980982 if (ifmsh->preq_queue_len &&
981983 time_after(jiffies,
982984 ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval)))
@@ -996,6 +998,9 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) · 13 unmodified lines
996998
997999 if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags))
9981000 mesh_sync_adjust_tbtt(sdata);
1001+
1002+out:
1003+ sdata_unlock(sdata);
9991004 }
10001005
10011006 void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
net/mac80211/mesh_plink.c+1−6
@@ -517,9 +517,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, · 516 unmodified lines
517517 ieee80211_mps_frame_release(sta, elems);
518518 out:
519519 rcu_read_unlock();
520− sdata_lock(sdata);
521520 ieee80211_mbss_info_change_notify(sdata, changed);
522− sdata_unlock(sdata);
523521 }
524522
525523 static void mesh_plink_timer(unsigned long data)
@@ -1070,9 +1068,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, · 544 unmodified lines
10701068
10711069 rcu_read_unlock();
10721070
1073− if (changed) {
1074− sdata_lock(sdata);
1071+ if (changed)
10751072 ieee80211_mbss_info_change_notify(sdata, changed);
1076− sdata_unlock(sdata);
1077− }
10781073 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t