aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorCorey Minyard <cminyard@mvista.com>2012-03-28 17:42:49 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-28 20:14:36 -0400
commit895dcfd1cab84d7e1c22af645a7f2f3c9bb5f24e (patch)
treebfa060ef5fb76ffb0cd5fbd168140895686d0fad /drivers/char
parent7adf579c8babf62026e6aab1dee85e6b104d9936 (diff)
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: 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')
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c103
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c17
2 files changed, 56 insertions, 64 deletions
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 289ab506b79b..5c1820c2a853 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -2794,16 +2794,18 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
2794 return; 2794 return;
2795} 2795}
2796 2796
2797void ipmi_poll_interface(ipmi_user_t user) 2797static void ipmi_poll(ipmi_smi_t intf)
2798{ 2798{
2799 ipmi_smi_t intf = user->intf;
2800
2801 if (intf->handlers->poll) 2799 if (intf->handlers->poll)
2802 intf->handlers->poll(intf->send_info); 2800 intf->handlers->poll(intf->send_info);
2803
2804 /* In case something came in */ 2801 /* In case something came in */
2805 handle_new_recv_msgs(intf); 2802 handle_new_recv_msgs(intf);
2806} 2803}
2804
2805void ipmi_poll_interface(ipmi_user_t user)
2806{
2807 ipmi_poll(user->intf);
2808}
2807EXPORT_SYMBOL(ipmi_poll_interface); 2809EXPORT_SYMBOL(ipmi_poll_interface);
2808 2810
2809int ipmi_register_smi(struct ipmi_smi_handlers *handlers, 2811int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
@@ -4204,12 +4206,48 @@ EXPORT_SYMBOL(ipmi_free_recv_msg);
4204 4206
4205#ifdef CONFIG_IPMI_PANIC_EVENT 4207#ifdef CONFIG_IPMI_PANIC_EVENT
4206 4208
4209static atomic_t panic_done_count = ATOMIC_INIT(0);
4210
4207static void dummy_smi_done_handler(struct ipmi_smi_msg *msg) 4211static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
4208{ 4212{
4213 atomic_dec(&panic_done_count);
4209} 4214}
4210 4215
4211static void dummy_recv_done_handler(struct ipmi_recv_msg *msg) 4216static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
4212{ 4217{
4218 atomic_dec(&panic_done_count);
4219}
4220
4221/*
4222 * Inside a panic, send a message and wait for a response.
4223 */
4224static void ipmi_panic_request_and_wait(ipmi_smi_t intf,
4225 struct ipmi_addr *addr,
4226 struct kernel_ipmi_msg *msg)
4227{
4228 struct ipmi_smi_msg smi_msg;
4229 struct ipmi_recv_msg recv_msg;
4230 int rv;
4231
4232 smi_msg.done = dummy_smi_done_handler;
4233 recv_msg.done = dummy_recv_done_handler;
4234 atomic_add(2, &panic_done_count);
4235 rv = i_ipmi_request(NULL,
4236 intf,
4237 addr,
4238 0,
4239 msg,
4240 intf,
4241 &smi_msg,
4242 &recv_msg,
4243 0,
4244 intf->channels[0].address,
4245 intf->channels[0].lun,
4246 0, 1); /* Don't retry, and don't wait. */
4247 if (rv)
4248 atomic_sub(2, &panic_done_count);
4249 while (atomic_read(&panic_done_count) != 0)
4250 ipmi_poll(intf);
4213} 4251}
4214 4252
4215#ifdef CONFIG_IPMI_PANIC_STRING 4253#ifdef CONFIG_IPMI_PANIC_STRING
@@ -4248,8 +4286,6 @@ static void send_panic_events(char *str)
4248 unsigned char data[16]; 4286 unsigned char data[16];
4249 struct ipmi_system_interface_addr *si; 4287 struct ipmi_system_interface_addr *si;
4250 struct ipmi_addr addr; 4288 struct ipmi_addr addr;
4251 struct ipmi_smi_msg smi_msg;
4252 struct ipmi_recv_msg recv_msg;
4253 4289
4254 si = (struct ipmi_system_interface_addr *) &addr; 4290 si = (struct ipmi_system_interface_addr *) &addr;
4255 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; 4291 si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
@@ -4277,9 +4313,6 @@ static void send_panic_events(char *str)
4277 data[7] = str[2]; 4313 data[7] = str[2];
4278 } 4314 }
4279 4315
4280 smi_msg.done = dummy_smi_done_handler;
4281 recv_msg.done = dummy_recv_done_handler;
4282
4283 /* For every registered interface, send the event. */ 4316 /* For every registered interface, send the event. */
4284 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { 4317 list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
4285 if (!intf->handlers) 4318 if (!intf->handlers)
@@ -4289,18 +4322,7 @@ static void send_panic_events(char *str)
4289 intf->run_to_completion = 1; 4322 intf->run_to_completion = 1;
4290 /* Send the event announcing the panic. */ 4323 /* Send the event announcing the panic. */
4291 intf->handlers->set_run_to_completion(intf->send_info, 1); 4324 intf->handlers->set_run_to_completion(intf->send_info, 1);
4292 i_ipmi_request(NULL, 4325 ipmi_panic_request_and_wait(intf, &addr, &msg);
4293 intf,
4294 &addr,
4295 0,
4296 &msg,
4297 intf,
4298 &smi_msg,
4299 &recv_msg,
4300 0,
4301 intf->channels[0].address,
4302 intf->channels[0].lun,
4303 0, 1); /* Don't retry, and don't wait. */
4304 } 4326 }
4305 4327
4306#ifdef CONFIG_IPMI_PANIC_STRING 4328#ifdef CONFIG_IPMI_PANIC_STRING
@@ -4348,18 +4370,7 @@ static void send_panic_events(char *str)
4348 msg.data = NULL; 4370 msg.data = NULL;
4349 msg.data_len = 0; 4371 msg.data_len = 0;
4350 intf->null_user_handler = device_id_fetcher; 4372 intf->null_user_handler = device_id_fetcher;
4351 i_ipmi_request(NULL, 4373 ipmi_panic_request_and_wait(intf, &addr, &msg);
4352 intf,
4353 &addr,
4354 0,
4355 &msg,
4356 intf,
4357 &smi_msg,
4358 &recv_msg,
4359 0,
4360 intf->channels[0].address,
4361 intf->channels[0].lun,
4362 0, 1); /* Don't retry, and don't wait. */
4363 4374
4364 if (intf->local_event_generator) { 4375 if (intf->local_event_generator) {
4365 /* Request the event receiver from the local MC. */ 4376 /* Request the event receiver from the local MC. */
@@ -4368,18 +4379,7 @@ static void send_panic_events(char *str)
4368 msg.data = NULL; 4379 msg.data = NULL;
4369 msg.data_len = 0; 4380 msg.data_len = 0;
4370 intf->null_user_handler = event_receiver_fetcher; 4381 intf->null_user_handler = event_receiver_fetcher;
4371 i_ipmi_request(NULL, 4382 ipmi_panic_request_and_wait(intf, &addr, &msg);
4372 intf,
4373 &addr,
4374 0,
4375 &msg,
4376 intf,
4377 &smi_msg,
4378 &recv_msg,
4379 0,
4380 intf->channels[0].address,
4381 intf->channels[0].lun,
4382 0, 1); /* no retry, and no wait. */
4383 } 4383 }
4384 intf->null_user_handler = NULL; 4384 intf->null_user_handler = NULL;
4385 4385
@@ -4436,18 +4436,7 @@ static void send_panic_events(char *str)
4436 strncpy(data+5, p, 11); 4436 strncpy(data+5, p, 11);
4437 p += size; 4437 p += size;
4438 4438
4439 i_ipmi_request(NULL, 4439 ipmi_panic_request_and_wait(intf, &addr, &msg);
4440 intf,
4441 &addr,
4442 0,
4443 &msg,
4444 intf,
4445 &smi_msg,
4446 &recv_msg,
4447 0,
4448 intf->channels[0].address,
4449 intf->channels[0].lun,
4450 0, 1); /* no retry, and no wait. */
4451 } 4440 }
4452 } 4441 }
4453#endif /* CONFIG_IPMI_PANIC_STRING */ 4442#endif /* CONFIG_IPMI_PANIC_STRING */
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 34767a6d7f42..57a53ba7758c 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -520,6 +520,7 @@ static void panic_halt_ipmi_heartbeat(void)
520 msg.cmd = IPMI_WDOG_RESET_TIMER; 520 msg.cmd = IPMI_WDOG_RESET_TIMER;
521 msg.data = NULL; 521 msg.data = NULL;
522 msg.data_len = 0; 522 msg.data_len = 0;
523 atomic_add(2, &panic_done_count);
523 rv = ipmi_request_supply_msgs(watchdog_user, 524 rv = ipmi_request_supply_msgs(watchdog_user,
524 (struct ipmi_addr *) &addr, 525 (struct ipmi_addr *) &addr,
525 0, 526 0,
@@ -528,8 +529,8 @@ static void panic_halt_ipmi_heartbeat(void)
528 &panic_halt_heartbeat_smi_msg, 529 &panic_halt_heartbeat_smi_msg,
529 &panic_halt_heartbeat_recv_msg, 530 &panic_halt_heartbeat_recv_msg,
530 1); 531 1);
531 if (!rv) 532 if (rv)
532 atomic_add(2, &panic_done_count); 533 atomic_sub(2, &panic_done_count);
533} 534}
534 535
535static struct ipmi_smi_msg panic_halt_smi_msg = { 536static struct ipmi_smi_msg panic_halt_smi_msg = {
@@ -553,16 +554,18 @@ static void panic_halt_ipmi_set_timeout(void)
553 /* Wait for the messages to be free. */ 554 /* Wait for the messages to be free. */
554 while (atomic_read(&panic_done_count) != 0) 555 while (atomic_read(&panic_done_count) != 0)
555 ipmi_poll_interface(watchdog_user); 556 ipmi_poll_interface(watchdog_user);
557 atomic_add(2, &panic_done_count);
556 rv = i_ipmi_set_timeout(&panic_halt_smi_msg, 558 rv = i_ipmi_set_timeout(&panic_halt_smi_msg,
557 &panic_halt_recv_msg, 559 &panic_halt_recv_msg,
558 &send_heartbeat_now); 560 &send_heartbeat_now);
559 if (!rv) { 561 if (rv) {
560 atomic_add(2, &panic_done_count); 562 atomic_sub(2, &panic_done_count);
561 if (send_heartbeat_now)
562 panic_halt_ipmi_heartbeat();
563 } else
564 printk(KERN_WARNING PFX 563 printk(KERN_WARNING PFX
565 "Unable to extend the watchdog timeout."); 564 "Unable to extend the watchdog timeout.");
565 } else {
566 if (send_heartbeat_now)
567 panic_halt_ipmi_heartbeat();
568 }
566 while (atomic_read(&panic_done_count) != 0) 569 while (atomic_read(&panic_done_count) != 0)
567 ipmi_poll_interface(watchdog_user); 570 ipmi_poll_interface(watchdog_user);
568} 571}