> -----Original Message----- > From: Rafael J. Wysocki <rjw@xxxxxxxxxxxxx> > Sent: Wednesday, June 10, 2020 5:22 AM > To: Williams, Dan J <dan.j.williams@xxxxxxxxx> > Cc: Kaneda, Erik <erik.kaneda@xxxxxxxxx>; Wysocki, Rafael J > <rafael.j.wysocki@xxxxxxxxx>; Len Brown <lenb@xxxxxxxxxx>; Borislav > Petkov <bp@xxxxxxxxx>; Weiny, Ira <ira.weiny@xxxxxxxxx>; James Morse > <james.morse@xxxxxxx>; Myron Stowe <myron.stowe@xxxxxxxxxx>; > Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx>; linux- > kernel@xxxxxxxxxxxxxxx; linux-acpi@xxxxxxxxxxxxxxx; linux- > nvdimm@xxxxxxxxxxxx; Moore, Robert <robert.moore@xxxxxxxxx> > Subject: [RFT][PATCH 2/3] ACPICA: Remove unused memory mappings on > interpreter exit > > From: "Rafael J. Wysocki" <rafael.j.wysocki@xxxxxxxxx> > > For transient memory opregions that are created dynamically under > the namespace and interpreter mutexes and go away quickly, there > still is the problem that removing their memory mappings may take > significant time and so doing that while holding the mutexes should > be avoided. > > For example, unmapping a chunk of memory associated with a memory > opregion in Linux involves running synchronize_rcu_expedited() > which really should not be done with the namespace mutex held. > > To address that problem, notice that the unused memory mappings left > behind by the "dynamic" opregions that went away need not be unmapped > right away when the opregion is deactivated. Instead, they may be > unmapped when exiting the interpreter, after the namespace and > interpreter mutexes have been dropped (there's one more place dealing > with opregions in the debug code that can be treated analogously). > > Accordingly, change acpi_ev_system_memory_region_setup() to put > the unused mappings into a global list instead of unmapping them > right away and add acpi_ev_system_release_memory_mappings() to > be called when leaving the interpreter in order to unmap the > unused memory mappings in the global list (which is protected > by the namespace mutex). > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx> > --- > drivers/acpi/acpica/acevents.h | 2 ++ > drivers/acpi/acpica/dbtest.c | 3 ++ > drivers/acpi/acpica/evrgnini.c | 51 > ++++++++++++++++++++++++++++++++-- > drivers/acpi/acpica/exutils.c | 3 ++ > drivers/acpi/acpica/utxface.c | 23 +++++++++++++++ > include/acpi/acpixf.h | 1 + > 6 files changed, 80 insertions(+), 3 deletions(-) > > diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h > index 79f292687bd6..463eb9124765 100644 > --- a/drivers/acpi/acpica/acevents.h > +++ b/drivers/acpi/acpica/acevents.h > @@ -197,6 +197,8 @@ acpi_ev_execute_reg_method(union > acpi_operand_object *region_obj, u32 function); > /* > * evregini - Region initialization and setup > */ > +void acpi_ev_system_release_memory_mappings(void); > + > acpi_status > acpi_ev_system_memory_region_setup(acpi_handle handle, > u32 function, > diff --git a/drivers/acpi/acpica/dbtest.c b/drivers/acpi/acpica/dbtest.c > index 6db44a5ac786..7dac6dae5c48 100644 > --- a/drivers/acpi/acpica/dbtest.c > +++ b/drivers/acpi/acpica/dbtest.c > @@ -8,6 +8,7 @@ > #include <acpi/acpi.h> > #include "accommon.h" > #include "acdebug.h" > +#include "acevents.h" > #include "acnamesp.h" > #include "acpredef.h" > #include "acinterp.h" > @@ -768,6 +769,8 @@ acpi_db_test_field_unit_type(union > acpi_operand_object *obj_desc) > acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); > acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); > > + acpi_ev_system_release_memory_mappings(); > + > bit_length = obj_desc->common_field.bit_length; > byte_length = > ACPI_ROUND_BITS_UP_TO_BYTES(bit_length); > > diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c > index 48a5e6eaf9b9..946c4eef054d 100644 > --- a/drivers/acpi/acpica/evrgnini.c > +++ b/drivers/acpi/acpica/evrgnini.c > @@ -16,6 +16,52 @@ > #define _COMPONENT ACPI_EVENTS > ACPI_MODULE_NAME("evrgnini") > > +#ifdef ACPI_OS_MAP_MEMORY_FAST_PATH > +static struct acpi_mem_mapping *unused_memory_mappings; > + > +/********************************************************* > ********************** > + * > + * FUNCTION: acpi_ev_system_release_memory_mappings > + * > + * PARAMETERS: None > + * > + * RETURN: None > + * > + * DESCRIPTION: Release all of the unused memory mappings in the queue > + * under the interpreter mutex. > + * > + > ********************************************************** > ********************/ > +void acpi_ev_system_release_memory_mappings(void) > +{ > + struct acpi_mem_mapping *mapping; > + > + > ACPI_FUNCTION_TRACE(acpi_ev_system_release_memory_mappin > gs); > + > + acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); > + > + while (unused_memory_mappings) { > + mapping = unused_memory_mappings; > + unused_memory_mappings = mapping->next; > + > + acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); > + > + acpi_os_unmap_memory(mapping->logical_address, > mapping->length); acpi_os_unmap_memory calls synchronize_rcu_expedited(). I'm no RCU expert but the definition of this function states: * Although this is a great improvement over previous expedited * implementations, it is still unfriendly to real-time workloads, so is * thus not recommended for any sort of common-case code. In fact, if * you are using synchronize_rcu_expedited() in a loop, please restructure * your code to batch your updates, and then use a single synchronize_rcu() * instead. > + ACPI_FREE(mapping); > + > + acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); > + } > + > + acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); > + > + return_VOID; > +} > +#else /* !ACPI_OS_MAP_MEMORY_FAST_PATH */ > +void acpi_ev_system_release_memory_mappings(void) > +{ > + return_VOID; > +} > +#endif /* !ACPI_OS_MAP_MEMORY_FAST_PATH */ > + > > /********************************************************** > ********************* > * > * FUNCTION: acpi_ev_system_memory_region_setup > @@ -60,9 +106,8 @@ acpi_ev_system_memory_region_setup(acpi_handle > handle, > while (local_region_context->first_mapping) > { > mapping = local_region_context- > >first_mapping; > local_region_context->first_mapping > = mapping->next; > - acpi_os_unmap_memory(mapping- > >logical_address, > - mapping->length); > - ACPI_FREE(mapping); > + mapping->next = > unused_memory_mappings; > + unused_memory_mappings = > mapping; > } > #endif > } > diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c > index 8fefa6feac2f..516d67664392 100644 > --- a/drivers/acpi/acpica/exutils.c > +++ b/drivers/acpi/acpica/exutils.c > @@ -25,6 +25,7 @@ > > #include <acpi/acpi.h> > #include "accommon.h" > +#include "acevents.h" > #include "acinterp.h" > #include "amlcode.h" > > @@ -106,6 +107,8 @@ void acpi_ex_exit_interpreter(void) > "Could not release AML Interpreter mutex")); > } > > + acpi_ev_system_release_memory_mappings(); > + > return_VOID; > } > > diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c > index ca7c9f0144ef..d972696be846 100644 > --- a/drivers/acpi/acpica/utxface.c > +++ b/drivers/acpi/acpica/utxface.c > @@ -11,6 +11,7 @@ > > #include <acpi/acpi.h> > #include "accommon.h" > +#include "acevents.h" > #include "acdebug.h" > > #define _COMPONENT ACPI_UTILITIES > @@ -244,6 +245,28 @@ acpi_status acpi_purge_cached_objects(void) > > ACPI_EXPORT_SYMBOL(acpi_purge_cached_objects) > > +/********************************************************* > ******************** > + * > + * FUNCTION: acpi_release_unused_memory_mappings > + * > + * PARAMETERS: None > + * > + * RETURN: None > + * > + * DESCRIPTION: Remove memory mappings that are not used any more. > + * > + > ********************************************************** > ******************/ > +void acpi_release_unused_memory_mappings(void) > +{ > + ACPI_FUNCTION_TRACE(acpi_release_unused_memory_mappings); > + > + acpi_ev_system_release_memory_mappings(); > + > + return_VOID; > +} > + > +ACPI_EXPORT_SYMBOL(acpi_release_unused_memory_mappings) > + > > /********************************************************** > ******************* > * > * FUNCTION: acpi_install_interface > diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h > index 1dc8d262035b..8d2cc02257ed 100644 > --- a/include/acpi/acpixf.h > +++ b/include/acpi/acpixf.h > @@ -449,6 +449,7 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status > acpi_size length, > struct acpi_pld_info > **return_buffer)) > +ACPI_EXTERNAL_RETURN_VOID(void > acpi_release_unused_memory_mappings(void)) > > /* > * ACPI table load/unload interfaces > -- > 2.26.2 > > >