Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Johannes Berg and committed by
John W. Linville
523d2f69 8cdb0456

+15 -13
+15 -13
net/mac80211/key.c
··· 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 { ··· 142 140 ret = drv_set_key(key->local, SET_KEY, &sdata->vif, sta, &key->conf); 143 141 144 142 if (!ret) { 145 - spin_lock(&todo_lock); 143 + spin_lock_bh(&todo_lock); 146 144 key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; 147 - spin_unlock(&todo_lock); 145 + spin_unlock_bh(&todo_lock); 148 146 } 149 147 150 148 if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) ··· 166 164 if (!key || !key->local->ops->set_key) 167 165 return; 168 166 169 - spin_lock(&todo_lock); 167 + spin_lock_bh(&todo_lock); 170 168 if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { 171 - spin_unlock(&todo_lock); 169 + spin_unlock_bh(&todo_lock); 172 170 return; 173 171 } 174 - spin_unlock(&todo_lock); 172 + spin_unlock_bh(&todo_lock); 175 173 176 174 sta = get_sta_for_key(key); 177 175 sdata = key->sdata; ··· 190 188 wiphy_name(key->local->hw.wiphy), 191 189 key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); 192 190 193 - spin_lock(&todo_lock); 191 + spin_lock_bh(&todo_lock); 194 192 key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; 195 - spin_unlock(&todo_lock); 193 + spin_unlock_bh(&todo_lock); 196 194 } 197 195 198 196 static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, ··· 439 437 440 438 __ieee80211_key_replace(sdata, sta, old_key, key); 441 439 442 - spin_unlock_irqrestore(&sdata->local->key_lock, flags); 443 - 444 440 /* free old key later */ 445 441 add_todo(old_key, KEY_FLAG_TODO_DELETE); 446 442 447 443 add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS); 448 444 if (netif_running(sdata->dev)) 449 445 add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD); 446 + 447 + spin_unlock_irqrestore(&sdata->local->key_lock, flags); 450 448 } 451 449 452 450 static void __ieee80211_key_free(struct ieee80211_key *key) ··· 549 547 */ 550 548 synchronize_rcu(); 551 549 552 - spin_lock(&todo_lock); 550 + spin_lock_bh(&todo_lock); 553 551 while (!list_empty(&todo_list)) { 554 552 key = list_first_entry(&todo_list, struct ieee80211_key, todo); 555 553 list_del_init(&key->todo); ··· 560 558 KEY_FLAG_TODO_HWACCEL_REMOVE | 561 559 KEY_FLAG_TODO_DELETE); 562 560 key->flags &= ~todoflags; 563 - spin_unlock(&todo_lock); 561 + spin_unlock_bh(&todo_lock); 564 562 565 563 work_done = false; 566 564 ··· 593 591 594 592 WARN_ON(!work_done); 595 593 596 - spin_lock(&todo_lock); 594 + spin_lock_bh(&todo_lock); 597 595 } 598 - spin_unlock(&todo_lock); 596 + spin_unlock_bh(&todo_lock); 599 597 } 600 598 601 599 void ieee80211_key_todo(void)