Commit 5f2aa25e authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

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: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent c57199bc
/* /*
* This is the linux wireless configuration interface. * 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> #include <linux/if.h>
...@@ -31,15 +31,10 @@ MODULE_AUTHOR("Johannes Berg"); ...@@ -31,15 +31,10 @@ MODULE_AUTHOR("Johannes Berg");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("wireless configuration support"); MODULE_DESCRIPTION("wireless configuration support");
/* RCU might be appropriate here since we usually /* RCU-protected (and cfg80211_mutex for writers) */
* only read the list, and that can happen quite
* often because we need to do it for each command */
LIST_HEAD(cfg80211_rdev_list); LIST_HEAD(cfg80211_rdev_list);
int cfg80211_rdev_list_generation; int cfg80211_rdev_list_generation;
/*
* This is used to protect the cfg80211_rdev_list
*/
DEFINE_MUTEX(cfg80211_mutex); DEFINE_MUTEX(cfg80211_mutex);
/* for debugfs */ /* for debugfs */
...@@ -477,7 +472,7 @@ int wiphy_register(struct wiphy *wiphy) ...@@ -477,7 +472,7 @@ int wiphy_register(struct wiphy *wiphy)
/* set up regulatory info */ /* set up regulatory info */
wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); 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++; cfg80211_rdev_list_generation++;
mutex_unlock(&cfg80211_mutex); mutex_unlock(&cfg80211_mutex);
...@@ -554,7 +549,8 @@ void wiphy_unregister(struct wiphy *wiphy) ...@@ -554,7 +549,8 @@ void wiphy_unregister(struct wiphy *wiphy)
* it impossible to find from userspace. * it impossible to find from userspace.
*/ */
debugfs_remove_recursive(rdev->wiphy.debugfsdir); 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, * 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, ...@@ -670,7 +666,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
INIT_LIST_HEAD(&wdev->event_list); INIT_LIST_HEAD(&wdev->event_list);
spin_lock_init(&wdev->event_lock); spin_lock_init(&wdev->event_lock);
mutex_lock(&rdev->devlist_mtx); mutex_lock(&rdev->devlist_mtx);
list_add(&wdev->list, &rdev->netdev_list); list_add_rcu(&wdev->list, &rdev->netdev_list);
rdev->devlist_generation++; rdev->devlist_generation++;
/* can only change netns with wiphy */ /* can only change netns with wiphy */
dev->features |= NETIF_F_NETNS_LOCAL; dev->features |= NETIF_F_NETNS_LOCAL;
...@@ -782,13 +778,21 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, ...@@ -782,13 +778,21 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
*/ */
if (!list_empty(&wdev->list)) { if (!list_empty(&wdev->list)) {
sysfs_remove_link(&dev->dev.kobj, "phy80211"); sysfs_remove_link(&dev->dev.kobj, "phy80211");
list_del_init(&wdev->list); list_del_rcu(&wdev->list);
rdev->devlist_generation++; rdev->devlist_generation++;
#ifdef CONFIG_CFG80211_WEXT #ifdef CONFIG_CFG80211_WEXT
kfree(wdev->wext.keys); kfree(wdev->wext.keys);
#endif #endif
} }
mutex_unlock(&rdev->devlist_mtx); 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; break;
case NETDEV_PRE_UP: case NETDEV_PRE_UP:
if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
......
/* /*
* Wireless configuration interface internals. * Wireless configuration interface internals.
* *
* Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
*/ */
#ifndef __NET_WIRELESS_CORE_H #ifndef __NET_WIRELESS_CORE_H
#define __NET_WIRELESS_CORE_H #define __NET_WIRELESS_CORE_H
...@@ -48,6 +48,7 @@ struct cfg80211_registered_device { ...@@ -48,6 +48,7 @@ struct cfg80211_registered_device {
/* associate netdev list */ /* associate netdev list */
struct mutex devlist_mtx; struct mutex devlist_mtx;
/* protected by devlist_mtx or RCU */
struct list_head netdev_list; struct list_head netdev_list;
int devlist_generation; int devlist_generation;
int opencount; /* also protected by devlist_mtx */ int opencount; /* also protected by devlist_mtx */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment