Commit 895dcfd1 authored by Corey Minyard's avatar Corey Minyard Committed by Linus Torvalds

ipmi: fix message handling during panics

The part of the IPMI driver that delivered panic information to the event
log and extended the watchdog timeout during a panic was not properly
handling the messages.  It used static messages to avoid allocation, but
wasn't properly waiting for these, or wasn't properly handling the
refcounts.
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 7adf579c
...@@ -2794,16 +2794,18 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) ...@@ -2794,16 +2794,18 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
return; return;
} }
void ipmi_poll_interface(ipmi_user_t user) static void ipmi_poll(ipmi_smi_t intf)
{ {
ipmi_smi_t intf = user->intf;
if (intf->handlers->poll) if (intf->handlers->poll)
intf->handlers->poll(intf->send_info); intf->handlers->poll(intf->send_info);
/* In case something came in */ /* In case something came in */
handle_new_recv_msgs(intf); handle_new_recv_msgs(intf);
} }
void ipmi_poll_interface(ipmi_user_t user)
{
ipmi_poll(user->intf);
}
EXPORT_SYMBOL(ipmi_poll_interface); EXPORT_SYMBOL(ipmi_poll_interface);
int ipmi_register_smi(struct ipmi_smi_handlers *handlers, int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
...@@ -4204,12 +4206,48 @@ EXPORT_SYMBOL(ipmi_free_recv_msg); ...@@ -4204,12 +4206,48 @@ EXPORT_SYMBOL(ipmi_free_recv_msg);
#ifdef CONFIG_IPMI_PANIC_EVENT #ifdef CONFIG_IPMI_PANIC_EVENT
static atomic_t panic_done_count = ATOMIC_INIT(0);
static void dummy_smi_done_handler(struct ipmi_smi_msg *msg) static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
{ {
atomic_dec(&panic_done_count);
} }
static void dummy_recv_done_handler(struct ipmi_recv_msg *msg) static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
{ {
atomic_dec(&panic_done_count);
}
/*
* Inside a panic, send a message and wait for a response.
*/
static void ipmi_panic_request_and_wait(ipmi_smi_t intf,
struct ipmi_addr *addr,
struct kernel_ipmi_msg *msg)
{
struct ipmi_smi_msg smi_msg;
struct ipmi_recv_msg recv_msg;
int rv;
smi_msg.done = dummy_smi_done_handler;
recv_msg.done = dummy_recv_done_handler;
atomic_add(2, &panic_done_count);
rv = i_ipmi_request(NULL,
intf,
addr,
0,
msg,
intf,
&smi_msg,
&recv_msg,
0,
intf->channels[0].address,
intf->channels[0].lun,
0, 1); /* Don't retry, and don't wait. */
if (rv)
atomic_sub(2, &panic_done_count);
while (atomic_read(&panic_done_count) != 0)
ipmi_poll(intf);
} }
#ifdef CONFIG_IPMI_PANIC_STRING #ifdef CONFIG_IPMI_PANIC_STRING
...@@ -4248,8 +4286,6 @@ static void send_panic_events(char *str) ...@@ -4248,8 +4286,6 @@ static void send_panic_events(char *str)
unsigned char data[16]; unsigned char data[16];
struct ipmi_system_interface_addr *si; struct ipmi_system_interface_addr *si;
struct ipmi_addr addr; struct ipmi_addr addr;
struct ipmi_smi_msg smi_msg;
struct ipmi_recv_msg recv_msg;
si = (struct ipmi_system_interface_addr *) &addr; si = (struct ipmi_system_interface_addr *) &addr;
si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
...@@ -4277,9 +4313,6 @@ static void send_panic_events(char *str) ...@@ -4277,9 +4313,6 @@ static void send_panic_events(char *str)
data[7] = str[2]; data[7] = str[2];
} }
smi_msg.done = dummy_smi_done_handler;
recv_msg.done = dummy_recv_done_handler;
/* For every registered interface, send the event. */ /* For every registered interface, send the event. */
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
if (!intf->handlers) if (!intf->handlers)
...@@ -4289,18 +4322,7 @@ static void send_panic_events(char *str) ...@@ -4289,18 +4322,7 @@ static void send_panic_events(char *str)
intf->run_to_completion = 1; 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, ipmi_panic_request_and_wait(intf, &addr, &msg);
intf,
&addr,
0,
&msg,
intf,
&smi_msg,
&recv_msg,
0,
intf->channels[0].address,
intf->channels[0].lun,
0, 1); /* Don't retry, and don't wait. */
} }
#ifdef CONFIG_IPMI_PANIC_STRING #ifdef CONFIG_IPMI_PANIC_STRING
...@@ -4348,18 +4370,7 @@ static void send_panic_events(char *str) ...@@ -4348,18 +4370,7 @@ static void send_panic_events(char *str)
msg.data = NULL; msg.data = NULL;
msg.data_len = 0; msg.data_len = 0;
intf->null_user_handler = device_id_fetcher; intf->null_user_handler = device_id_fetcher;
i_ipmi_request(NULL, ipmi_panic_request_and_wait(intf, &addr, &msg);
intf,
&addr,
0,
&msg,
intf,
&smi_msg,
&recv_msg,
0,
intf->channels[0].address,
intf->channels[0].lun,
0, 1); /* Don't retry, and don't wait. */
if (intf->local_event_generator) { if (intf->local_event_generator) {
/* Request the event receiver from the local MC. */ /* Request the event receiver from the local MC. */
...@@ -4368,18 +4379,7 @@ static void send_panic_events(char *str) ...@@ -4368,18 +4379,7 @@ static void send_panic_events(char *str)
msg.data = NULL; msg.data = NULL;
msg.data_len = 0; msg.data_len = 0;
intf->null_user_handler = event_receiver_fetcher; intf->null_user_handler = event_receiver_fetcher;
i_ipmi_request(NULL, ipmi_panic_request_and_wait(intf, &addr, &msg);
intf,
&addr,
0,
&msg,
intf,
&smi_msg,
&recv_msg,
0,
intf->channels[0].address,
intf->channels[0].lun,
0, 1); /* no retry, and no wait. */
} }
intf->null_user_handler = NULL; intf->null_user_handler = NULL;
...@@ -4436,18 +4436,7 @@ static void send_panic_events(char *str) ...@@ -4436,18 +4436,7 @@ static void send_panic_events(char *str)
strncpy(data+5, p, 11); strncpy(data+5, p, 11);
p += size; p += size;
i_ipmi_request(NULL, ipmi_panic_request_and_wait(intf, &addr, &msg);
intf,
&addr,
0,
&msg,
intf,
&smi_msg,
&recv_msg,
0,
intf->channels[0].address,
intf->channels[0].lun,
0, 1); /* no retry, and no wait. */
} }
} }
#endif /* CONFIG_IPMI_PANIC_STRING */ #endif /* CONFIG_IPMI_PANIC_STRING */
......
...@@ -520,6 +520,7 @@ static void panic_halt_ipmi_heartbeat(void) ...@@ -520,6 +520,7 @@ static void panic_halt_ipmi_heartbeat(void)
msg.cmd = IPMI_WDOG_RESET_TIMER; msg.cmd = IPMI_WDOG_RESET_TIMER;
msg.data = NULL; msg.data = NULL;
msg.data_len = 0; msg.data_len = 0;
atomic_add(2, &panic_done_count);
rv = ipmi_request_supply_msgs(watchdog_user, rv = ipmi_request_supply_msgs(watchdog_user,
(struct ipmi_addr *) &addr, (struct ipmi_addr *) &addr,
0, 0,
...@@ -528,8 +529,8 @@ static void panic_halt_ipmi_heartbeat(void) ...@@ -528,8 +529,8 @@ static void panic_halt_ipmi_heartbeat(void)
&panic_halt_heartbeat_smi_msg, &panic_halt_heartbeat_smi_msg,
&panic_halt_heartbeat_recv_msg, &panic_halt_heartbeat_recv_msg,
1); 1);
if (!rv) if (rv)
atomic_add(2, &panic_done_count); atomic_sub(2, &panic_done_count);
} }
static struct ipmi_smi_msg panic_halt_smi_msg = { static struct ipmi_smi_msg panic_halt_smi_msg = {
...@@ -553,16 +554,18 @@ static void panic_halt_ipmi_set_timeout(void) ...@@ -553,16 +554,18 @@ static void panic_halt_ipmi_set_timeout(void)
/* Wait for the messages to be free. */ /* Wait for the messages to be free. */
while (atomic_read(&panic_done_count) != 0) while (atomic_read(&panic_done_count) != 0)
ipmi_poll_interface(watchdog_user); ipmi_poll_interface(watchdog_user);
atomic_add(2, &panic_done_count);
rv = i_ipmi_set_timeout(&panic_halt_smi_msg, rv = i_ipmi_set_timeout(&panic_halt_smi_msg,
&panic_halt_recv_msg, &panic_halt_recv_msg,
&send_heartbeat_now); &send_heartbeat_now);
if (!rv) { if (rv) {
atomic_add(2, &panic_done_count); atomic_sub(2, &panic_done_count);
if (send_heartbeat_now)
panic_halt_ipmi_heartbeat();
} else
printk(KERN_WARNING PFX printk(KERN_WARNING PFX
"Unable to extend the watchdog timeout."); "Unable to extend the watchdog timeout.");
} else {
if (send_heartbeat_now)
panic_halt_ipmi_heartbeat();
}
while (atomic_read(&panic_done_count) != 0) while (atomic_read(&panic_done_count) != 0)
ipmi_poll_interface(watchdog_user); ipmi_poll_interface(watchdog_user);
} }
......
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