diff options
author | Corey Minyard <minyard@acm.org> | 2005-05-01 11:59:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-05-01 11:59:12 -0400 |
commit | 882fe011a92fa4fc31ca6cc95b279f7e4e52935c (patch) | |
tree | da1fc3fab16f937c79a83024c552813f8d61602f /drivers/char | |
parent | 9dbf68f97d585265eaadd15aea308efd9ae39d34 (diff) |
[PATCH] ipmi: fix a deadlock
Correct an issue with the IPMI message layer taking a lock and calling
lower layer driver. If an error occrues at the lower layer the lock can be
taken again causing a deadlock. The lock is released before calling the
lower layer.
Signed-off-by: David Griego <dgriego@mvista.com>
Signed-off-by: Corey Minyard <minyard@acm.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/ipmi/ipmi_msghandler.c | 36 |
1 files changed, 21 insertions, 15 deletions
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index a6606a1aced7..d7fb452af7f9 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c | |||
@@ -2588,28 +2588,20 @@ handle_msg_timeout(struct ipmi_recv_msg *msg) | |||
2588 | deliver_response(msg); | 2588 | deliver_response(msg); |
2589 | } | 2589 | } |
2590 | 2590 | ||
2591 | static void | 2591 | static struct ipmi_smi_msg * |
2592 | send_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, | 2592 | smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, |
2593 | struct ipmi_smi_msg *smi_msg, | 2593 | unsigned char seq, long seqid) |
2594 | unsigned char seq, long seqid) | ||
2595 | { | 2594 | { |
2596 | if (!smi_msg) | 2595 | struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg(); |
2597 | smi_msg = ipmi_alloc_smi_msg(); | ||
2598 | if (!smi_msg) | 2596 | if (!smi_msg) |
2599 | /* If we can't allocate the message, then just return, we | 2597 | /* If we can't allocate the message, then just return, we |
2600 | get 4 retries, so this should be ok. */ | 2598 | get 4 retries, so this should be ok. */ |
2601 | return; | 2599 | return NULL; |
2602 | 2600 | ||
2603 | memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len); | 2601 | memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len); |
2604 | smi_msg->data_size = recv_msg->msg.data_len; | 2602 | smi_msg->data_size = recv_msg->msg.data_len; |
2605 | smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid); | 2603 | smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid); |
2606 | 2604 | ||
2607 | /* Send the new message. We send with a zero priority. It | ||
2608 | timed out, I doubt time is that critical now, and high | ||
2609 | priority messages are really only for messages to the local | ||
2610 | MC, which don't get resent. */ | ||
2611 | intf->handlers->sender(intf->send_info, smi_msg, 0); | ||
2612 | |||
2613 | #ifdef DEBUG_MSGING | 2605 | #ifdef DEBUG_MSGING |
2614 | { | 2606 | { |
2615 | int m; | 2607 | int m; |
@@ -2619,6 +2611,7 @@ send_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, | |||
2619 | printk("\n"); | 2611 | printk("\n"); |
2620 | } | 2612 | } |
2621 | #endif | 2613 | #endif |
2614 | return smi_msg; | ||
2622 | } | 2615 | } |
2623 | 2616 | ||
2624 | static void | 2617 | static void |
@@ -2683,14 +2676,13 @@ ipmi_timeout_handler(long timeout_period) | |||
2683 | intf->timed_out_ipmb_commands++; | 2676 | intf->timed_out_ipmb_commands++; |
2684 | spin_unlock(&intf->counter_lock); | 2677 | spin_unlock(&intf->counter_lock); |
2685 | } else { | 2678 | } else { |
2679 | struct ipmi_smi_msg *smi_msg; | ||
2686 | /* More retries, send again. */ | 2680 | /* More retries, send again. */ |
2687 | 2681 | ||
2688 | /* Start with the max timer, set to normal | 2682 | /* Start with the max timer, set to normal |
2689 | timer after the message is sent. */ | 2683 | timer after the message is sent. */ |
2690 | ent->timeout = MAX_MSG_TIMEOUT; | 2684 | ent->timeout = MAX_MSG_TIMEOUT; |
2691 | ent->retries_left--; | 2685 | ent->retries_left--; |
2692 | send_from_recv_msg(intf, ent->recv_msg, NULL, | ||
2693 | j, ent->seqid); | ||
2694 | spin_lock(&intf->counter_lock); | 2686 | spin_lock(&intf->counter_lock); |
2695 | if (ent->recv_msg->addr.addr_type | 2687 | if (ent->recv_msg->addr.addr_type |
2696 | == IPMI_LAN_ADDR_TYPE) | 2688 | == IPMI_LAN_ADDR_TYPE) |
@@ -2698,6 +2690,20 @@ ipmi_timeout_handler(long timeout_period) | |||
2698 | else | 2690 | else |
2699 | intf->retransmitted_ipmb_commands++; | 2691 | intf->retransmitted_ipmb_commands++; |
2700 | spin_unlock(&intf->counter_lock); | 2692 | spin_unlock(&intf->counter_lock); |
2693 | smi_msg = smi_from_recv_msg(intf, | ||
2694 | ent->recv_msg, j, ent->seqid); | ||
2695 | if(!smi_msg) | ||
2696 | continue; | ||
2697 | |||
2698 | spin_unlock_irqrestore(&(intf->seq_lock),flags); | ||
2699 | /* Send the new message. We send with a zero | ||
2700 | * priority. It timed out, I doubt time is | ||
2701 | * that critical now, and high priority | ||
2702 | * messages are really only for messages to the | ||
2703 | * local MC, which don't get resent. */ | ||
2704 | intf->handlers->sender(intf->send_info, | ||
2705 | smi_msg, 0); | ||
2706 | spin_lock_irqsave(&(intf->seq_lock), flags); | ||
2701 | } | 2707 | } |
2702 | } | 2708 | } |
2703 | spin_unlock_irqrestore(&(intf->seq_lock), flags); | 2709 | spin_unlock_irqrestore(&(intf->seq_lock), flags); |