aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/firmware/efivars.c48
1 files changed, 47 insertions, 1 deletions
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index 1e9d9b9d7a12..d64661fda4fd 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -170,6 +170,7 @@ efivar_create_sysfs_entry(struct efivars *efivars,
170 170
171static void efivar_update_sysfs_entries(struct work_struct *); 171static void efivar_update_sysfs_entries(struct work_struct *);
172static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries); 172static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries);
173static bool efivar_wq_enabled = true;
173 174
174/* Return the number of unicode characters in data */ 175/* Return the number of unicode characters in data */
175static unsigned long 176static unsigned long
@@ -1444,7 +1445,7 @@ static int efi_pstore_write(enum pstore_type_id type,
1444 1445
1445 spin_unlock_irqrestore(&efivars->lock, flags); 1446 spin_unlock_irqrestore(&efivars->lock, flags);
1446 1447
1447 if (reason == KMSG_DUMP_OOPS) 1448 if (reason == KMSG_DUMP_OOPS && efivar_wq_enabled)
1448 schedule_work(&efivar_work); 1449 schedule_work(&efivar_work);
1449 1450
1450 *id = part; 1451 *id = part;
@@ -1975,6 +1976,35 @@ void unregister_efivars(struct efivars *efivars)
1975} 1976}
1976EXPORT_SYMBOL_GPL(unregister_efivars); 1977EXPORT_SYMBOL_GPL(unregister_efivars);
1977 1978
1979/*
1980 * Print a warning when duplicate EFI variables are encountered and
1981 * disable the sysfs workqueue since the firmware is buggy.
1982 */
1983static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid,
1984 unsigned long len16)
1985{
1986 size_t i, len8 = len16 / sizeof(efi_char16_t);
1987 char *s8;
1988
1989 /*
1990 * Disable the workqueue since the algorithm it uses for
1991 * detecting new variables won't work with this buggy
1992 * implementation of GetNextVariableName().
1993 */
1994 efivar_wq_enabled = false;
1995
1996 s8 = kzalloc(len8, GFP_KERNEL);
1997 if (!s8)
1998 return;
1999
2000 for (i = 0; i < len8; i++)
2001 s8[i] = s16[i];
2002
2003 printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n",
2004 s8, vendor_guid);
2005 kfree(s8);
2006}
2007
1978int register_efivars(struct efivars *efivars, 2008int register_efivars(struct efivars *efivars,
1979 const struct efivar_operations *ops, 2009 const struct efivar_operations *ops,
1980 struct kobject *parent_kobj) 2010 struct kobject *parent_kobj)
@@ -2025,6 +2055,22 @@ int register_efivars(struct efivars *efivars,
2025 case EFI_SUCCESS: 2055 case EFI_SUCCESS:
2026 variable_name_size = var_name_strnsize(variable_name, 2056 variable_name_size = var_name_strnsize(variable_name,
2027 variable_name_size); 2057 variable_name_size);
2058
2059 /*
2060 * Some firmware implementations return the
2061 * same variable name on multiple calls to
2062 * get_next_variable(). Terminate the loop
2063 * immediately as there is no guarantee that
2064 * we'll ever see a different variable name,
2065 * and may end up looping here forever.
2066 */
2067 if (variable_is_present(variable_name, &vendor_guid)) {
2068 dup_variable_bug(variable_name, &vendor_guid,
2069 variable_name_size);
2070 status = EFI_NOT_FOUND;
2071 break;
2072 }
2073
2028 efivar_create_sysfs_entry(efivars, 2074 efivar_create_sysfs_entry(efivars,
2029 variable_name_size, 2075 variable_name_size,
2030 variable_name, 2076 variable_name,