mirror of
https://github.com/acpica/acpica/
synced 2025-02-25 01:44:33 +03:00
Tables: Mechanism to handle AcpiGetTable()/AcpiPutTable() imbalance better
On linux, 2 ioremap() mechanisms are implemented for 2 stages: 1. During early boot, before memory manager is fully initialized. 2. For late boot and runtime, after memory manager is fully initialized. Maps mapped in the early stage cannot be used by late stage. So for early stage, linux invokes AcpiGetTable()/AcpiPutTable() APIs to free table mappings (means there is no imbalance), and for late stage, linux mostly only invokes AcpiGetTable() table API (means there are imbalances, and balances and imbalances co-exist). The original mechanism is designed to allow: 1. early stage balances; 2. late stage co-existence of balances/imbalances. But for the latter, it has a limitation, it doesn't allow balances to be implemented for users who can easily increment ValidationCount to its maximum value. Considering this case: 1. A program opens a sysfs table file 65535 times, it can increase ValidationCount and first increment causes the table to be mapped: ValidationCount = 65535 2. AML execution causes "Load" to be executed on the same table, this time it cannot increase ValidationCount, so ValidationCount remains: ValidationCount = 65535 3. The program closes sysfs table file 65535 times, it can decrease ValidationCount and the last decrement cause the table to be unmapped: ValidationCount = 0 4. AML code still accessing the loaded table, kernel crash can be observed. This is because the original mechanism is only prepared for late stage users that won't invoke AcpiPutTable() so often (means can only handle co-existence of balanced non-frequent AcpiPutTable() invocations and imbalanced AcpiGetTable() invocations), and cannot handle the co-existence of balanced frequent AcpiPutTable() invocations and imbalanced AcpiGetTable() invocations. To prevent that from happening, add a ValidationCount threashold. When it is reached, the ValidationCount can no longer be incremented/decremented to invalidate the table descriptor (means preventing table unmappings). Now the improved mechanism can handle co-existence of any balances/imbalances. Note that code added in AcpiTbPutTable() is actually a no-op but changes the warning message into a "warn once" one. Since all warning messages can only appear once for one table descriptor, it is safe now to add them back without worrying about log flooding. Lv Zheng. Signed-off-by: Lv Zheng <lv.zheng@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
b7ab82151e
commit
beb7833ef1
@ -559,10 +559,19 @@ AcpiTbGetTable (
|
||||
}
|
||||
}
|
||||
|
||||
TableDesc->ValidationCount++;
|
||||
if (TableDesc->ValidationCount == 0)
|
||||
if (TableDesc->ValidationCount < ACPI_MAX_TABLE_VALIDATIONS)
|
||||
{
|
||||
TableDesc->ValidationCount--;
|
||||
TableDesc->ValidationCount++;
|
||||
|
||||
/*
|
||||
* Detect ValidationCount overflows to ensure that the warning
|
||||
* message will only be printed once.
|
||||
*/
|
||||
if (TableDesc->ValidationCount >= ACPI_MAX_TABLE_VALIDATIONS)
|
||||
{
|
||||
ACPI_WARNING((AE_INFO,
|
||||
"Table %p, Validation count overflows\n", TableDesc));
|
||||
}
|
||||
}
|
||||
|
||||
*OutTable = TableDesc->Pointer;
|
||||
@ -593,14 +602,21 @@ AcpiTbPutTable (
|
||||
ACPI_FUNCTION_TRACE (AcpiTbPutTable);
|
||||
|
||||
|
||||
if (TableDesc->ValidationCount == 0)
|
||||
if (TableDesc->ValidationCount < ACPI_MAX_TABLE_VALIDATIONS)
|
||||
{
|
||||
ACPI_WARNING ((AE_INFO,
|
||||
"Table %p, Validation count is zero before decrement\n",
|
||||
TableDesc));
|
||||
return_VOID;
|
||||
TableDesc->ValidationCount--;
|
||||
|
||||
/*
|
||||
* Detect ValidationCount underflows to ensure that the warning
|
||||
* message will only be printed once.
|
||||
*/
|
||||
if (TableDesc->ValidationCount >= ACPI_MAX_TABLE_VALIDATIONS)
|
||||
{
|
||||
ACPI_WARNING ((AE_INFO,
|
||||
"Table %p, Validation count underflows\n", TableDesc));
|
||||
return_VOID;
|
||||
}
|
||||
}
|
||||
TableDesc->ValidationCount--;
|
||||
|
||||
if (TableDesc->ValidationCount == 0)
|
||||
{
|
||||
|
@ -517,6 +517,20 @@ typedef struct acpi_table_desc
|
||||
|
||||
} ACPI_TABLE_DESC;
|
||||
|
||||
/*
|
||||
* Maximum value of the ValidationCount field in ACPI_TABLE_DESC.
|
||||
* When reached, ValidationCount cannot be changed any more and the table will
|
||||
* be permanently regarded as validated.
|
||||
*
|
||||
* This is to prevent situations in which unbalanced table get/put operations
|
||||
* may cause premature table unmapping in the OS to happen.
|
||||
*
|
||||
* The maximum validation count can be defined to any value, but should be
|
||||
* greater than the maximum number of OS early stage mapping slots to avoid
|
||||
* leaking early stage table mappings to the late stage.
|
||||
*/
|
||||
#define ACPI_MAX_TABLE_VALIDATIONS ACPI_UINT16_MAX
|
||||
|
||||
/* Masks for Flags field above */
|
||||
|
||||
#define ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL (0) /* Virtual address, external maintained */
|
||||
|
Loading…
x
Reference in New Issue
Block a user