diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-06-18 08:58:09 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-06-26 16:49:17 -0400 |
commit | 5a9f7b047e81a73a1ce3e42ef87c28a61fd4df24 (patch) | |
tree | a9d727db68885155b36afb57e5f28df8cd82e029 /net | |
parent | 135a2110c55c71d7ccaf5ac66968b993347fe8e2 (diff) |
mac80211: use separate spinlock for sta flags
David Ellingsworth posted a bug that was only noticable on UP/NO-PREEMPT
and Michael correctly analysed it to be a spin_lock_bh() section within
a spin_lock_irqsave() section. This adds a separate spinlock for the
sta_info flags to fix that issue and avoid having to take much care
about where the sta flag manipulation functions are called.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Reported-By: David Ellingsworth <david@identd.dyndns.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/sta_info.c | 1 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 40 |
2 files changed, 28 insertions, 13 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index c24770cb02c5..b3c733162fc1 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -235,6 +235,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
235 | return NULL; | 235 | return NULL; |
236 | 236 | ||
237 | spin_lock_init(&sta->lock); | 237 | spin_lock_init(&sta->lock); |
238 | spin_lock_init(&sta->flaglock); | ||
238 | 239 | ||
239 | memcpy(sta->addr, addr, ETH_ALEN); | 240 | memcpy(sta->addr, addr, ETH_ALEN); |
240 | sta->local = local; | 241 | sta->local = local; |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 95753f860acf..fd228c198e31 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -164,6 +164,7 @@ struct sta_ampdu_mlme { | |||
164 | * @aid: STA's unique AID (1..2007, 0 = not assigned yet), | 164 | * @aid: STA's unique AID (1..2007, 0 = not assigned yet), |
165 | * only used in AP (and IBSS?) mode | 165 | * only used in AP (and IBSS?) mode |
166 | * @flags: STA flags, see &enum ieee80211_sta_info_flags | 166 | * @flags: STA flags, see &enum ieee80211_sta_info_flags |
167 | * @flaglock: spinlock for flags accesses | ||
167 | * @ps_tx_buf: buffer of frames to transmit to this station | 168 | * @ps_tx_buf: buffer of frames to transmit to this station |
168 | * when it leaves power saving state | 169 | * when it leaves power saving state |
169 | * @tx_filtered: buffer of frames we already tried to transmit | 170 | * @tx_filtered: buffer of frames we already tried to transmit |
@@ -186,6 +187,7 @@ struct sta_info { | |||
186 | struct rate_control_ref *rate_ctrl; | 187 | struct rate_control_ref *rate_ctrl; |
187 | void *rate_ctrl_priv; | 188 | void *rate_ctrl_priv; |
188 | spinlock_t lock; | 189 | spinlock_t lock; |
190 | spinlock_t flaglock; | ||
189 | struct ieee80211_ht_info ht_info; | 191 | struct ieee80211_ht_info ht_info; |
190 | u64 supp_rates[IEEE80211_NUM_BANDS]; | 192 | u64 supp_rates[IEEE80211_NUM_BANDS]; |
191 | u8 addr[ETH_ALEN]; | 193 | u8 addr[ETH_ALEN]; |
@@ -198,7 +200,10 @@ struct sta_info { | |||
198 | */ | 200 | */ |
199 | u8 pin_status; | 201 | u8 pin_status; |
200 | 202 | ||
201 | /* frequently updated information, locked with lock spinlock */ | 203 | /* |
204 | * frequently updated, locked with own spinlock (flaglock), | ||
205 | * use the accessors defined below | ||
206 | */ | ||
202 | u32 flags; | 207 | u32 flags; |
203 | 208 | ||
204 | /* | 209 | /* |
@@ -293,34 +298,41 @@ static inline enum plink_state sta_plink_state(struct sta_info *sta) | |||
293 | 298 | ||
294 | static inline void set_sta_flags(struct sta_info *sta, const u32 flags) | 299 | static inline void set_sta_flags(struct sta_info *sta, const u32 flags) |
295 | { | 300 | { |
296 | spin_lock_bh(&sta->lock); | 301 | unsigned long irqfl; |
302 | |||
303 | spin_lock_irqsave(&sta->flaglock, irqfl); | ||
297 | sta->flags |= flags; | 304 | sta->flags |= flags; |
298 | spin_unlock_bh(&sta->lock); | 305 | spin_unlock_irqrestore(&sta->flaglock, irqfl); |
299 | } | 306 | } |
300 | 307 | ||
301 | static inline void clear_sta_flags(struct sta_info *sta, const u32 flags) | 308 | static inline void clear_sta_flags(struct sta_info *sta, const u32 flags) |
302 | { | 309 | { |
303 | spin_lock_bh(&sta->lock); | 310 | unsigned long irqfl; |
311 | |||
312 | spin_lock_irqsave(&sta->flaglock, irqfl); | ||
304 | sta->flags &= ~flags; | 313 | sta->flags &= ~flags; |
305 | spin_unlock_bh(&sta->lock); | 314 | spin_unlock_irqrestore(&sta->flaglock, irqfl); |
306 | } | 315 | } |
307 | 316 | ||
308 | static inline void set_and_clear_sta_flags(struct sta_info *sta, | 317 | static inline void set_and_clear_sta_flags(struct sta_info *sta, |
309 | const u32 set, const u32 clear) | 318 | const u32 set, const u32 clear) |
310 | { | 319 | { |
311 | spin_lock_bh(&sta->lock); | 320 | unsigned long irqfl; |
321 | |||
322 | spin_lock_irqsave(&sta->flaglock, irqfl); | ||
312 | sta->flags |= set; | 323 | sta->flags |= set; |
313 | sta->flags &= ~clear; | 324 | sta->flags &= ~clear; |
314 | spin_unlock_bh(&sta->lock); | 325 | spin_unlock_irqrestore(&sta->flaglock, irqfl); |
315 | } | 326 | } |
316 | 327 | ||
317 | static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags) | 328 | static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags) |
318 | { | 329 | { |
319 | u32 ret; | 330 | u32 ret; |
331 | unsigned long irqfl; | ||
320 | 332 | ||
321 | spin_lock_bh(&sta->lock); | 333 | spin_lock_irqsave(&sta->flaglock, irqfl); |
322 | ret = sta->flags & flags; | 334 | ret = sta->flags & flags; |
323 | spin_unlock_bh(&sta->lock); | 335 | spin_unlock_irqrestore(&sta->flaglock, irqfl); |
324 | 336 | ||
325 | return ret; | 337 | return ret; |
326 | } | 338 | } |
@@ -329,11 +341,12 @@ static inline u32 test_and_clear_sta_flags(struct sta_info *sta, | |||
329 | const u32 flags) | 341 | const u32 flags) |
330 | { | 342 | { |
331 | u32 ret; | 343 | u32 ret; |
344 | unsigned long irqfl; | ||
332 | 345 | ||
333 | spin_lock_bh(&sta->lock); | 346 | spin_lock_irqsave(&sta->flaglock, irqfl); |
334 | ret = sta->flags & flags; | 347 | ret = sta->flags & flags; |
335 | sta->flags &= ~flags; | 348 | sta->flags &= ~flags; |
336 | spin_unlock_bh(&sta->lock); | 349 | spin_unlock_irqrestore(&sta->flaglock, irqfl); |
337 | 350 | ||
338 | return ret; | 351 | return ret; |
339 | } | 352 | } |
@@ -341,10 +354,11 @@ static inline u32 test_and_clear_sta_flags(struct sta_info *sta, | |||
341 | static inline u32 get_sta_flags(struct sta_info *sta) | 354 | static inline u32 get_sta_flags(struct sta_info *sta) |
342 | { | 355 | { |
343 | u32 ret; | 356 | u32 ret; |
357 | unsigned long irqfl; | ||
344 | 358 | ||
345 | spin_lock_bh(&sta->lock); | 359 | spin_lock_irqsave(&sta->flaglock, irqfl); |
346 | ret = sta->flags; | 360 | ret = sta->flags; |
347 | spin_unlock_bh(&sta->lock); | 361 | spin_unlock_irqrestore(&sta->flaglock, irqfl); |
348 | 362 | ||
349 | return ret; | 363 | return ret; |
350 | } | 364 | } |