diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-02-25 16:27:47 +0100 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-03-06 15:30:47 -0500 |
commit | 73651ee6396c499ccb59ebc84c9274db01ed026d (patch) | |
tree | 1d59027cbdaec732f3e1378770cbf7b42b48cd70 /net/mac80211/ieee80211.c | |
parent | d0709a65181beb787ef3f58cfe45536a2bb254c8 (diff) |
mac80211: split sta_info_add
sta_info_add() has two functions: allocating a station info
structure and inserting it into the hash table/list. Splitting
these two functions allows allocating with GFP_KERNEL in many
places instead of GFP_ATOMIC which is now required by the RCU
protection. Additionally, in many places RCU protection is now
no longer needed at all because between sta_info_alloc() and
sta_info_insert() the caller owns the structure.
This fixes a few race conditions with setting initial flags
and similar, but not all (see comments in ieee80211_sta.c and
cfg.c). More documentation on the existing races will be in
a follow-up patch.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/ieee80211.c')
-rw-r--r-- | net/mac80211/ieee80211.c | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 85b1391375c..22cba82a0c6 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -899,6 +899,7 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sta_info *sta; + int err; DECLARE_MAC_BUF(mac); might_sleep(); @@ -906,16 +907,19 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) return 0; - rcu_read_lock(); - /* Create STA entry for the new peer */ - sta = sta_info_add(sdata, remote_addr); - if (IS_ERR(sta)) { - rcu_read_unlock(); - return PTR_ERR(sta); - } + sta = sta_info_alloc(sdata, remote_addr, GFP_KERNEL); + if (!sta) + return -ENOMEM; sta->flags |= WLAN_STA_AUTHORIZED; + err = sta_info_insert(sta); + if (err) { + sta_info_destroy(sta); + return err; + } + + rcu_read_lock(); /* Remove STA entry for the old peer */ sta = sta_info_get(local, sdata->u.wds.remote_addr); |