[PATCH] efi: vars: commonize the 512-byte name buffer quirk
Jonggeun Park <[email protected]>
| Newsgroups | org.kernel.vger.linux-efi,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Some old UEFI implementations reject GetNextVariableName() calls with a name buffer size larger than 512 bytes. Both efivar_init() and efi_pstore_read() open-code the same workaround of resetting the size to 512 on every iteration. Introduce efivar_get_next_variable_safe() which keeps this quirk in a single place, resolving the TODO in efi-pstore.c. No functional change intended. Signed-off-by: Jonggeun Park <[email protected]> --- drivers/firmware/efi/efi-pstore.c | 16 +++++----------- drivers/firmware/efi/vars.c | 21 +++++++++++++++++++++ fs/efivarfs/vars.c | 4 +--- include/linux/efi.h | 4 ++++ 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index a5db3534f..a135d6e2f 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -164,16 +164,6 @@ static ssize_t efi_pstore_read(struct pstore_record *record) efi_status_t status; for (;;) { - /* - * A small set of old UEFI implementations reject sizes - * above a certain threshold, the lowest seen in the wild - * is 512. - * - * TODO: Commonize with the iteration implementation in - * fs/efivarfs to keep all the quirks in one place. - */ - varname_size = 512; - /* * If this is the first read() call in the pstore enumeration, * varname will be the empty string, and the GetNextVariable() @@ -185,8 +175,12 @@ static ssize_t efi_pstore_read(struct pstore_record *record) * store varname in record->psi->data. Given that we only * enumerate variables with the efi-pstore GUID, there is no * need to record the guid return value. + * + * The 512-byte name buffer quirk is handled inside + * efivar_get_next_variable_safe(). */ - status = efivar_get_next_variable(&varname_size, varname, &guid); + status = efivar_get_next_variable_safe(&varname_size, varname, + &guid); if (status == EFI_NOT_FOUND) return 0; diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index 3700e9869..8e69f3632 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c @@ -265,3 +265,24 @@ efi_status_t efivar_query_variable_info(u32 attr, remaining_space, max_variable_size); } EXPORT_SYMBOL_NS_GPL(efivar_query_variable_info, "EFIVAR"); + +/* + * efivar_get_next_variable_safe() - enumerate the next name/vendor pair + * + * Wrapper around efivar_get_next_variable() that keeps the 512-byte name + * buffer quirk in one place. Some old UEFI implementations reject name buffer + * sizes larger than 512 bytes (the lowest seen in the wild), so this always + * requests 512 bytes; callers must provide a buffer of at least that size. + * + * Must be called with efivars_lock held. + */ +efi_status_t efivar_get_next_variable_safe(unsigned long *name_size, + efi_char16_t *name, + efi_guid_t *vendor) +{ + BUILD_BUG_ON(EFI_VAR_NAME_LEN < 512); + *name_size = 512; + + return efivar_get_next_variable(name_size, name, vendor); +} +EXPORT_SYMBOL_NS_GPL(efivar_get_next_variable_safe, "EFIVAR"); diff --git a/fs/efivarfs/vars.c b/fs/efivarfs/vars.c index 6833c3d24..ee55a26cb 100644 --- a/fs/efivarfs/vars.c +++ b/fs/efivarfs/vars.c @@ -398,10 +398,8 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *), */ do { - variable_name_size = 512; - BUILD_BUG_ON(EFI_VAR_NAME_LEN < 512); - status = efivar_get_next_variable(&variable_name_size, + status = efivar_get_next_variable_safe(&variable_name_size, variable_name, &vendor_guid); switch (status) { diff --git a/include/linux/efi.h b/include/linux/efi.h index ccbc35479..f36505aa0 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1076,6 +1076,10 @@ efi_status_t efivar_get_variable(efi_char16_t *name, efi_guid_t *vendor, efi_status_t efivar_get_next_variable(unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor); +efi_status_t efivar_get_next_variable_safe(unsigned long *name_size, + efi_char16_t *name, + efi_guid_t *vendor); + efi_status_t efivar_set_variable_locked(efi_char16_t *name, efi_guid_t *vendor, u32 attr, unsigned long data_size, void *data, bool nonblocking); -- 2.43.0