Commit 882fe011 authored by Corey Minyard's avatar Corey Minyard Committed by Linus Torvalds
Browse files

[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: default avatarDavid Griego <dgriego@mvista.com>
Signed-off-by: default avatarCorey Minyard <minyard@acm.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 9dbf68f9
Loading
Loading
Loading
Loading
+21 −15
Original line number Diff line number Diff line
@@ -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,
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);