aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEliad Peller <eliad@wizery.com>2012-09-09 07:43:51 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-09-10 06:44:17 -0400
commitb22cfcfcae5b2c1e9b43543b6a23e5ef517de8f8 (patch)
treeb87ec8f76a6ccdd4d8d5ed9752d4bfedf3ea04c3 /net
parente548c49e6dc6b08b59042930a2e90c69c13c9293 (diff)
mac80211: use call_rcu() on sta deletion
mac80211 calls synchronize_rcu() on sta deletion, which increase the roaming time significantly. Convert it into a call_rcu() mechanism, in order to avoid blocking. Since some of the cleanup functions might sleep, schedule from the call_rcu callback a new work that will do the actual cleanup. In order to make sure the cleanup occurs before the interface went down, flush local->workqueue on ieee80211_do_stop(). Signed-off-by: Yoni Divinsky <yoni.divinsky@ti.com> Signed-off-by: Eliad Peller <eliad@wizery.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/iface.c15
-rw-r--r--net/mac80211/sta_info.c121
-rw-r--r--net/mac80211/sta_info.h2
3 files changed, 81 insertions, 57 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index d747da541747..6f8a73c64fb3 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -793,11 +793,20 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
793 flush_work(&sdata->work); 793 flush_work(&sdata->work);
794 /* 794 /*
795 * When we get here, the interface is marked down. 795 * When we get here, the interface is marked down.
796 * Call synchronize_rcu() to wait for the RX path 796 * Call rcu_barrier() to wait both for the RX path
797 * should it be using the interface and enqueuing 797 * should it be using the interface and enqueuing
798 * frames at this very time on another CPU. 798 * frames at this very time on another CPU, and
799 * for the sta free call_rcu callbacks.
799 */ 800 */
800 synchronize_rcu(); 801 rcu_barrier();
802
803 /*
804 * free_sta_rcu() enqueues a work for the actual
805 * sta cleanup, so we need to flush it while
806 * sdata is still valid.
807 */
808 flush_workqueue(local->workqueue);
809
801 skb_queue_purge(&sdata->skb_queue); 810 skb_queue_purge(&sdata->skb_queue);
802 811
803 /* 812 /*
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 06fa75ceb025..9c8cd8b8f753 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -91,6 +91,70 @@ static int sta_info_hash_del(struct ieee80211_local *local,
91 return -ENOENT; 91 return -ENOENT;
92} 92}
93 93
94static void free_sta_work(struct work_struct *wk)
95{
96 struct sta_info *sta = container_of(wk, struct sta_info, free_sta_wk);
97 int ac, i;
98 struct tid_ampdu_tx *tid_tx;
99 struct ieee80211_sub_if_data *sdata = sta->sdata;
100 struct ieee80211_local *local = sdata->local;
101
102 /*
103 * At this point, when being called as call_rcu callback,
104 * neither mac80211 nor the driver can reference this
105 * sta struct any more except by still existing timers
106 * associated with this station that we clean up below.
107 */
108
109 if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
110 BUG_ON(!sdata->bss);
111
112 clear_sta_flag(sta, WLAN_STA_PS_STA);
113
114 atomic_dec(&sdata->bss->num_sta_ps);
115 sta_info_recalc_tim(sta);
116 }
117
118 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
119 local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]);
120 __skb_queue_purge(&sta->ps_tx_buf[ac]);
121 __skb_queue_purge(&sta->tx_filtered[ac]);
122 }
123
124#ifdef CONFIG_MAC80211_MESH
125 if (ieee80211_vif_is_mesh(&sdata->vif)) {
126 mesh_accept_plinks_update(sdata);
127 mesh_plink_deactivate(sta);
128 del_timer_sync(&sta->plink_timer);
129 }
130#endif
131
132 cancel_work_sync(&sta->drv_unblock_wk);
133
134 /*
135 * Destroy aggregation state here. It would be nice to wait for the
136 * driver to finish aggregation stop and then clean up, but for now
137 * drivers have to handle aggregation stop being requested, followed
138 * directly by station destruction.
139 */
140 for (i = 0; i < STA_TID_NUM; i++) {
141 tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);
142 if (!tid_tx)
143 continue;
144 __skb_queue_purge(&tid_tx->pending);
145 kfree(tid_tx);
146 }
147
148 sta_info_free(local, sta);
149}
150
151static void free_sta_rcu(struct rcu_head *h)
152{
153 struct sta_info *sta = container_of(h, struct sta_info, rcu_head);
154
155 ieee80211_queue_work(&sta->local->hw, &sta->free_sta_wk);
156}
157
94/* protected by RCU */ 158/* protected by RCU */
95struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, 159struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
96 const u8 *addr) 160 const u8 *addr)
@@ -241,6 +305,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
241 305
242 spin_lock_init(&sta->lock); 306 spin_lock_init(&sta->lock);
243 INIT_WORK(&sta->drv_unblock_wk, sta_unblock); 307 INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
308 INIT_WORK(&sta->free_sta_wk, free_sta_work);
244 INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); 309 INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
245 mutex_init(&sta->ampdu_mlme.mtx); 310 mutex_init(&sta->ampdu_mlme.mtx);
246 311
@@ -654,8 +719,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
654{ 719{
655 struct ieee80211_local *local; 720 struct ieee80211_local *local;
656 struct ieee80211_sub_if_data *sdata; 721 struct ieee80211_sub_if_data *sdata;
657 int ret, i, ac; 722 int ret, i;
658 struct tid_ampdu_tx *tid_tx;
659 723
660 might_sleep(); 724 might_sleep();
661 725
@@ -711,65 +775,14 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
711 WARN_ON_ONCE(ret != 0); 775 WARN_ON_ONCE(ret != 0);
712 } 776 }
713 777
714 /*
715 * At this point, after we wait for an RCU grace period,
716 * neither mac80211 nor the driver can reference this
717 * sta struct any more except by still existing timers
718 * associated with this station that we clean up below.
719 */
720 synchronize_rcu();
721
722 if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
723 BUG_ON(!sdata->bss);
724
725 clear_sta_flag(sta, WLAN_STA_PS_STA);
726
727 atomic_dec(&sdata->bss->num_sta_ps);
728 sta_info_recalc_tim(sta);
729 }
730
731 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
732 local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]);
733 __skb_queue_purge(&sta->ps_tx_buf[ac]);
734 __skb_queue_purge(&sta->tx_filtered[ac]);
735 }
736
737#ifdef CONFIG_MAC80211_MESH
738 if (ieee80211_vif_is_mesh(&sdata->vif))
739 mesh_accept_plinks_update(sdata);
740#endif
741
742 sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr); 778 sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr);
743 779
744 cancel_work_sync(&sta->drv_unblock_wk);
745
746 cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL); 780 cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL);
747 781
748 rate_control_remove_sta_debugfs(sta); 782 rate_control_remove_sta_debugfs(sta);
749 ieee80211_sta_debugfs_remove(sta); 783 ieee80211_sta_debugfs_remove(sta);
750 784
751#ifdef CONFIG_MAC80211_MESH 785 call_rcu(&sta->rcu_head, free_sta_rcu);
752 if (ieee80211_vif_is_mesh(&sta->sdata->vif)) {
753 mesh_plink_deactivate(sta);
754 del_timer_sync(&sta->plink_timer);
755 }
756#endif
757
758 /*
759 * Destroy aggregation state here. It would be nice to wait for the
760 * driver to finish aggregation stop and then clean up, but for now
761 * drivers have to handle aggregation stop being requested, followed
762 * directly by station destruction.
763 */
764 for (i = 0; i < STA_TID_NUM; i++) {
765 tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);
766 if (!tid_tx)
767 continue;
768 __skb_queue_purge(&tid_tx->pending);
769 kfree(tid_tx);
770 }
771
772 sta_info_free(local, sta);
773 786
774 return 0; 787 return 0;
775} 788}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index a470e1123a55..c88f161f8118 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -287,6 +287,7 @@ struct sta_ampdu_mlme {
287struct sta_info { 287struct sta_info {
288 /* General information, mostly static */ 288 /* General information, mostly static */
289 struct list_head list; 289 struct list_head list;
290 struct rcu_head rcu_head;
290 struct sta_info __rcu *hnext; 291 struct sta_info __rcu *hnext;
291 struct ieee80211_local *local; 292 struct ieee80211_local *local;
292 struct ieee80211_sub_if_data *sdata; 293 struct ieee80211_sub_if_data *sdata;
@@ -297,6 +298,7 @@ struct sta_info {
297 spinlock_t lock; 298 spinlock_t lock;
298 299
299 struct work_struct drv_unblock_wk; 300 struct work_struct drv_unblock_wk;
301 struct work_struct free_sta_wk;
300 302
301 u16 listen_interval; 303 u16 listen_interval;
302 304