diff options
-rw-r--r-- | net/mac80211/sta_info.c | 42 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 3 |
2 files changed, 41 insertions, 4 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 08e50760e092..89d449d0de6d 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -794,7 +794,7 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
794 | return have_buffered; | 794 | return have_buffered; |
795 | } | 795 | } |
796 | 796 | ||
797 | int __must_check __sta_info_destroy(struct sta_info *sta) | 797 | static int __must_check __sta_info_destroy_part1(struct sta_info *sta) |
798 | { | 798 | { |
799 | struct ieee80211_local *local; | 799 | struct ieee80211_local *local; |
800 | struct ieee80211_sub_if_data *sdata; | 800 | struct ieee80211_sub_if_data *sdata; |
@@ -831,7 +831,23 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
831 | rcu_access_pointer(sdata->u.vlan.sta) == sta) | 831 | rcu_access_pointer(sdata->u.vlan.sta) == sta) |
832 | RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); | 832 | RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); |
833 | 833 | ||
834 | synchronize_net(); | 834 | return 0; |
835 | } | ||
836 | |||
837 | static void __sta_info_destroy_part2(struct sta_info *sta) | ||
838 | { | ||
839 | struct ieee80211_local *local = sta->local; | ||
840 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
841 | int ret; | ||
842 | |||
843 | /* | ||
844 | * NOTE: This assumes at least synchronize_net() was done | ||
845 | * after _part1 and before _part2! | ||
846 | */ | ||
847 | |||
848 | might_sleep(); | ||
849 | lockdep_assert_held(&local->sta_mtx); | ||
850 | |||
835 | /* now keys can no longer be reached */ | 851 | /* now keys can no longer be reached */ |
836 | ieee80211_free_sta_keys(local, sta); | 852 | ieee80211_free_sta_keys(local, sta); |
837 | 853 | ||
@@ -863,6 +879,18 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
863 | ieee80211_recalc_min_chandef(sdata); | 879 | ieee80211_recalc_min_chandef(sdata); |
864 | 880 | ||
865 | cleanup_single_sta(sta); | 881 | cleanup_single_sta(sta); |
882 | } | ||
883 | |||
884 | int __must_check __sta_info_destroy(struct sta_info *sta) | ||
885 | { | ||
886 | int err = __sta_info_destroy_part1(sta); | ||
887 | |||
888 | if (err) | ||
889 | return err; | ||
890 | |||
891 | synchronize_net(); | ||
892 | |||
893 | __sta_info_destroy_part2(sta); | ||
866 | 894 | ||
867 | return 0; | 895 | return 0; |
868 | } | 896 | } |
@@ -936,6 +964,7 @@ int sta_info_flush(struct ieee80211_sub_if_data *sdata) | |||
936 | { | 964 | { |
937 | struct ieee80211_local *local = sdata->local; | 965 | struct ieee80211_local *local = sdata->local; |
938 | struct sta_info *sta, *tmp; | 966 | struct sta_info *sta, *tmp; |
967 | LIST_HEAD(free_list); | ||
939 | int ret = 0; | 968 | int ret = 0; |
940 | 969 | ||
941 | might_sleep(); | 970 | might_sleep(); |
@@ -943,10 +972,17 @@ int sta_info_flush(struct ieee80211_sub_if_data *sdata) | |||
943 | mutex_lock(&local->sta_mtx); | 972 | mutex_lock(&local->sta_mtx); |
944 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { | 973 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { |
945 | if (sdata == sta->sdata) { | 974 | if (sdata == sta->sdata) { |
946 | WARN_ON(__sta_info_destroy(sta)); | 975 | if (!WARN_ON(__sta_info_destroy_part1(sta))) |
976 | list_add(&sta->free_list, &free_list); | ||
947 | ret++; | 977 | ret++; |
948 | } | 978 | } |
949 | } | 979 | } |
980 | |||
981 | if (!list_empty(&free_list)) { | ||
982 | synchronize_net(); | ||
983 | list_for_each_entry_safe(sta, tmp, &free_list, free_list) | ||
984 | __sta_info_destroy_part2(sta); | ||
985 | } | ||
950 | mutex_unlock(&local->sta_mtx); | 986 | mutex_unlock(&local->sta_mtx); |
951 | 987 | ||
952 | return ret; | 988 | return ret; |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 9104f812e9de..f6081e574a28 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -247,6 +247,7 @@ struct ieee80211_tx_latency_stat { | |||
247 | * mac80211 is communicating with. | 247 | * mac80211 is communicating with. |
248 | * | 248 | * |
249 | * @list: global linked list entry | 249 | * @list: global linked list entry |
250 | * @free_list: list entry for keeping track of stations to free | ||
250 | * @hnext: hash table linked list pointer | 251 | * @hnext: hash table linked list pointer |
251 | * @local: pointer to the global information | 252 | * @local: pointer to the global information |
252 | * @sdata: virtual interface this station belongs to | 253 | * @sdata: virtual interface this station belongs to |
@@ -329,7 +330,7 @@ struct ieee80211_tx_latency_stat { | |||
329 | */ | 330 | */ |
330 | struct sta_info { | 331 | struct sta_info { |
331 | /* General information, mostly static */ | 332 | /* General information, mostly static */ |
332 | struct list_head list; | 333 | struct list_head list, free_list; |
333 | struct rcu_head rcu_head; | 334 | struct rcu_head rcu_head; |
334 | struct sta_info __rcu *hnext; | 335 | struct sta_info __rcu *hnext; |
335 | struct ieee80211_local *local; | 336 | struct ieee80211_local *local; |