diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-04-08 19:56:52 +0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-04-09 00:44:45 +0400 |
commit | 3b96766f0e643f52ae19e134664df6730c737e87 (patch) | |
tree | b1707d94a14c9777f09b1aab33970e7741190d4c /net/mac80211/debugfs_key.c | |
parent | 7d1559f1737d5ca27b267b0392015f42b3bbe2fa (diff) | |
download | linux-3b96766f0e643f52ae19e134664df6730c737e87.tar.xz |
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/debugfs_key.c')
-rw-r--r-- | net/mac80211/debugfs_key.c | 37 |
1 files changed, 18 insertions, 19 deletions
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index c881524c8725..459f0767fae5 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -184,23 +184,35 @@ KEY_OPS(key); key->debugfs.name = debugfs_create_file(#name, 0400,\ key->debugfs.dir, key, &key_##name##_ops); -void ieee80211_debugfs_key_add(struct ieee80211_local *local, - struct ieee80211_key *key) -{ +void ieee80211_debugfs_key_add(struct ieee80211_key *key) + { static int keycount; - char buf[20]; + char buf[50]; + DECLARE_MAC_BUF(mac); + struct sta_info *sta; - if (!local->debugfs.keys) + if (!key->local->debugfs.keys) return; sprintf(buf, "%d", keycount); keycount++; key->debugfs.dir = debugfs_create_dir(buf, - local->debugfs.keys); + key->local->debugfs.keys); if (!key->debugfs.dir) return; + rcu_read_lock(); + sta = rcu_dereference(key->sta); + if (sta) + sprintf(buf, "../../stations/%s", print_mac(mac, sta->addr)); + rcu_read_unlock(); + + /* using sta as a boolean is fine outside RCU lock */ + if (sta) + key->debugfs.stalink = + debugfs_create_symlink("station", key->debugfs.dir, buf); + DEBUGFS_ADD(keylen); DEBUGFS_ADD(flags); DEBUGFS_ADD(keyidx); @@ -258,19 +270,6 @@ void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata) debugfs_remove(sdata->debugfs.default_key); sdata->debugfs.default_key = NULL; } -void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key, - struct sta_info *sta) -{ - char buf[50]; - DECLARE_MAC_BUF(mac); - - if (!key->debugfs.dir) - return; - - sprintf(buf, "../../stations/%s", print_mac(mac, sta->addr)); - key->debugfs.stalink = - debugfs_create_symlink("station", key->debugfs.dir, buf); -} void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, struct sta_info *sta) |