Commit 5956dce1 authored by Konstantin Baydarov's avatar Konstantin Baydarov Committed by Linus Torvalds

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: default avatarKonstantin Baydarov <kbaidarov@ru.mvista.com>
Signed-off-by: default avatarCorey Minyard <cminyard@mvista.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent bda4c30a
...@@ -351,8 +351,16 @@ struct ipmi_smi ...@@ -351,8 +351,16 @@ struct ipmi_smi
/* Invalid data in an event. */ /* Invalid data in an event. */
unsigned int invalid_events; unsigned int invalid_events;
/* Events that were received with the proper format. */ /* Events that were received with the proper format. */
unsigned int events; unsigned int events;
/*
* run_to_completion duplicate of smb_info, smi_info
* and ipmi_serial_info structures. Used to decrease numbers of
* parameters passed by "low" level IPMI code.
*/
int run_to_completion;
}; };
#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev) #define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
...@@ -3451,8 +3459,9 @@ static int handle_new_recv_msg(ipmi_smi_t intf, ...@@ -3451,8 +3459,9 @@ static int handle_new_recv_msg(ipmi_smi_t intf,
void ipmi_smi_msg_received(ipmi_smi_t intf, void ipmi_smi_msg_received(ipmi_smi_t intf,
struct ipmi_smi_msg *msg) struct ipmi_smi_msg *msg)
{ {
unsigned long flags; unsigned long flags = 0; /* keep us warning-free. */
int rv; int rv;
int run_to_completion;
if ((msg->data_size >= 2) if ((msg->data_size >= 2)
...@@ -3501,21 +3510,28 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, ...@@ -3501,21 +3510,28 @@ void ipmi_smi_msg_received(ipmi_smi_t intf,
/* To preserve message order, if the list is not empty, we /* To preserve message order, if the list is not empty, we
tack this message onto the end of the list. */ tack this message onto the end of the list. */
spin_lock_irqsave(&intf->waiting_msgs_lock, flags); run_to_completion = intf->run_to_completion;
if (!run_to_completion)
spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
if (!list_empty(&intf->waiting_msgs)) { if (!list_empty(&intf->waiting_msgs)) {
list_add_tail(&msg->link, &intf->waiting_msgs); list_add_tail(&msg->link, &intf->waiting_msgs);
spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); if (!run_to_completion)
spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
goto out; goto out;
} }
spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); if (!run_to_completion)
spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
rv = handle_new_recv_msg(intf, msg); rv = handle_new_recv_msg(intf, msg);
if (rv > 0) { if (rv > 0) {
/* Could not handle the message now, just add it to a /* Could not handle the message now, just add it to a
list to handle later. */ list to handle later. */
spin_lock_irqsave(&intf->waiting_msgs_lock, flags); run_to_completion = intf->run_to_completion;
if (!run_to_completion)
spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
list_add_tail(&msg->link, &intf->waiting_msgs); list_add_tail(&msg->link, &intf->waiting_msgs);
spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); if (!run_to_completion)
spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
} else if (rv == 0) { } else if (rv == 0) {
ipmi_free_smi_msg(msg); ipmi_free_smi_msg(msg);
} }
...@@ -3884,6 +3900,7 @@ static void send_panic_events(char *str) ...@@ -3884,6 +3900,7 @@ static void send_panic_events(char *str)
/* Interface is not ready. */ /* Interface is not ready. */
continue; continue;
intf->run_to_completion = 1;
/* Send the event announcing the panic. */ /* Send the event announcing the panic. */
intf->handlers->set_run_to_completion(intf->send_info, 1); intf->handlers->set_run_to_completion(intf->send_info, 1);
i_ipmi_request(NULL, i_ipmi_request(NULL,
...@@ -4059,6 +4076,7 @@ static int panic_event(struct notifier_block *this, ...@@ -4059,6 +4076,7 @@ static int panic_event(struct notifier_block *this,
/* Interface is not ready. */ /* Interface is not ready. */
continue; continue;
intf->run_to_completion = 1;
intf->handlers->set_run_to_completion(intf->send_info, 1); intf->handlers->set_run_to_completion(intf->send_info, 1);
} }
......
...@@ -289,7 +289,8 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) ...@@ -289,7 +289,8 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
/* No need to save flags, we aleady have interrupts off and we /* No need to save flags, we aleady have interrupts off and we
already hold the SMI lock. */ already hold the SMI lock. */
spin_lock(&(smi_info->msg_lock)); if (!smi_info->run_to_completion)
spin_lock(&(smi_info->msg_lock));
/* Pick the high priority queue first. */ /* Pick the high priority queue first. */
if (!list_empty(&(smi_info->hp_xmit_msgs))) { 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,7 +330,8 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
rv = SI_SM_CALL_WITHOUT_DELAY; rv = SI_SM_CALL_WITHOUT_DELAY;
} }
out: out:
spin_unlock(&(smi_info->msg_lock)); if (!smi_info->run_to_completion)
spin_unlock(&(smi_info->msg_lock));
return rv; return rv;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment