aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/ipmi
diff options
context:
space:
mode:
authorKonstantin Baydarov <kbaidarov@ru.mvista.com>2008-04-29 04:01:03 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-29 11:06:14 -0400
commit5956dce1485efe3816febc24aa52490dcb2be837 (patch)
tree292231b7783baaf980a65eacb199a0384446f566 /drivers/char/ipmi
parentbda4c30aa6f7dc1483f39ea1dfe37bcab8a96207 (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>
Diffstat (limited to 'drivers/char/ipmi')
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c30
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c6
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,
3451void ipmi_smi_msg_received(ipmi_smi_t intf, 3459void 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}