diff options
author | Corey Minyard <cminyard@mvista.com> | 2012-03-28 17:42:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-28 20:14:36 -0400 |
commit | 895dcfd1cab84d7e1c22af645a7f2f3c9bb5f24e (patch) | |
tree | bfa060ef5fb76ffb0cd5fbd168140895686d0fad /drivers/char | |
parent | 7adf579c8babf62026e6aab1dee85e6b104d9936 (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.c | 103 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_watchdog.c | 17 |
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 | ||
2797 | void ipmi_poll_interface(ipmi_user_t user) | 2797 | static 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 | |||
2805 | void ipmi_poll_interface(ipmi_user_t user) | ||
2806 | { | ||
2807 | ipmi_poll(user->intf); | ||
2808 | } | ||
2807 | EXPORT_SYMBOL(ipmi_poll_interface); | 2809 | EXPORT_SYMBOL(ipmi_poll_interface); |
2808 | 2810 | ||
2809 | int ipmi_register_smi(struct ipmi_smi_handlers *handlers, | 2811 | int 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 | ||
4209 | static atomic_t panic_done_count = ATOMIC_INIT(0); | ||
4210 | |||
4207 | static void dummy_smi_done_handler(struct ipmi_smi_msg *msg) | 4211 | static void dummy_smi_done_handler(struct ipmi_smi_msg *msg) |
4208 | { | 4212 | { |
4213 | atomic_dec(&panic_done_count); | ||
4209 | } | 4214 | } |
4210 | 4215 | ||
4211 | static void dummy_recv_done_handler(struct ipmi_recv_msg *msg) | 4216 | static 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 | */ | ||
4224 | static 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 | ||
535 | static struct ipmi_smi_msg panic_halt_smi_msg = { | 536 | static 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 | } |