Merge branch 'next' into efi-next-merge
Conflicts: arch/x86/boot/compressed/eboot.c
This commit is contained in:
@@ -321,11 +321,11 @@ static unsigned long var_name_strnsize(efi_char16_t *variable_name,
|
||||
* Print a warning when duplicate EFI variables are encountered and
|
||||
* disable the sysfs workqueue since the firmware is buggy.
|
||||
*/
|
||||
static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid,
|
||||
static void dup_variable_bug(efi_char16_t *str16, efi_guid_t *vendor_guid,
|
||||
unsigned long len16)
|
||||
{
|
||||
size_t i, len8 = len16 / sizeof(efi_char16_t);
|
||||
char *s8;
|
||||
char *str8;
|
||||
|
||||
/*
|
||||
* Disable the workqueue since the algorithm it uses for
|
||||
@@ -334,16 +334,16 @@ static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid,
|
||||
*/
|
||||
efivar_wq_enabled = false;
|
||||
|
||||
s8 = kzalloc(len8, GFP_KERNEL);
|
||||
if (!s8)
|
||||
str8 = kzalloc(len8, GFP_KERNEL);
|
||||
if (!str8)
|
||||
return;
|
||||
|
||||
for (i = 0; i < len8; i++)
|
||||
s8[i] = s16[i];
|
||||
str8[i] = str16[i];
|
||||
|
||||
printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n",
|
||||
s8, vendor_guid);
|
||||
kfree(s8);
|
||||
str8, vendor_guid);
|
||||
kfree(str8);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -595,6 +595,39 @@ int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(efivar_entry_set);
|
||||
|
||||
/*
|
||||
* efivar_entry_set_nonblocking - call set_variable_nonblocking()
|
||||
*
|
||||
* This function is guaranteed to not block and is suitable for calling
|
||||
* from crash/panic handlers.
|
||||
*
|
||||
* Crucially, this function will not block if it cannot acquire
|
||||
* __efivars->lock. Instead, it returns -EBUSY.
|
||||
*/
|
||||
static int
|
||||
efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor,
|
||||
u32 attributes, unsigned long size, void *data)
|
||||
{
|
||||
const struct efivar_operations *ops = __efivars->ops;
|
||||
unsigned long flags;
|
||||
efi_status_t status;
|
||||
|
||||
if (!spin_trylock_irqsave(&__efivars->lock, flags))
|
||||
return -EBUSY;
|
||||
|
||||
status = check_var_size(attributes, size + ucs2_strsize(name, 1024));
|
||||
if (status != EFI_SUCCESS) {
|
||||
spin_unlock_irqrestore(&__efivars->lock, flags);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
status = ops->set_variable_nonblocking(name, &vendor, attributes,
|
||||
size, data);
|
||||
|
||||
spin_unlock_irqrestore(&__efivars->lock, flags);
|
||||
return efi_status_to_err(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* efivar_entry_set_safe - call set_variable() if enough space in firmware
|
||||
* @name: buffer containing the variable name
|
||||
@@ -622,6 +655,20 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
|
||||
if (!ops->query_variable_store)
|
||||
return -ENOSYS;
|
||||
|
||||
/*
|
||||
* If the EFI variable backend provides a non-blocking
|
||||
* ->set_variable() operation and we're in a context where we
|
||||
* cannot block, then we need to use it to avoid live-locks,
|
||||
* since the implication is that the regular ->set_variable()
|
||||
* will block.
|
||||
*
|
||||
* If no ->set_variable_nonblocking() is provided then
|
||||
* ->set_variable() is assumed to be non-blocking.
|
||||
*/
|
||||
if (!block && ops->set_variable_nonblocking)
|
||||
return efivar_entry_set_nonblocking(name, vendor, attributes,
|
||||
size, data);
|
||||
|
||||
if (!block) {
|
||||
if (!spin_trylock_irqsave(&__efivars->lock, flags))
|
||||
return -EBUSY;
|
||||
|
||||
Reference in New Issue
Block a user