Skip to content

Commit

Permalink
[MAC80211]: improve locking of sta_info related structures
Browse files Browse the repository at this point in the history
The sta_info code has some awkward locking which prevents some driver
callbacks from being allowed to sleep. This patch makes the locking more
focused so code that calls driver callbacks are allowed to sleep. It also
converts sta_lock to a rwlock.

Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Jiri Benc <jbenc@suse.cz>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Michael Wu authored and David S. Miller committed Oct 10, 2007
1 parent c2d1560 commit be8755e
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 136 deletions.
3 changes: 1 addition & 2 deletions include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -626,8 +626,7 @@ struct ieee80211_ops {
* station hwaddr for individual keys. aid of the station is given
* to help low-level driver in selecting which key->hw_key_idx to use
* for this key. TX control data will use the hw_key_idx selected by
* the low-level driver.
* Must be atomic. */
* the low-level driver. */
int (*set_key)(struct ieee80211_hw *hw, set_key_cmd cmd,
u8 *addr, struct ieee80211_key_conf *key, int aid);

Expand Down
6 changes: 3 additions & 3 deletions net/mac80211/ieee80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -628,8 +628,8 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
/* Remove STA entry for the old peer */
sta = sta_info_get(local, sdata->u.wds.remote_addr);
if (sta) {
sta_info_free(sta);
sta_info_put(sta);
sta_info_free(sta, 0);
} else {
printk(KERN_DEBUG "%s: could not find STA entry for WDS link "
"peer " MAC_FMT "\n",
Expand Down Expand Up @@ -776,13 +776,13 @@ static void ieee80211_stat_refresh(unsigned long data)
return;

/* go through all stations */
spin_lock_bh(&local->sta_lock);
read_lock_bh(&local->sta_lock);
list_for_each_entry(sta, &local->sta_list, list) {
sta->channel_use = (sta->channel_use_raw / local->stat_time) /
CHAN_UTIL_PER_10MS;
sta->channel_use_raw = 0;
}
spin_unlock_bh(&local->sta_lock);
read_unlock_bh(&local->sta_lock);

/* go through all subinterfaces */
read_lock(&local->sub_if_lock);
Expand Down
11 changes: 5 additions & 6 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -417,10 +417,9 @@ struct ieee80211_local {
struct sk_buff_head skb_queue_unreliable;

/* Station data structures */
spinlock_t sta_lock; /* mutex for STA data structures */
rwlock_t sta_lock; /* protects STA data structures */
int num_sta; /* number of stations in sta_list */
struct list_head sta_list;
struct list_head deleted_sta_list;
struct sta_info *sta_hash[STA_HASH_SIZE];
struct timer_list sta_cleanup;

Expand Down Expand Up @@ -669,9 +668,9 @@ static inline void __bss_tim_set(struct ieee80211_if_ap *bss, int aid)
static inline void bss_tim_set(struct ieee80211_local *local,
struct ieee80211_if_ap *bss, int aid)
{
spin_lock_bh(&local->sta_lock);
read_lock_bh(&local->sta_lock);
__bss_tim_set(bss, aid);
spin_unlock_bh(&local->sta_lock);
read_unlock_bh(&local->sta_lock);
}

static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, int aid)
Expand All @@ -686,9 +685,9 @@ static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, int aid)
static inline void bss_tim_clear(struct ieee80211_local *local,
struct ieee80211_if_ap *bss, int aid)
{
spin_lock_bh(&local->sta_lock);
read_lock_bh(&local->sta_lock);
__bss_tim_clear(bss, aid);
spin_unlock_bh(&local->sta_lock);
read_unlock_bh(&local->sta_lock);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion net/mac80211/ieee80211_iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,8 @@ void ieee80211_if_reinit(struct net_device *dev)
case IEEE80211_IF_TYPE_WDS:
sta = sta_info_get(local, sdata->u.wds.remote_addr);
if (sta) {
sta_info_free(sta);
sta_info_put(sta);
sta_info_free(sta, 0);
} else {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
printk(KERN_DEBUG "%s: Someone had deleted my STA "
Expand Down
20 changes: 14 additions & 6 deletions net/mac80211/ieee80211_sta.c
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,7 @@ static void ieee80211_associated(struct net_device *dev,
"range\n",
dev->name, MAC_ARG(ifsta->bssid));
disassoc = 1;
sta_info_free(sta, 0);
sta_info_free(sta);
ifsta->probereq_poll = 0;
} else {
ieee80211_send_probe_req(dev, ifsta->bssid,
Expand Down Expand Up @@ -1890,7 +1890,7 @@ static int ieee80211_sta_active_ibss(struct net_device *dev)
int active = 0;
struct sta_info *sta;

spin_lock_bh(&local->sta_lock);
read_lock_bh(&local->sta_lock);
list_for_each_entry(sta, &local->sta_list, list) {
if (sta->dev == dev &&
time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
Expand All @@ -1899,7 +1899,7 @@ static int ieee80211_sta_active_ibss(struct net_device *dev)
break;
}
}
spin_unlock_bh(&local->sta_lock);
read_unlock_bh(&local->sta_lock);

return active;
}
Expand All @@ -1909,16 +1909,24 @@ static void ieee80211_sta_expire(struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta, *tmp;
LIST_HEAD(tmp_list);

spin_lock_bh(&local->sta_lock);
write_lock_bh(&local->sta_lock);
list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
if (time_after(jiffies, sta->last_rx +
IEEE80211_IBSS_INACTIVITY_LIMIT)) {
printk(KERN_DEBUG "%s: expiring inactive STA " MAC_FMT
"\n", dev->name, MAC_ARG(sta->addr));
sta_info_free(sta, 1);
__sta_info_get(sta);
sta_info_remove(sta);
list_add(&sta->list, &tmp_list);
}
spin_unlock_bh(&local->sta_lock);
write_unlock_bh(&local->sta_lock);

list_for_each_entry_safe(sta, tmp, &tmp_list, list) {
sta_info_free(sta);
sta_info_put(sta);
}
}


Expand Down
Loading

0 comments on commit be8755e

Please sign in to comment.