Commit 523d2f6982136d332c9b7dd00e9e16da1091f060

Authored by Johannes Berg
Committed by John W. Linville
1 parent 8cdb045632

mac80211: fix todo lock

The key todo lock can be taken from different locks
that require it to be _bh to avoid lock inversion
due to (soft)irqs.

This should fix the two problems reported by Bob and
Gabor:
http://mid.gmane.org/20090619113049.GB18956@hash.localnet
http://mid.gmane.org/4A3FA376.8020307@openwrt.org

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Cc: Bob Copeland <me@bobcopeland.com>
Cc: Gabor Juhos <juhosg@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

Showing 1 changed file with 15 additions and 13 deletions Side-by-side Diff

... ... @@ -67,6 +67,8 @@
67 67 *
68 68 * @key: key to add to do item for
69 69 * @flag: todo flag(s)
  70 + *
  71 + * Must be called with IRQs or softirqs disabled.
70 72 */
71 73 static void add_todo(struct ieee80211_key *key, u32 flag)
72 74 {
73 75  
... ... @@ -140,9 +142,9 @@
140 142 ret = drv_set_key(key->local, SET_KEY, &sdata->vif, sta, &key->conf);
141 143  
142 144 if (!ret) {
143   - spin_lock(&todo_lock);
  145 + spin_lock_bh(&todo_lock);
144 146 key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
145   - spin_unlock(&todo_lock);
  147 + spin_unlock_bh(&todo_lock);
146 148 }
147 149  
148 150 if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
149 151  
150 152  
... ... @@ -164,12 +166,12 @@
164 166 if (!key || !key->local->ops->set_key)
165 167 return;
166 168  
167   - spin_lock(&todo_lock);
  169 + spin_lock_bh(&todo_lock);
168 170 if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
169   - spin_unlock(&todo_lock);
  171 + spin_unlock_bh(&todo_lock);
170 172 return;
171 173 }
172   - spin_unlock(&todo_lock);
  174 + spin_unlock_bh(&todo_lock);
173 175  
174 176 sta = get_sta_for_key(key);
175 177 sdata = key->sdata;
176 178  
... ... @@ -188,9 +190,9 @@
188 190 wiphy_name(key->local->hw.wiphy),
189 191 key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
190 192  
191   - spin_lock(&todo_lock);
  193 + spin_lock_bh(&todo_lock);
192 194 key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
193   - spin_unlock(&todo_lock);
  195 + spin_unlock_bh(&todo_lock);
194 196 }
195 197  
196 198 static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
197 199  
... ... @@ -437,14 +439,14 @@
437 439  
438 440 __ieee80211_key_replace(sdata, sta, old_key, key);
439 441  
440   - spin_unlock_irqrestore(&sdata->local->key_lock, flags);
441   -
442 442 /* free old key later */
443 443 add_todo(old_key, KEY_FLAG_TODO_DELETE);
444 444  
445 445 add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS);
446 446 if (netif_running(sdata->dev))
447 447 add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD);
  448 +
  449 + spin_unlock_irqrestore(&sdata->local->key_lock, flags);
448 450 }
449 451  
450 452 static void __ieee80211_key_free(struct ieee80211_key *key)
... ... @@ -547,7 +549,7 @@
547 549 */
548 550 synchronize_rcu();
549 551  
550   - spin_lock(&todo_lock);
  552 + spin_lock_bh(&todo_lock);
551 553 while (!list_empty(&todo_list)) {
552 554 key = list_first_entry(&todo_list, struct ieee80211_key, todo);
553 555 list_del_init(&key->todo);
... ... @@ -558,7 +560,7 @@
558 560 KEY_FLAG_TODO_HWACCEL_REMOVE |
559 561 KEY_FLAG_TODO_DELETE);
560 562 key->flags &= ~todoflags;
561   - spin_unlock(&todo_lock);
  563 + spin_unlock_bh(&todo_lock);
562 564  
563 565 work_done = false;
564 566  
565 567  
... ... @@ -591,9 +593,9 @@
591 593  
592 594 WARN_ON(!work_done);
593 595  
594   - spin_lock(&todo_lock);
  596 + spin_lock_bh(&todo_lock);
595 597 }
596   - spin_unlock(&todo_lock);
  598 + spin_unlock_bh(&todo_lock);
597 599 }
598 600  
599 601 void ieee80211_key_todo(void)