diff options
author | Konstantin Baydarov <kbaidarov@ru.mvista.com> | 2008-04-29 04:01:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-29 11:06:14 -0400 |
commit | 5956dce1485efe3816febc24aa52490dcb2be837 (patch) | |
tree | 292231b7783baaf980a65eacb199a0384446f566 | |
parent | bda4c30aa6f7dc1483f39ea1dfe37bcab8a96207 (diff) |
ipmi: don't grab locks in run-to-completion mode
This patch prevents deadlocks in IPMI panic handler caused by msg_lock
in smi_info structure and waiting_msgs_lock in ipmi_smi structure.
[cminyard@mvista.com: remove unnecessary memory barriers]
Signed-off-by: Konstantin Baydarov <kbaidarov@ru.mvista.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/char/ipmi/ipmi_msghandler.c | 30 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 6 |
2 files changed, 28 insertions, 8 deletions
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 9f0075ca34ba..8b71f5638b60 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c | |||
@@ -351,8 +351,16 @@ struct ipmi_smi | |||
351 | 351 | ||
352 | /* Invalid data in an event. */ | 352 | /* Invalid data in an event. */ |
353 | unsigned int invalid_events; | 353 | unsigned int invalid_events; |
354 | |||
354 | /* Events that were received with the proper format. */ | 355 | /* Events that were received with the proper format. */ |
355 | unsigned int events; | 356 | unsigned int events; |
357 | |||
358 | /* | ||
359 | * run_to_completion duplicate of smb_info, smi_info | ||
360 | * and ipmi_serial_info structures. Used to decrease numbers of | ||
361 | * parameters passed by "low" level IPMI code. | ||
362 | */ | ||
363 | int run_to_completion; | ||
356 | }; | 364 | }; |
357 | #define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev) | 365 | #define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev) |
358 | 366 | ||
@@ -3451,8 +3459,9 @@ static int handle_new_recv_msg(ipmi_smi_t intf, | |||
3451 | void ipmi_smi_msg_received(ipmi_smi_t intf, | 3459 | void ipmi_smi_msg_received(ipmi_smi_t intf, |
3452 | struct ipmi_smi_msg *msg) | 3460 | struct ipmi_smi_msg *msg) |
3453 | { | 3461 | { |
3454 | unsigned long flags; | 3462 | unsigned long flags = 0; /* keep us warning-free. */ |
3455 | int rv; | 3463 | int rv; |
3464 | int run_to_completion; | ||
3456 | 3465 | ||
3457 | 3466 | ||
3458 | if ((msg->data_size >= 2) | 3467 | if ((msg->data_size >= 2) |
@@ -3501,21 +3510,28 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, | |||
3501 | 3510 | ||
3502 | /* To preserve message order, if the list is not empty, we | 3511 | /* To preserve message order, if the list is not empty, we |
3503 | tack this message onto the end of the list. */ | 3512 | tack this message onto the end of the list. */ |
3504 | spin_lock_irqsave(&intf->waiting_msgs_lock, flags); | 3513 | run_to_completion = intf->run_to_completion; |
3514 | if (!run_to_completion) | ||
3515 | spin_lock_irqsave(&intf->waiting_msgs_lock, flags); | ||
3505 | if (!list_empty(&intf->waiting_msgs)) { | 3516 | if (!list_empty(&intf->waiting_msgs)) { |
3506 | list_add_tail(&msg->link, &intf->waiting_msgs); | 3517 | list_add_tail(&msg->link, &intf->waiting_msgs); |
3507 | spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); | 3518 | if (!run_to_completion) |
3519 | spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); | ||
3508 | goto out; | 3520 | goto out; |
3509 | } | 3521 | } |
3510 | spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); | 3522 | if (!run_to_completion) |
3523 | spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); | ||
3511 | 3524 | ||
3512 | rv = handle_new_recv_msg(intf, msg); | 3525 | rv = handle_new_recv_msg(intf, msg); |
3513 | if (rv > 0) { | 3526 | if (rv > 0) { |
3514 | /* Could not handle the message now, just add it to a | 3527 | /* Could not handle the message now, just add it to a |
3515 | list to handle later. */ | 3528 | list to handle later. */ |
3516 | spin_lock_irqsave(&intf->waiting_msgs_lock, flags); | 3529 | run_to_completion = intf->run_to_completion; |
3530 | if (!run_to_completion) | ||
3531 | spin_lock_irqsave(&intf->waiting_msgs_lock, flags); | ||
3517 | list_add_tail(&msg->link, &intf->waiting_msgs); | 3532 | list_add_tail(&msg->link, &intf->waiting_msgs); |
3518 | spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); | 3533 | if (!run_to_completion) |
3534 | spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); | ||
3519 | } else if (rv == 0) { | 3535 | } else if (rv == 0) { |
3520 | ipmi_free_smi_msg(msg); | 3536 | ipmi_free_smi_msg(msg); |
3521 | } | 3537 | } |
@@ -3884,6 +3900,7 @@ static void send_panic_events(char *str) | |||
3884 | /* Interface is not ready. */ | 3900 | /* Interface is not ready. */ |
3885 | continue; | 3901 | continue; |
3886 | 3902 | ||
3903 | intf->run_to_completion = 1; | ||
3887 | /* Send the event announcing the panic. */ | 3904 | /* Send the event announcing the panic. */ |
3888 | intf->handlers->set_run_to_completion(intf->send_info, 1); | 3905 | intf->handlers->set_run_to_completion(intf->send_info, 1); |
3889 | i_ipmi_request(NULL, | 3906 | i_ipmi_request(NULL, |
@@ -4059,6 +4076,7 @@ static int panic_event(struct notifier_block *this, | |||
4059 | /* Interface is not ready. */ | 4076 | /* Interface is not ready. */ |
4060 | continue; | 4077 | continue; |
4061 | 4078 | ||
4079 | intf->run_to_completion = 1; | ||
4062 | intf->handlers->set_run_to_completion(intf->send_info, 1); | 4080 | intf->handlers->set_run_to_completion(intf->send_info, 1); |
4063 | } | 4081 | } |
4064 | 4082 | ||
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 30f535657342..657034febdaf 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
@@ -289,7 +289,8 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) | |||
289 | 289 | ||
290 | /* No need to save flags, we aleady have interrupts off and we | 290 | /* No need to save flags, we aleady have interrupts off and we |
291 | already hold the SMI lock. */ | 291 | already hold the SMI lock. */ |
292 | spin_lock(&(smi_info->msg_lock)); | 292 | if (!smi_info->run_to_completion) |
293 | spin_lock(&(smi_info->msg_lock)); | ||
293 | 294 | ||
294 | /* Pick the high priority queue first. */ | 295 | /* Pick the high priority queue first. */ |
295 | if (!list_empty(&(smi_info->hp_xmit_msgs))) { | 296 | if (!list_empty(&(smi_info->hp_xmit_msgs))) { |
@@ -329,7 +330,8 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) | |||
329 | rv = SI_SM_CALL_WITHOUT_DELAY; | 330 | rv = SI_SM_CALL_WITHOUT_DELAY; |
330 | } | 331 | } |
331 | out: | 332 | out: |
332 | spin_unlock(&(smi_info->msg_lock)); | 333 | if (!smi_info->run_to_completion) |
334 | spin_unlock(&(smi_info->msg_lock)); | ||
333 | 335 | ||
334 | return rv; | 336 | return rv; |
335 | } | 337 | } |