VYPR
Unrated severityNVD Advisory· Published May 28, 2026

CVE-2026-46177

CVE-2026-46177

Description

In the Linux kernel, the following vulnerability has been resolved:

ipmi: Add limits to event and receive message requests

The driver would just fetch events and receive messages until the BMC said it was done. To avoid issues with BMCs that never say they are done, add a limit of 10 fetches at a time.

In addition, an si interface has an attn state it can return from the hardware which is supposed to cause a flag fetch to see if the driver needs to fetch events or message or a few other things. If the attn bit gets stuck, it's a similar problem. So allow messages in between flag fetches so the driver itself doesn't get stuck.

This is a more general fix than the previous fix for the specific bad BMC, but should fix the more general issue of a BMC that won't stop saying it has data.

This has been there from the beginning of the driver. It's not a bug per-se, but it is accounting for bugs in BMCs.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Linux kernel IPMI driver limits event/receive message fetches to 10 per call and adds interrupt-driven flag polling to prevent hang from buggy BMCs.

Vulnerability

In the Linux kernel IPMI driver (all versions since its inception), the event and receive message request handling lacked a bound on how many events or messages it would fetch at once. The driver would continue fetching until the BMC indicated it had no more data. A buggy BMC that never signals completion could cause an unbounded fetch loop, stalling the system. Additionally, the si interface has an attn state from hardware that triggers a flag fetch; if the attn bit becomes stuck, the driver could also hang. The fix introduces a limit of 10 fetches per call and allows message processing between flag fetches to prevent driver lockup. This is not a bug per se but a hardening against misbehaving BMCs [1].

Exploitation

An attacker would need a BMC that is either buggy or has been compromised/flashed with malicious firmware that intentionally never clears its “data available” or attn flags. No special authentication or network position is required beyond normal access to the system’s IPMI interface (local or via the BMC). The exploit sequence: the BMC continuously reports that events or messages are pending, causing the kernel IPMI driver to repeatedly fetch them without termination, leading to an indefinite hang in the kernel IPMI thread. The attacker does not need to interact with the driver on the host side; the attack is driven entirely by the BMC’s behavior [1].

Impact

Successful exploitation causes a denial of service (DoS) — the kernel IPMI event/receive message thread hangs, preventing further IPMI communication and potentially impacting system management functions. No privilege escalation, data disclosure, or remote code execution is possible; the impact is strictly availability loss for management interfaces [1].

Mitigation

The fix was committed to the Linux kernel stable tree as commit c024167baee08c72182ca2e7dc5fb9f20 (referenced in [1]). Users should apply this patch or update to a kernel version that includes it. No workaround is available for unpatched kernels; the issue affects all IPMI drivers from the beginning, but only BMCs with stuck flags trigger the condition. The vulnerability is not listed on CISA’s Known Exploited Vulnerabilities (KEV) catalog as of the publication date [1].

AI Insight generated on May 28, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

1

Patches

10
c4cca2369686

ipmi: Add limits to event and receive message requests

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitCorey MinyardApr 20, 2026Fixed in 7.1-rc3via kernel-cna
4 files changed · +128 28
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index 08c208cc64c56b..7c3c463e08da25 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -168,6 +168,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -410,7 +414,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -421,7 +428,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -595,6 +605,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -646,6 +657,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -684,6 +700,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -825,6 +846,26 @@ restart:
     		goto out;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -852,15 +893,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index 08c208cc64c56b..7c3c463e08da25 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -168,6 +168,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -410,7 +414,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -421,7 +428,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -595,6 +605,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -646,6 +657,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -684,6 +700,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -825,6 +846,26 @@ restart:
     		goto out;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -852,15 +893,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index b49500a1bd3637..f3798f4e6a6374 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index b49500a1bd3637..f3798f4e6a6374 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
67c44e0deba9

ipmi: Add limits to event and receive message requests

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitCorey MinyardApr 20, 2026Fixed in 6.6.140via kernel-cna
4 files changed · +128 28
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index 5cd031f3fc9700..3db6df94ebe79b 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -162,6 +162,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -394,7 +398,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -405,7 +412,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -579,6 +589,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -624,6 +635,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -662,6 +678,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -789,6 +810,26 @@ restart:
     		goto restart;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -822,15 +863,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index 5cd031f3fc9700..3db6df94ebe79b 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -162,6 +162,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -394,7 +398,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -405,7 +412,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -579,6 +589,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -624,6 +635,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -662,6 +678,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -789,6 +810,26 @@ restart:
     		goto restart;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -822,15 +863,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index df8dd50b4cbed0..cc0238fcf7dc7f 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index df8dd50b4cbed0..cc0238fcf7dc7f 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
e20212b431be

ipmi: Add limits to event and receive message requests

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitCorey MinyardApr 20, 2026Fixed in 6.12.88via kernel-cna
4 files changed · +128 28
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index eea23a3b966ef1..a3eca46ca0abca 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -162,6 +162,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -394,7 +398,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -405,7 +412,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -579,6 +589,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -624,6 +635,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -662,6 +678,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -789,6 +810,26 @@ restart:
     		goto restart;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -822,15 +863,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index eea23a3b966ef1..a3eca46ca0abca 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -162,6 +162,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -394,7 +398,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -405,7 +412,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -579,6 +589,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -624,6 +635,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -662,6 +678,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -789,6 +810,26 @@ restart:
     		goto restart;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -822,15 +863,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index d04b391048fbaa..9d8872cbc43e10 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index d04b391048fbaa..9d8872cbc43e10 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
3d37d2165df9

ipmi: Add limits to event and receive message requests

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitCorey MinyardApr 20, 2026Fixed in 6.18.30via kernel-cna
4 files changed · +128 28
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index f3a4fa98b1efd2..f67b7ffe1050c5 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -168,6 +168,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -411,7 +415,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -422,7 +429,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -596,6 +606,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -641,6 +652,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -679,6 +695,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -820,6 +841,26 @@ restart:
     		goto out;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -847,15 +888,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index f3a4fa98b1efd2..f67b7ffe1050c5 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -168,6 +168,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -411,7 +415,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -422,7 +429,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -596,6 +606,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -641,6 +652,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -679,6 +695,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -820,6 +841,26 @@ restart:
     		goto out;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -847,15 +888,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index 4d4fbf6931ffcc..164ef375b36432 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index 4d4fbf6931ffcc..164ef375b36432 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
c024167fb004

ipmi: Add limits to event and receive message requests

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitCorey MinyardApr 20, 2026Fixed in 7.0.7via kernel-cna
4 files changed · +128 28
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index 4a9e9de4d684f9..c4f746b3c46041 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -168,6 +168,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -410,7 +414,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -421,7 +428,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -595,6 +605,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -640,6 +651,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -678,6 +694,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -819,6 +840,26 @@ restart:
     		goto out;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -846,15 +887,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index 4a9e9de4d684f9..c4f746b3c46041 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -168,6 +168,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -410,7 +414,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -421,7 +428,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -595,6 +605,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -640,6 +651,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -678,6 +694,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -819,6 +840,26 @@ restart:
     		goto out;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -846,15 +887,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index 69765bbe08be14..f419b46bf00207 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index 69765bbe08be14..f419b46bf00207 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
67c44e0deba9

ipmi: Add limits to event and receive message requests

4 files changed · +128 28
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index 5cd031f3fc9700..3db6df94ebe79b 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -162,6 +162,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -394,7 +398,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -405,7 +412,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -579,6 +589,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -624,6 +635,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -662,6 +678,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -789,6 +810,26 @@ restart:
     		goto restart;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -822,15 +863,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index 5cd031f3fc9700..3db6df94ebe79b 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -162,6 +162,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -394,7 +398,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -405,7 +412,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -579,6 +589,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -624,6 +635,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -662,6 +678,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -789,6 +810,26 @@ restart:
     		goto restart;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -822,15 +863,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index df8dd50b4cbed0..cc0238fcf7dc7f 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index df8dd50b4cbed0..cc0238fcf7dc7f 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
3d37d2165df9

ipmi: Add limits to event and receive message requests

4 files changed · +128 28
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index f3a4fa98b1efd2..f67b7ffe1050c5 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -168,6 +168,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -411,7 +415,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -422,7 +429,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -596,6 +606,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -641,6 +652,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -679,6 +695,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -820,6 +841,26 @@ restart:
     		goto out;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -847,15 +888,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index f3a4fa98b1efd2..f67b7ffe1050c5 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -168,6 +168,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -411,7 +415,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -422,7 +429,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -596,6 +606,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -641,6 +652,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -679,6 +695,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -820,6 +841,26 @@ restart:
     		goto out;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -847,15 +888,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index 4d4fbf6931ffcc..164ef375b36432 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index 4d4fbf6931ffcc..164ef375b36432 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
c024167fb004

ipmi: Add limits to event and receive message requests

4 files changed · +128 28
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index 4a9e9de4d684f9..c4f746b3c46041 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -168,6 +168,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -410,7 +414,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -421,7 +428,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -595,6 +605,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -640,6 +651,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -678,6 +694,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -819,6 +840,26 @@ restart:
     		goto out;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -846,15 +887,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index 4a9e9de4d684f9..c4f746b3c46041 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -168,6 +168,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -410,7 +414,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -421,7 +428,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -595,6 +605,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -640,6 +651,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -678,6 +694,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -819,6 +840,26 @@ restart:
     		goto out;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -846,15 +887,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index 69765bbe08be14..f419b46bf00207 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index 69765bbe08be14..f419b46bf00207 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
c4cca2369686

ipmi: Add limits to event and receive message requests

4 files changed · +128 28
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index 08c208cc64c56b..7c3c463e08da25 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -168,6 +168,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -410,7 +414,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -421,7 +428,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -595,6 +605,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -646,6 +657,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -684,6 +700,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -825,6 +846,26 @@ restart:
     		goto out;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -852,15 +893,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index 08c208cc64c56b..7c3c463e08da25 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -168,6 +168,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -410,7 +414,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -421,7 +428,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -595,6 +605,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -646,6 +657,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -684,6 +700,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -825,6 +846,26 @@ restart:
     		goto out;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -852,15 +893,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index b49500a1bd3637..f3798f4e6a6374 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index b49500a1bd3637..f3798f4e6a6374 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
e20212b431be

ipmi: Add limits to event and receive message requests

4 files changed · +128 28
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index eea23a3b966ef1..a3eca46ca0abca 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -162,6 +162,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -394,7 +398,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -405,7 +412,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -579,6 +589,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -624,6 +635,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -662,6 +678,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -789,6 +810,26 @@ restart:
     		goto restart;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -822,15 +863,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_si_intf.c+43 11 modified
    diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
    index eea23a3b966ef1..a3eca46ca0abca 100644
    --- a/drivers/char/ipmi/ipmi_si_intf.c
    +++ b/drivers/char/ipmi/ipmi_si_intf.c
    @@ -162,6 +162,10 @@ struct smi_info {
     			     OEM2_DATA_AVAIL)
     	unsigned char       msg_flags;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +	bool		    last_was_flag_fetch;
    +
     	/* Does the BMC have an event buffer? */
     	bool		    has_event_buffer;
     
    @@ -394,7 +398,10 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_MESSAGES;
    +	if (smi_info->si_state != SI_GETTING_MESSAGES) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_MESSAGES;
    +	}
     }
     
     static void start_getting_events(struct smi_info *smi_info)
    @@ -405,7 +412,10 @@ static void start_getting_events(struct smi_info *smi_info)
     
     	start_new_msg(smi_info, smi_info->curr_msg->data,
     		      smi_info->curr_msg->data_size);
    -	smi_info->si_state = SI_GETTING_EVENTS;
    +	if (smi_info->si_state != SI_GETTING_EVENTS) {
    +		smi_info->num_requests_in_a_row = 0;
    +		smi_info->si_state = SI_GETTING_EVENTS;
    +	}
     }
     
     /*
    @@ -579,6 +589,7 @@ static void handle_transaction_done(struct smi_info *smi_info)
     			smi_info->si_state = SI_NORMAL;
     		} else {
     			smi_info->msg_flags = msg[3];
    +			smi_info->last_was_flag_fetch = true;
     			handle_flags(smi_info);
     		}
     		break;
    @@ -624,6 +635,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, events);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -662,6 +678,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
     		} else {
     			smi_inc_stat(smi_info, incoming_messages);
     
    +			smi_info->num_requests_in_a_row++;
    +			if (smi_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			/*
     			 * Do this before we deliver the message
     			 * because delivering the message releases the
    @@ -789,6 +810,26 @@ restart:
     		goto restart;
     	}
     
    +	/*
    +	 * If we are currently idle, or if the last thing that was
    +	 * done was a flag fetch and there is a message pending, try
    +	 * to start the next message.
    +	 *
    +	 * We do the waiting message check to avoid a stuck flag
    +	 * completely wedging the driver.  Let a message through
    +	 * in between flag operations if that happens.
    +	 */
    +	if (si_sm_result == SI_SM_IDLE ||
    +	    (si_sm_result == SI_SM_ATTN && smi_info->waiting_msg &&
    +	     smi_info->last_was_flag_fetch)) {
    +		smi_info->last_was_flag_fetch = false;
    +		smi_inc_stat(smi_info, idles);
    +
    +		si_sm_result = start_next_msg(smi_info);
    +		if (si_sm_result != SI_SM_IDLE)
    +			goto restart;
    +	}
    +
     	/*
     	 * We prefer handling attn over new messages.  But don't do
     	 * this if there is not yet an upper layer to handle anything.
    @@ -822,15 +863,6 @@ restart:
     		}
     	}
     
    -	/* If we are currently idle, try to start the next message. */
    -	if (si_sm_result == SI_SM_IDLE) {
    -		smi_inc_stat(smi_info, idles);
    -
    -		si_sm_result = start_next_msg(smi_info);
    -		if (si_sm_result != SI_SM_IDLE)
    -			goto restart;
    -	}
    -
     	if ((si_sm_result == SI_SM_IDLE)
     	    && (atomic_read(&smi_info->req_events))) {
     		/*
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index d04b391048fbaa..9d8872cbc43e10 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/char/ipmi/ipmi_ssif.c+21 3 modified
    diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
    index d04b391048fbaa..9d8872cbc43e10 100644
    --- a/drivers/char/ipmi/ipmi_ssif.c
    +++ b/drivers/char/ipmi/ipmi_ssif.c
    @@ -225,6 +225,9 @@ struct ssif_info {
     	bool		    has_event_buffer;
     	bool		    supports_alert;
     
    +	/* When requesting events and messages, don't do it forever. */
    +	unsigned int        num_requests_in_a_row;
    +
     	/*
     	 * Used to tell what we should do with alerts.  If we are
     	 * waiting on a response, read the data immediately.
    @@ -413,7 +416,10 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags)
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	if (ssif_info->ssif_state != SSIF_GETTING_EVENTS) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_EVENTS;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -436,7 +442,10 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info,
     	}
     
     	ssif_info->curr_msg = msg;
    -	ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	if (ssif_info->ssif_state != SSIF_GETTING_MESSAGES) {
    +		ssif_info->num_requests_in_a_row = 0;
    +		ssif_info->ssif_state = SSIF_GETTING_MESSAGES;
    +	}
     	ipmi_ssif_unlock_cond(ssif_info, flags);
     
     	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
    @@ -843,6 +852,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
    +
     			handle_flags(ssif_info, flags);
     			ssif_inc_stat(ssif_info, events);
     			deliver_recv_msg(ssif_info, msg);
    @@ -876,6 +890,11 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
     			ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
     			handle_flags(ssif_info, flags);
     		} else {
    +			ssif_info->num_requests_in_a_row++;
    +			if (ssif_info->num_requests_in_a_row > 10)
    +				/* Stop if we do this too many times. */
    +				ssif_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
    +
     			ssif_inc_stat(ssif_info, incoming_messages);
     			handle_flags(ssif_info, flags);
     			deliver_recv_msg(ssif_info, msg);
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Root cause

"Missing upper bound on consecutive event/message fetch iterations allows a BMC that never signals completion to cause an infinite loop in the IPMI driver."

Attack vector

A faulty or malicious BMC can continuously assert that events or messages are available, causing the IPMI driver to loop indefinitely fetching data. The driver previously had no upper bound on the number of consecutive event or message fetches. Additionally, on the SI interface, a stuck hardware "attn" (attention) bit could cause the driver to repeatedly perform flag fetches without ever processing pending outgoing messages, effectively wedging the driver. An attacker with control over the BMC (or a BMC that malfunctions) can trigger this resource-exhaustion condition, leading to a denial of service on the host system's IPMI subsystem.

Affected code

The vulnerability affects the IPMI driver's event and message fetch loops in `drivers/char/ipmi/ipmi_si_intf.c` (functions `handle_transaction_done`, `start_getting_msg_queue`, `start_getting_events`, and the `restart` loop) and `drivers/char/ipmi/ipmi_ssif.c` (functions `msg_done_handler`, `start_event_fetch`, `start_recv_msg_fetch`). The issue has been present since the driver's introduction in Linux-2.6.12-rc2 [patch_id=2898025].

What the fix does

The patch introduces a `num_requests_in_a_row` counter that is incremented each time an event or message is successfully fetched. When the counter exceeds 10, the driver clears the corresponding flag bit (`EVENT_MSG_BUFFER_FULL` or `RECEIVE_MSG_AVAIL`) in `msg_flags`, stopping further fetches [patch_id=2898025]. The counter is reset to zero when entering a new fetch state. For the SI interface, a `last_was_flag_fetch` boolean is added; when the attn state is stuck and a message is waiting, the driver now prioritizes sending that message instead of looping on flag fetches. This prevents the driver from being completely wedged by a stuck attn bit.

Preconditions

  • inputA BMC (Baseboard Management Controller) that is faulty or malicious, which continuously reports events or messages as available without ever indicating completion.
  • inputFor the SI interface attn-stuck scenario: a hardware attn bit that remains asserted, causing repeated flag fetches.
  • configThe IPMI driver must be active and communicating with the BMC over the SI or SSIF interface.

Generated on May 28, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.