aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2010-01-17 09:49:02 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-01-19 16:43:09 -0500
commit5f2aa25e0e5b221a176ab3d1c51d51da265cb4a7 (patch)
treeb991f42ad2f5874b6ac3d8fcb1a138e889d70c19 /net/wireless
parentc57199bc32ebcd914253496486d2e09b1c9a3de0 (diff)
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')
-rw-r--r--net/wireless/core.c26
-rw-r--r--net/wireless/core.h3
2 files changed, 17 insertions, 12 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 @@
1/* 1/*
2 * This is the linux wireless configuration interface. 2 * This is the linux wireless configuration interface.
3 * 3 *
4 * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> 4 * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
5 */ 5 */
6 6
7#include <linux/if.h> 7#include <linux/if.h>
@@ -31,15 +31,10 @@ MODULE_AUTHOR("Johannes Berg");
31MODULE_LICENSE("GPL"); 31MODULE_LICENSE("GPL");
32MODULE_DESCRIPTION("wireless configuration support"); 32MODULE_DESCRIPTION("wireless configuration support");
33 33
34/* RCU might be appropriate here since we usually 34/* RCU-protected (and cfg80211_mutex for writers) */
35 * only read the list, and that can happen quite
36 * often because we need to do it for each command */
37LIST_HEAD(cfg80211_rdev_list); 35LIST_HEAD(cfg80211_rdev_list);
38int cfg80211_rdev_list_generation; 36int cfg80211_rdev_list_generation;
39 37
40/*
41 * This is used to protect the cfg80211_rdev_list
42 */
43DEFINE_MUTEX(cfg80211_mutex); 38DEFINE_MUTEX(cfg80211_mutex);
44 39
45/* for debugfs */ 40/* for debugfs */
@@ -477,7 +472,7 @@ int wiphy_register(struct wiphy *wiphy)
477 /* set up regulatory info */ 472 /* set up regulatory info */
478 wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); 473 wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
479 474
480 list_add(&rdev->list, &cfg80211_rdev_list); 475 list_add_rcu(&rdev->list, &cfg80211_rdev_list);
481 cfg80211_rdev_list_generation++; 476 cfg80211_rdev_list_generation++;
482 477
483 mutex_unlock(&cfg80211_mutex); 478 mutex_unlock(&cfg80211_mutex);
@@ -554,7 +549,8 @@ void wiphy_unregister(struct wiphy *wiphy)
554 * it impossible to find from userspace. 549 * it impossible to find from userspace.
555 */ 550 */
556 debugfs_remove_recursive(rdev->wiphy.debugfsdir); 551 debugfs_remove_recursive(rdev->wiphy.debugfsdir);
557 list_del(&rdev->list); 552 list_del_rcu(&rdev->list);
553 synchronize_rcu();
558 554
559 /* 555 /*
560 * Try to grab rdev->mtx. If a command is still in progress, 556 * 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 INIT_LIST_HEAD(&wdev->event_list); 666 INIT_LIST_HEAD(&wdev->event_list);
671 spin_lock_init(&wdev->event_lock); 667 spin_lock_init(&wdev->event_lock);
672 mutex_lock(&rdev->devlist_mtx); 668 mutex_lock(&rdev->devlist_mtx);
673 list_add(&wdev->list, &rdev->netdev_list); 669 list_add_rcu(&wdev->list, &rdev->netdev_list);
674 rdev->devlist_generation++; 670 rdev->devlist_generation++;
675 /* can only change netns with wiphy */ 671 /* can only change netns with wiphy */
676 dev->features |= NETIF_F_NETNS_LOCAL; 672 dev->features |= NETIF_F_NETNS_LOCAL;
@@ -782,13 +778,21 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
782 */ 778 */
783 if (!list_empty(&wdev->list)) { 779 if (!list_empty(&wdev->list)) {
784 sysfs_remove_link(&dev->dev.kobj, "phy80211"); 780 sysfs_remove_link(&dev->dev.kobj, "phy80211");
785 list_del_init(&wdev->list); 781 list_del_rcu(&wdev->list);
786 rdev->devlist_generation++; 782 rdev->devlist_generation++;
787#ifdef CONFIG_CFG80211_WEXT 783#ifdef CONFIG_CFG80211_WEXT
788 kfree(wdev->wext.keys); 784 kfree(wdev->wext.keys);
789#endif 785#endif
790 } 786 }
791 mutex_unlock(&rdev->devlist_mtx); 787 mutex_unlock(&rdev->devlist_mtx);
788 /*
789 * synchronise (so that we won't find this netdev
790 * from other code any more) and then clear the list
791 * head so that the above code can safely check for
792 * !list_empty() to avoid double-cleanup.
793 */
794 synchronize_rcu();
795 INIT_LIST_HEAD(&wdev->list);
792 break; 796 break;
793 case NETDEV_PRE_UP: 797 case NETDEV_PRE_UP:
794 if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) 798 if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 2d6a6b9c0c43..c326a667022a 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -1,7 +1,7 @@
1/* 1/*
2 * Wireless configuration interface internals. 2 * Wireless configuration interface internals.
3 * 3 *
4 * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> 4 * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
5 */ 5 */
6#ifndef __NET_WIRELESS_CORE_H 6#ifndef __NET_WIRELESS_CORE_H
7#define __NET_WIRELESS_CORE_H 7#define __NET_WIRELESS_CORE_H
@@ -48,6 +48,7 @@ struct cfg80211_registered_device {
48 48
49 /* associate netdev list */ 49 /* associate netdev list */
50 struct mutex devlist_mtx; 50 struct mutex devlist_mtx;
51 /* protected by devlist_mtx or RCU */
51 struct list_head netdev_list; 52 struct list_head netdev_list;
52 int devlist_generation; 53 int devlist_generation;
53 int opencount; /* also protected by devlist_mtx */ 54 int opencount; /* also protected by devlist_mtx */