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>
This commit is contained in:
committed by
John W. Linville
parent
c57199bc32
commit
5f2aa25e0e
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* 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");
|
|||||||
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)
|
|||||||
/* 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)
|
|||||||
* 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,
|
|||||||
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,
|
|||||||
*/
|
*/
|
||||||
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)))
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* 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 {
|
|||||||
|
|
||||||
/* 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 */
|
||||||
|
Reference in New Issue
Block a user