aboutsummaryrefslogtreecommitdiffstats
path: root/net/rfkill/rfkill.c
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2008-07-21 20:18:20 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-07-29 16:36:35 -0400
commit064af1117b4aa64a0e52f6b741df7356ef055142 (patch)
tree262651d81f5d390467ee80bca96e403f86bacee3 /net/rfkill/rfkill.c
parentf1b23361a0f15497d4c6795a2935b2e98064ddfb (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/rfkill/rfkill.c')
-rw-r--r--net/rfkill/rfkill.c29
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 */
155static int rfkill_toggle_radio(struct rfkill *rfkill, 155static 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 */
233void rfkill_epo(void) 236void 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
395out_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/**