提交 8584ec6a 编写于 作者: L Lv Zheng 提交者: Rafael J. Wysocki

ACPI / IPMI: Fix race caused by the timed out ACPI IPMI transfers

This patch fixes races caused by timed out ACPI IPMI transfers.

This patch uses timeout mechanism provided by ipmi_si to avoid the race
that the msg_done flag is set but without any protection, its content can
be invalid.  Thanks for the suggestion of Corey Minyard.
Signed-off-by: NLv Zheng <lv.zheng@intel.com>
Reviewed-by: NHuang Ying <ying.huang@intel.com>
Signed-off-by: NRafael J. Wysocki <rafael.j.wysocki@intel.com>
上级 5ac557ef
...@@ -51,7 +51,7 @@ MODULE_LICENSE("GPL"); ...@@ -51,7 +51,7 @@ MODULE_LICENSE("GPL");
#define ACPI_IPMI_TIMEOUT 0x10 #define ACPI_IPMI_TIMEOUT 0x10
#define ACPI_IPMI_UNKNOWN 0x07 #define ACPI_IPMI_UNKNOWN 0x07
/* the IPMI timeout is 5s */ /* the IPMI timeout is 5s */
#define IPMI_TIMEOUT (5 * HZ) #define IPMI_TIMEOUT (5000)
#define ACPI_IPMI_MAX_MSG_LENGTH 64 #define ACPI_IPMI_MAX_MSG_LENGTH 64
struct acpi_ipmi_device { struct acpi_ipmi_device {
...@@ -135,6 +135,7 @@ static struct acpi_ipmi_msg *acpi_alloc_ipmi_msg(struct acpi_ipmi_device *ipmi) ...@@ -135,6 +135,7 @@ static struct acpi_ipmi_msg *acpi_alloc_ipmi_msg(struct acpi_ipmi_device *ipmi)
init_completion(&ipmi_msg->tx_complete); init_completion(&ipmi_msg->tx_complete);
INIT_LIST_HEAD(&ipmi_msg->head); INIT_LIST_HEAD(&ipmi_msg->head);
ipmi_msg->device = ipmi; ipmi_msg->device = ipmi;
ipmi_msg->msg_done = ACPI_IPMI_UNKNOWN;
return ipmi_msg; return ipmi_msg;
} }
...@@ -192,7 +193,7 @@ static int acpi_format_ipmi_request(struct acpi_ipmi_msg *tx_msg, ...@@ -192,7 +193,7 @@ static int acpi_format_ipmi_request(struct acpi_ipmi_msg *tx_msg,
} }
static void acpi_format_ipmi_response(struct acpi_ipmi_msg *msg, static void acpi_format_ipmi_response(struct acpi_ipmi_msg *msg,
acpi_integer *value, int rem_time) acpi_integer *value)
{ {
struct acpi_ipmi_buffer *buffer; struct acpi_ipmi_buffer *buffer;
...@@ -201,24 +202,17 @@ static void acpi_format_ipmi_response(struct acpi_ipmi_msg *msg, ...@@ -201,24 +202,17 @@ static void acpi_format_ipmi_response(struct acpi_ipmi_msg *msg,
* IPMI message returned by IPMI command. * IPMI message returned by IPMI command.
*/ */
buffer = (struct acpi_ipmi_buffer *)value; buffer = (struct acpi_ipmi_buffer *)value;
if (!rem_time && !msg->msg_done) {
buffer->status = ACPI_IPMI_TIMEOUT;
return;
}
/* /*
* If the flag of msg_done is not set or the recv length is zero, it * If the flag of msg_done is not set, it means that the IPMI command is
* means that the IPMI command is not executed correctly. * not executed correctly.
* The status code will be ACPI_IPMI_UNKNOWN.
*/ */
if (!msg->msg_done || !msg->rx_len) { buffer->status = msg->msg_done;
buffer->status = ACPI_IPMI_UNKNOWN; if (msg->msg_done != ACPI_IPMI_OK)
return; return;
}
/* /*
* If the IPMI response message is obtained correctly, the status code * If the IPMI response message is obtained correctly, the status code
* will be ACPI_IPMI_OK * will be ACPI_IPMI_OK
*/ */
buffer->status = ACPI_IPMI_OK;
buffer->length = msg->rx_len; buffer->length = msg->rx_len;
memcpy(buffer->data, msg->data, msg->rx_len); memcpy(buffer->data, msg->data, msg->rx_len);
} }
...@@ -280,11 +274,23 @@ static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) ...@@ -280,11 +274,23 @@ static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
dev_WARN_ONCE(&pnp_dev->dev, true, dev_WARN_ONCE(&pnp_dev->dev, true,
"Unexpected response (msg len %d).\n", "Unexpected response (msg len %d).\n",
msg->msg.data_len); msg->msg.data_len);
} else { goto out_comp;
}
/* response msg is an error msg */
msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
if (msg->recv_type == IPMI_RESPONSE_RECV_TYPE &&
msg->msg.data_len == 1) {
if (msg->msg.data[0] == IPMI_TIMEOUT_COMPLETION_CODE) {
dev_WARN_ONCE(&pnp_dev->dev, true,
"Unexpected response (timeout).\n");
tx_msg->msg_done = ACPI_IPMI_TIMEOUT;
}
goto out_comp;
}
tx_msg->rx_len = msg->msg.data_len; tx_msg->rx_len = msg->msg.data_len;
memcpy(tx_msg->data, msg->msg.data, tx_msg->rx_len); memcpy(tx_msg->data, msg->msg.data, tx_msg->rx_len);
tx_msg->msg_done = 1; tx_msg->msg_done = ACPI_IPMI_OK;
} out_comp:
complete(&tx_msg->tx_complete); complete(&tx_msg->tx_complete);
out_lock: out_lock:
spin_unlock_irqrestore(&ipmi_device->tx_msg_lock, flags); spin_unlock_irqrestore(&ipmi_device->tx_msg_lock, flags);
...@@ -392,7 +398,7 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address, ...@@ -392,7 +398,7 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address,
{ {
struct acpi_ipmi_msg *tx_msg; struct acpi_ipmi_msg *tx_msg;
struct acpi_ipmi_device *ipmi_device = handler_context; struct acpi_ipmi_device *ipmi_device = handler_context;
int err, rem_time; int err;
acpi_status status; acpi_status status;
unsigned long flags; unsigned long flags;
/* /*
...@@ -422,14 +428,13 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address, ...@@ -422,14 +428,13 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address,
&tx_msg->addr, &tx_msg->addr,
tx_msg->tx_msgid, tx_msg->tx_msgid,
&tx_msg->tx_message, &tx_msg->tx_message,
NULL, 0, 0, 0); NULL, 0, 0, IPMI_TIMEOUT);
if (err) { if (err) {
status = AE_ERROR; status = AE_ERROR;
goto out_list; goto out_list;
} }
rem_time = wait_for_completion_timeout(&tx_msg->tx_complete, wait_for_completion(&tx_msg->tx_complete);
IPMI_TIMEOUT); acpi_format_ipmi_response(tx_msg, value);
acpi_format_ipmi_response(tx_msg, value, rem_time);
status = AE_OK; status = AE_OK;
out_list: out_list:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册