diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2010-01-17 09:49:02 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-01-19 16:43:09 -0500 |
commit | 5f2aa25e0e5b221a176ab3d1c51d51da265cb4a7 (patch) | |
tree | b991f42ad2f5874b6ac3d8fcb1a138e889d70c19 /net/wireless/core.c | |
parent | c57199bc32ebcd914253496486d2e09b1c9a3de0 (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/core.c')
-rw-r--r-- | net/wireless/core.c | 26 |
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 @@ | |||
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"); | |||
31 | MODULE_LICENSE("GPL"); | 31 | MODULE_LICENSE("GPL"); |
32 | MODULE_DESCRIPTION("wireless configuration support"); | 32 | MODULE_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 */ | ||
37 | LIST_HEAD(cfg80211_rdev_list); | 35 | LIST_HEAD(cfg80211_rdev_list); |
38 | int cfg80211_rdev_list_generation; | 36 | int cfg80211_rdev_list_generation; |
39 | 37 | ||
40 | /* | ||
41 | * This is used to protect the cfg80211_rdev_list | ||
42 | */ | ||
43 | DEFINE_MUTEX(cfg80211_mutex); | 38 | DEFINE_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))) |