diff options
-rw-r--r-- | net/mac80211/cfg.c | 9 | ||||
-rw-r--r-- | net/mac80211/iface.c | 13 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 2 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 14 |
4 files changed, 29 insertions, 9 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index be019533b233..908f1153942d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1010,8 +1010,13 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1010 | kfree_rcu(old_probe_resp, rcu_head); | 1010 | kfree_rcu(old_probe_resp, rcu_head); |
1011 | 1011 | ||
1012 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | 1012 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) |
1013 | sta_info_flush(vlan); | 1013 | sta_info_flush_defer(vlan); |
1014 | sta_info_flush(sdata); | 1014 | sta_info_flush_defer(sdata); |
1015 | rcu_barrier(); | ||
1016 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | ||
1017 | sta_info_flush_cleanup(vlan); | ||
1018 | sta_info_flush_cleanup(sdata); | ||
1019 | |||
1015 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | 1020 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
1016 | 1021 | ||
1017 | drv_stop_ap(sdata->local, sdata); | 1022 | drv_stop_ap(sdata->local, sdata); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 12341efb109e..1ab7d8e57d39 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -863,12 +863,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
863 | cancel_work_sync(&sdata->work); | 863 | cancel_work_sync(&sdata->work); |
864 | /* | 864 | /* |
865 | * When we get here, the interface is marked down. | 865 | * When we get here, the interface is marked down. |
866 | * sta_info_flush_cleanup() calls rcu_barrier to | 866 | * |
867 | * wait for the station call_rcu() calls to complete, | 867 | * sta_info_flush_cleanup() requires rcu_barrier() |
868 | * here we require it to wait for the RX path in case | 868 | * first to wait for the station call_rcu() calls |
869 | * it is using the interface and enqueuing frames at | 869 | * to complete, here we need at least sychronize_rcu() |
870 | * this very time on another CPU. | 870 | * it to wait for the RX path in case it is using the |
871 | * interface and enqueuing frames at this very time on | ||
872 | * another CPU. | ||
871 | */ | 873 | */ |
874 | rcu_barrier(); | ||
872 | sta_info_flush_cleanup(sdata); | 875 | sta_info_flush_cleanup(sdata); |
873 | 876 | ||
874 | skb_queue_purge(&sdata->skb_queue); | 877 | skb_queue_purge(&sdata->skb_queue); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 7199b9d5b2f4..738f9349c0a2 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -920,8 +920,6 @@ int sta_info_flush_defer(struct ieee80211_sub_if_data *sdata) | |||
920 | 920 | ||
921 | void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata) | 921 | void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata) |
922 | { | 922 | { |
923 | rcu_barrier(); | ||
924 | |||
925 | ieee80211_cleanup_sdata_stas(sdata); | 923 | ieee80211_cleanup_sdata_stas(sdata); |
926 | cancel_work_sync(&sdata->cleanup_stations_wk); | 924 | cancel_work_sync(&sdata->cleanup_stations_wk); |
927 | } | 925 | } |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index c3266aed4a07..031e4a5bbeca 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -549,6 +549,19 @@ void sta_info_recalc_tim(struct sta_info *sta); | |||
549 | void sta_info_init(struct ieee80211_local *local); | 549 | void sta_info_init(struct ieee80211_local *local); |
550 | void sta_info_stop(struct ieee80211_local *local); | 550 | void sta_info_stop(struct ieee80211_local *local); |
551 | int sta_info_flush_defer(struct ieee80211_sub_if_data *sdata); | 551 | int sta_info_flush_defer(struct ieee80211_sub_if_data *sdata); |
552 | |||
553 | /** | ||
554 | * sta_info_flush_cleanup - flush the sta_info cleanup queue | ||
555 | * @sdata: the interface | ||
556 | * | ||
557 | * Flushes the sta_info cleanup queue for a given interface; | ||
558 | * this is necessary before the interface is removed or, for | ||
559 | * AP/mesh interfaces, before it is deconfigured. | ||
560 | * | ||
561 | * Note an rcu_barrier() must precede the function, after all | ||
562 | * stations have been flushed/removed to ensure the call_rcu() | ||
563 | * calls that add stations to the cleanup queue have completed. | ||
564 | */ | ||
552 | void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata); | 565 | void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata); |
553 | 566 | ||
554 | /** | 567 | /** |
@@ -562,6 +575,7 @@ static inline int sta_info_flush(struct ieee80211_sub_if_data *sdata) | |||
562 | { | 575 | { |
563 | int ret = sta_info_flush_defer(sdata); | 576 | int ret = sta_info_flush_defer(sdata); |
564 | 577 | ||
578 | rcu_barrier(); | ||
565 | sta_info_flush_cleanup(sdata); | 579 | sta_info_flush_cleanup(sdata); |
566 | 580 | ||
567 | return ret; | 581 | return ret; |