summaryrefslogtreecommitdiffstats
path: root/net/wireless/core.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2010-01-17 15:49:02 +0100
committerJohn W. Linville <linville@tuxdriver.com>2010-01-19 16:43:09 -0500
commit5f2aa25e0e5b221a176ab3d1c51d51da265cb4a7 (patch)
treeb991f42ad2f5874b6ac3d8fcb1a138e889d70c19 /net/wireless/core.c
parentc57199bc32ebcd914253496486d2e09b1c9a3de0 (diff)
downloadlinux-5f2aa25e0e5b221a176ab3d1c51d51da265cb4a7.tar.bz2
cfg80211: rcu-ify rdev and wdev
Future code will need to look up rdev and wdev within atomic sections, but currently we need to lock a mutex for such lookups. Change the list handling for both to be RCU-safe so that we can look them up in rcu sections instead in the future. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/core.c')
-rw-r--r--net/wireless/core.c26
1 files changed, 15 insertions, 11 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 20db90246de5..d07f57c906db 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1,7 +1,7 @@
/*
* This is the linux wireless configuration interface.
*
- * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
*/
#include <linux/if.h>
@@ -31,15 +31,10 @@ MODULE_AUTHOR("Johannes Berg");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("wireless configuration support");
-/* RCU might be appropriate here since we usually
- * only read the list, and that can happen quite
- * often because we need to do it for each command */
+/* RCU-protected (and cfg80211_mutex for writers) */
LIST_HEAD(cfg80211_rdev_list);
int cfg80211_rdev_list_generation;
-/*
- * This is used to protect the cfg80211_rdev_list
- */
DEFINE_MUTEX(cfg80211_mutex);
/* for debugfs */
@@ -477,7 +472,7 @@ int wiphy_register(struct wiphy *wiphy)
/* set up regulatory info */
wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
- list_add(&rdev->list, &cfg80211_rdev_list);
+ list_add_rcu(&rdev->list, &cfg80211_rdev_list);
cfg80211_rdev_list_generation++;
mutex_unlock(&cfg80211_mutex);
@@ -554,7 +549,8 @@ void wiphy_unregister(struct wiphy *wiphy)
* it impossible to find from userspace.
*/
debugfs_remove_recursive(rdev->wiphy.debugfsdir);
- list_del(&rdev->list);
+ list_del_rcu(&rdev->list);
+ synchronize_rcu();
/*
* Try to grab rdev->mtx. If a command is still in progress,
@@ -670,7 +666,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
INIT_LIST_HEAD(&wdev->event_list);
spin_lock_init(&wdev->event_lock);
mutex_lock(&rdev->devlist_mtx);
- list_add(&wdev->list, &rdev->netdev_list);
+ list_add_rcu(&wdev->list, &rdev->netdev_list);
rdev->devlist_generation++;
/* can only change netns with wiphy */
dev->features |= NETIF_F_NETNS_LOCAL;
@@ -782,13 +778,21 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
*/
if (!list_empty(&wdev->list)) {
sysfs_remove_link(&dev->dev.kobj, "phy80211");
- list_del_init(&wdev->list);
+ list_del_rcu(&wdev->list);
rdev->devlist_generation++;
#ifdef CONFIG_CFG80211_WEXT
kfree(wdev->wext.keys);
#endif
}
mutex_unlock(&rdev->devlist_mtx);
+ /*
+ * synchronise (so that we won't find this netdev
+ * from other code any more) and then clear the list
+ * head so that the above code can safely check for
+ * !list_empty() to avoid double-cleanup.
+ */
+ synchronize_rcu();
+ INIT_LIST_HEAD(&wdev->list);
break;
case NETDEV_PRE_UP:
if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))