diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-04-08 11:56:52 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-04-08 16:44:45 -0400 |
commit | 3b96766f0e643f52ae19e134664df6730c737e87 (patch) | |
tree | b1707d94a14c9777f09b1aab33970e7741190d4c /net/mac80211/sta_info.c | |
parent | 7d1559f1737d5ca27b267b0392015f42b3bbe2fa (diff) |
mac80211: fix key vs. sta locking problems
Up to now, key manipulation is supposed to run under RTNL to
avoid concurrent manipulations and also allow the set_key()
hardware callback to sleep. This is not feasible because STA
structs are rcu-protected and thus a lot of operations there
cannot take the RTNL. Also, key references are rcu-protected
so we cannot do things atomically.
This patch changes key locking completely:
* key operations are now atomic
* hardware crypto offload is enabled and disabled from
a workqueue, due to that key freeing is also delayed
* debugfs code is also run from a workqueue
* keys reference STAs (and vice versa!) so during STA
unlink the STAs key reference is removed but not the
keys STA reference, to avoid races key todo work is
run before STA destruction.
* fewer STA operations now need the RTNL which was
required due to key operations
This fixes the locking problems lockdep pointed out and also
makes things more light-weight because the rtnl isn't required
as much.
Note that the key todo lock/key mutex are global locks, this
is not required, of course, they could be per-hardware instead.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r-- | net/mac80211/sta_info.c | 48 |
1 files changed, 22 insertions, 26 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index cedd73a0c875..5540cbf7c445 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -51,17 +51,15 @@ | |||
51 | * | 51 | * |
52 | * In order to remove a STA info structure, the caller needs to first | 52 | * In order to remove a STA info structure, the caller needs to first |
53 | * unlink it (sta_info_unlink()) from the list and hash tables and | 53 | * unlink it (sta_info_unlink()) from the list and hash tables and |
54 | * then destroy it while holding the RTNL; sta_info_destroy() will wait | 54 | * then destroy it; sta_info_destroy() will wait for an RCU grace period |
55 | * for an RCU grace period to elapse before actually freeing it. Due to | 55 | * to elapse before actually freeing it. Due to the pinning and the |
56 | * the pinning and the possibility of multiple callers trying to remove | 56 | * possibility of multiple callers trying to remove the same STA info at |
57 | * the same STA info at the same time, sta_info_unlink() can clear the | 57 | * the same time, sta_info_unlink() can clear the STA info pointer it is |
58 | * STA info pointer it is passed to indicate that the STA info is owned | 58 | * passed to indicate that the STA info is owned by somebody else now. |
59 | * by somebody else now. | ||
60 | * | 59 | * |
61 | * If sta_info_unlink() did not clear the pointer then the caller owns | 60 | * If sta_info_unlink() did not clear the pointer then the caller owns |
62 | * the STA info structure now and is responsible of destroying it with | 61 | * the STA info structure now and is responsible of destroying it with |
63 | * a call to sta_info_destroy(), not before RCU synchronisation, of | 62 | * a call to sta_info_destroy(). |
64 | * course. Note that sta_info_destroy() must be protected by the RTNL. | ||
65 | * | 63 | * |
66 | * In all other cases, there is no concept of ownership on a STA entry, | 64 | * In all other cases, there is no concept of ownership on a STA entry, |
67 | * each structure is owned by the global hash table/list until it is | 65 | * each structure is owned by the global hash table/list until it is |
@@ -164,7 +162,6 @@ void sta_info_destroy(struct sta_info *sta) | |||
164 | struct sk_buff *skb; | 162 | struct sk_buff *skb; |
165 | int i; | 163 | int i; |
166 | 164 | ||
167 | ASSERT_RTNL(); | ||
168 | might_sleep(); | 165 | might_sleep(); |
169 | 166 | ||
170 | if (!sta) | 167 | if (!sta) |
@@ -180,22 +177,16 @@ void sta_info_destroy(struct sta_info *sta) | |||
180 | mesh_plink_deactivate(sta); | 177 | mesh_plink_deactivate(sta); |
181 | #endif | 178 | #endif |
182 | 179 | ||
183 | if (sta->key) { | 180 | /* |
184 | /* | 181 | * We have only unlinked the key, and actually destroying it |
185 | * NOTE: This will call synchronize_rcu() internally to | 182 | * may mean it is removed from hardware which requires that |
186 | * make sure no key references can be in use. We rely on | 183 | * the key->sta pointer is still valid, so flush the key todo |
187 | * that when we take this branch to make sure nobody can | 184 | * list here. |
188 | * reference this STA struct any longer! | 185 | * |
189 | */ | 186 | * ieee80211_key_todo() will synchronize_rcu() so after this |
190 | ieee80211_key_free(sta->key); | 187 | * nothing can reference this sta struct any more. |
191 | WARN_ON(sta->key); | 188 | */ |
192 | } else { | 189 | ieee80211_key_todo(); |
193 | /* | ||
194 | * Make sure that nobody can reference this STA struct | ||
195 | * any longer. | ||
196 | */ | ||
197 | synchronize_rcu(); | ||
198 | } | ||
199 | 190 | ||
200 | #ifdef CONFIG_MAC80211_MESH | 191 | #ifdef CONFIG_MAC80211_MESH |
201 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | 192 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) |
@@ -439,6 +430,11 @@ void __sta_info_unlink(struct sta_info **sta) | |||
439 | return; | 430 | return; |
440 | } | 431 | } |
441 | 432 | ||
433 | if ((*sta)->key) { | ||
434 | ieee80211_key_free((*sta)->key); | ||
435 | WARN_ON((*sta)->key); | ||
436 | } | ||
437 | |||
442 | list_del(&(*sta)->list); | 438 | list_del(&(*sta)->list); |
443 | 439 | ||
444 | if ((*sta)->flags & WLAN_STA_PS) { | 440 | if ((*sta)->flags & WLAN_STA_PS) { |
@@ -652,7 +648,7 @@ static void sta_info_debugfs_add_work(struct work_struct *work) | |||
652 | } | 648 | } |
653 | #endif | 649 | #endif |
654 | 650 | ||
655 | void __ieee80211_run_pending_flush(struct ieee80211_local *local) | 651 | static void __ieee80211_run_pending_flush(struct ieee80211_local *local) |
656 | { | 652 | { |
657 | struct sta_info *sta; | 653 | struct sta_info *sta; |
658 | unsigned long flags; | 654 | unsigned long flags; |