efi: Provide a non-blocking SetVariable() operation
There are some circumstances that call for trying to write an EFI variable in a non-blocking way. One such scenario is when writing pstore data in efi_pstore_write() via the pstore_dump() kdump callback. Now that we have an EFI runtime spinlock we need a way of aborting if there is contention instead of spinning, since when writing pstore data from the kdump callback, the runtime lock may already be held by the CPU that's running the callback if we crashed in the middle of an EFI variable operation. The situation is sufficiently special that a new EFI variable operation is warranted. Introduce ->set_variable_nonblocking() for this use case. It is an optional EFI backend operation, and need only be implemented by those backends that usually acquire locks to serialize access to EFI variables, as is the case for virt_efi_set_variable() where we now grab the EFI runtime spinlock. Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ingo Molnar <mingo@kernel.org> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Matthew Garrett <mjg59@srcf.ucam.org> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
This commit is contained in:
@@ -503,6 +503,10 @@ typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char
|
||||
typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor,
|
||||
u32 attr, unsigned long data_size,
|
||||
void *data);
|
||||
typedef efi_status_t
|
||||
efi_set_variable_nonblocking_t(efi_char16_t *name, efi_guid_t *vendor,
|
||||
u32 attr, unsigned long data_size, void *data);
|
||||
|
||||
typedef efi_status_t efi_get_next_high_mono_count_t (u32 *count);
|
||||
typedef void efi_reset_system_t (int reset_type, efi_status_t status,
|
||||
unsigned long data_size, efi_char16_t *data);
|
||||
@@ -822,6 +826,7 @@ extern struct efi {
|
||||
efi_get_variable_t *get_variable;
|
||||
efi_get_next_variable_t *get_next_variable;
|
||||
efi_set_variable_t *set_variable;
|
||||
efi_set_variable_nonblocking_t *set_variable_nonblocking;
|
||||
efi_query_variable_info_t *query_variable_info;
|
||||
efi_update_capsule_t *update_capsule;
|
||||
efi_query_capsule_caps_t *query_capsule_caps;
|
||||
@@ -1042,6 +1047,7 @@ struct efivar_operations {
|
||||
efi_get_variable_t *get_variable;
|
||||
efi_get_next_variable_t *get_next_variable;
|
||||
efi_set_variable_t *set_variable;
|
||||
efi_set_variable_nonblocking_t *set_variable_nonblocking;
|
||||
efi_query_variable_store_t *query_variable_store;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user