summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorey Minyard <minyard@acm.org>2005-05-01 08:59:12 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-05-01 08:59:12 -0700
commit882fe011a92fa4fc31ca6cc95b279f7e4e52935c (patch)
treeda1fc3fab16f937c79a83024c552813f8d61602f
parent9dbf68f97d585265eaadd15aea308efd9ae39d34 (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>
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c36
1 files changed, 21 insertions, 15 deletions
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index a6606a1aced..d7fb452af7f 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)
deliver_response(msg);
}
-static void
-send_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
- struct ipmi_smi_msg *smi_msg,
- unsigned char seq, long seqid)
+static struct ipmi_smi_msg *
+smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
+ unsigned char seq, long seqid)
{
- if (!smi_msg)
- smi_msg = ipmi_alloc_smi_msg();
+ struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
if (!smi_msg)
/* If we can't allocate the message, then just return, we
get 4 retries, so this should be ok. */
- return;
+ return NULL;
memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
smi_msg->data_size = recv_msg->msg.data_len;
smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
- /* Send the new message. We send with a zero priority. It
- timed out, I doubt time is that critical now, and high
- priority messages are really only for messages to the local
- MC, which don't get resent. */
- intf->handlers->sender(intf->send_info, smi_msg, 0);
-
#ifdef DEBUG_MSGING
{
int m;
@@ -2619,6 +2611,7 @@ send_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
printk("\n");
}
#endif
+ return smi_msg;
}
static void
@@ -2683,14 +2676,13 @@ ipmi_timeout_handler(long timeout_period)
intf->timed_out_ipmb_commands++;
spin_unlock(&intf->counter_lock);
} else {
+ struct ipmi_smi_msg *smi_msg;
/* More retries, send again. */
/* Start with the max timer, set to normal
timer after the message is sent. */
ent->timeout = MAX_MSG_TIMEOUT;
ent->retries_left--;
- send_from_recv_msg(intf, ent->recv_msg, NULL,
- j, ent->seqid);
spin_lock(&intf->counter_lock);
if (ent->recv_msg->addr.addr_type
== IPMI_LAN_ADDR_TYPE)
@@ -2698,6 +2690,20 @@ ipmi_timeout_handler(long timeout_period)
else
intf->retransmitted_ipmb_commands++;
spin_unlock(&intf->counter_lock);
+ smi_msg = smi_from_recv_msg(intf,
+ ent->recv_msg, j, ent->seqid);
+ if(!smi_msg)
+ continue;
+
+ spin_unlock_irqrestore(&(intf->seq_lock),flags);
+ /* Send the new message. We send with a zero
+ * priority. It timed out, I doubt time is
+ * that critical now, and high priority
+ * messages are really only for messages to the
+ * local MC, which don't get resent. */
+ intf->handlers->sender(intf->send_info,
+ smi_msg, 0);
+ spin_lock_irqsave(&(intf->seq_lock), flags);
}
}
spin_unlock_irqrestore(&(intf->seq_lock), flags);