diff options
author | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 2008-07-21 20:18:20 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-07-29 16:36:35 -0400 |
commit | 064af1117b4aa64a0e52f6b741df7356ef055142 (patch) | |
tree | 262651d81f5d390467ee80bca96e403f86bacee3 /net | |
parent | f1b23361a0f15497d4c6795a2935b2e98064ddfb (diff) |
rfkill: mutex fixes
There are two mutexes in rfkill:
rfkill->mutex, which protects some of the fields of a rfkill struct, and is
also used for callback serialization.
rfkill_mutex, which protects the global state, the list of registered
rfkill structs and rfkill->claim.
Make sure to use the correct mutex, and to not miss locking rfkill->mutex
even when we already took rfkill_mutex.
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/rfkill/rfkill.c | 29 |
1 files changed, 19 insertions, 10 deletions
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index fc3a4fd88995..ac205eceaf42 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c | |||
@@ -150,7 +150,7 @@ static void update_rfkill_state(struct rfkill *rfkill) | |||
150 | * even if the radio is in RFKILL_STATE_HARD_BLOCKED state, so as to | 150 | * even if the radio is in RFKILL_STATE_HARD_BLOCKED state, so as to |
151 | * give the driver a hint that it should double-BLOCK the transmitter. | 151 | * give the driver a hint that it should double-BLOCK the transmitter. |
152 | * | 152 | * |
153 | * Caller must have aquired rfkill_mutex. | 153 | * Caller must have acquired rfkill->mutex. |
154 | */ | 154 | */ |
155 | static int rfkill_toggle_radio(struct rfkill *rfkill, | 155 | static int rfkill_toggle_radio(struct rfkill *rfkill, |
156 | enum rfkill_state state, | 156 | enum rfkill_state state, |
@@ -216,8 +216,11 @@ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) | |||
216 | rfkill_states[type] = state; | 216 | rfkill_states[type] = state; |
217 | 217 | ||
218 | list_for_each_entry(rfkill, &rfkill_list, node) { | 218 | list_for_each_entry(rfkill, &rfkill_list, node) { |
219 | if ((!rfkill->user_claim) && (rfkill->type == type)) | 219 | if ((!rfkill->user_claim) && (rfkill->type == type)) { |
220 | mutex_lock(&rfkill->mutex); | ||
220 | rfkill_toggle_radio(rfkill, state, 0); | 221 | rfkill_toggle_radio(rfkill, state, 0); |
222 | mutex_unlock(&rfkill->mutex); | ||
223 | } | ||
221 | } | 224 | } |
222 | 225 | ||
223 | mutex_unlock(&rfkill_mutex); | 226 | mutex_unlock(&rfkill_mutex); |
@@ -228,7 +231,7 @@ EXPORT_SYMBOL(rfkill_switch_all); | |||
228 | * rfkill_epo - emergency power off all transmitters | 231 | * rfkill_epo - emergency power off all transmitters |
229 | * | 232 | * |
230 | * This kicks all rfkill devices to RFKILL_STATE_SOFT_BLOCKED, ignoring | 233 | * This kicks all rfkill devices to RFKILL_STATE_SOFT_BLOCKED, ignoring |
231 | * everything in its path but rfkill_mutex. | 234 | * everything in its path but rfkill_mutex and rfkill->mutex. |
232 | */ | 235 | */ |
233 | void rfkill_epo(void) | 236 | void rfkill_epo(void) |
234 | { | 237 | { |
@@ -236,7 +239,9 @@ void rfkill_epo(void) | |||
236 | 239 | ||
237 | mutex_lock(&rfkill_mutex); | 240 | mutex_lock(&rfkill_mutex); |
238 | list_for_each_entry(rfkill, &rfkill_list, node) { | 241 | list_for_each_entry(rfkill, &rfkill_list, node) { |
242 | mutex_lock(&rfkill->mutex); | ||
239 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); | 243 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); |
244 | mutex_unlock(&rfkill->mutex); | ||
240 | } | 245 | } |
241 | mutex_unlock(&rfkill_mutex); | 246 | mutex_unlock(&rfkill_mutex); |
242 | } | 247 | } |
@@ -372,6 +377,9 @@ static ssize_t rfkill_claim_store(struct device *dev, | |||
372 | if (!capable(CAP_NET_ADMIN)) | 377 | if (!capable(CAP_NET_ADMIN)) |
373 | return -EPERM; | 378 | return -EPERM; |
374 | 379 | ||
380 | if (rfkill->user_claim_unsupported) | ||
381 | return -EOPNOTSUPP; | ||
382 | |||
375 | /* | 383 | /* |
376 | * Take the global lock to make sure the kernel is not in | 384 | * Take the global lock to make sure the kernel is not in |
377 | * the middle of rfkill_switch_all | 385 | * the middle of rfkill_switch_all |
@@ -380,19 +388,17 @@ static ssize_t rfkill_claim_store(struct device *dev, | |||
380 | if (error) | 388 | if (error) |
381 | return error; | 389 | return error; |
382 | 390 | ||
383 | if (rfkill->user_claim_unsupported) { | ||
384 | error = -EOPNOTSUPP; | ||
385 | goto out_unlock; | ||
386 | } | ||
387 | if (rfkill->user_claim != claim) { | 391 | if (rfkill->user_claim != claim) { |
388 | if (!claim) | 392 | if (!claim) { |
393 | mutex_lock(&rfkill->mutex); | ||
389 | rfkill_toggle_radio(rfkill, | 394 | rfkill_toggle_radio(rfkill, |
390 | rfkill_states[rfkill->type], | 395 | rfkill_states[rfkill->type], |
391 | 0); | 396 | 0); |
397 | mutex_unlock(&rfkill->mutex); | ||
398 | } | ||
392 | rfkill->user_claim = claim; | 399 | rfkill->user_claim = claim; |
393 | } | 400 | } |
394 | 401 | ||
395 | out_unlock: | ||
396 | mutex_unlock(&rfkill_mutex); | 402 | mutex_unlock(&rfkill_mutex); |
397 | 403 | ||
398 | return error ? error : count; | 404 | return error ? error : count; |
@@ -521,8 +527,11 @@ static void rfkill_remove_switch(struct rfkill *rfkill) | |||
521 | { | 527 | { |
522 | mutex_lock(&rfkill_mutex); | 528 | mutex_lock(&rfkill_mutex); |
523 | list_del_init(&rfkill->node); | 529 | list_del_init(&rfkill->node); |
524 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); | ||
525 | mutex_unlock(&rfkill_mutex); | 530 | mutex_unlock(&rfkill_mutex); |
531 | |||
532 | mutex_lock(&rfkill->mutex); | ||
533 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); | ||
534 | mutex_unlock(&rfkill->mutex); | ||
526 | } | 535 | } |
527 | 536 | ||
528 | /** | 537 | /** |