aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-06-18 08:58:09 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-06-26 16:49:17 -0400
commit5a9f7b047e81a73a1ce3e42ef87c28a61fd4df24 (patch)
treea9d727db68885155b36afb57e5f28df8cd82e029 /net
parent135a2110c55c71d7ccaf5ac66968b993347fe8e2 (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.c1
-rw-r--r--net/mac80211/sta_info.h40
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
294static inline void set_sta_flags(struct sta_info *sta, const u32 flags) 299static 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
301static inline void clear_sta_flags(struct sta_info *sta, const u32 flags) 308static 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
308static inline void set_and_clear_sta_flags(struct sta_info *sta, 317static 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
317static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags) 328static 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,
341static inline u32 get_sta_flags(struct sta_info *sta) 354static 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}