aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2013-03-07 06:59:14 -0500
committerMatt Fleming <matt.fleming@intel.com>2013-03-21 08:43:46 -0400
commite971318bbed610e28bb3fde9d548e6aaf0a6b02e (patch)
tree244682af28ef6c7a6b5719c0ad5c493b446e7f85 /drivers/firmware
parentec50bd32f1672d38ddce10fb1841cbfda89cfe9a (diff)
efivars: Handle duplicate names from get_next_variable()
Some firmware exhibits a bug where the same VariableName and VendorGuid values are returned on multiple invocations of GetNextVariableName(). See, https://bugzilla.kernel.org/show_bug.cgi?id=47631 As a consequence of such a bug, Andre reports hitting the following WARN_ON() in the sysfs code after updating the BIOS on his, "Gigabyte Technology Co., Ltd. To be filled by O.E.M./Z77X-UD3H, BIOS F19e 11/21/2012)" machine, [ 0.581554] EFI Variables Facility v0.08 2004-May-17 [ 0.584914] ------------[ cut here ]------------ [ 0.585639] WARNING: at /home/andre/linux/fs/sysfs/dir.c:536 sysfs_add_one+0xd4/0x100() [ 0.586381] Hardware name: To be filled by O.E.M. [ 0.587123] sysfs: cannot create duplicate filename '/firmware/efi/vars/SbAslBufferPtrVar-01f33c25-764d-43ea-aeea-6b5a41f3f3e8' [ 0.588694] Modules linked in: [ 0.589484] Pid: 1, comm: swapper/0 Not tainted 3.8.0+ #7 [ 0.590280] Call Trace: [ 0.591066] [<ffffffff81208954>] ? sysfs_add_one+0xd4/0x100 [ 0.591861] [<ffffffff810587bf>] warn_slowpath_common+0x7f/0xc0 [ 0.592650] [<ffffffff810588bc>] warn_slowpath_fmt+0x4c/0x50 [ 0.593429] [<ffffffff8134dd85>] ? strlcat+0x65/0x80 [ 0.594203] [<ffffffff81208954>] sysfs_add_one+0xd4/0x100 [ 0.594979] [<ffffffff81208b78>] create_dir+0x78/0xd0 [ 0.595753] [<ffffffff81208ec6>] sysfs_create_dir+0x86/0xe0 [ 0.596532] [<ffffffff81347e4c>] kobject_add_internal+0x9c/0x220 [ 0.597310] [<ffffffff81348307>] kobject_init_and_add+0x67/0x90 [ 0.598083] [<ffffffff81584a71>] ? efivar_create_sysfs_entry+0x61/0x1c0 [ 0.598859] [<ffffffff81584b2b>] efivar_create_sysfs_entry+0x11b/0x1c0 [ 0.599631] [<ffffffff8158517e>] register_efivars+0xde/0x420 [ 0.600395] [<ffffffff81d430a7>] ? edd_init+0x2f5/0x2f5 [ 0.601150] [<ffffffff81d4315f>] efivars_init+0xb8/0x104 [ 0.601903] [<ffffffff8100215a>] do_one_initcall+0x12a/0x180 [ 0.602659] [<ffffffff81d05d80>] kernel_init_freeable+0x13e/0x1c6 [ 0.603418] [<ffffffff81d05586>] ? loglevel+0x31/0x31 [ 0.604183] [<ffffffff816a6530>] ? rest_init+0x80/0x80 [ 0.604936] [<ffffffff816a653e>] kernel_init+0xe/0xf0 [ 0.605681] [<ffffffff816ce7ec>] ret_from_fork+0x7c/0xb0 [ 0.606414] [<ffffffff816a6530>] ? rest_init+0x80/0x80 [ 0.607143] ---[ end trace 1609741ab737eb29 ]--- There's not much we can do to work around and keep traversing the variable list once we hit this firmware bug. Our only solution is to terminate the loop because, as Lingzhu reports, some machines get stuck when they encounter duplicate names, > I had an IBM System x3100 M4 and x3850 X5 on which kernel would > get stuck in infinite loop creating duplicate sysfs files because, > for some reason, there are several duplicate boot entries in nvram > getting GetNextVariableName into a circle of iteration (with > period > 2). Also disable the workqueue, as efivar_update_sysfs_entries() uses GetNextVariableName() to figure out which variables have been created since the last iteration. That algorithm isn't going to work if GetNextVariableName() returns duplicates. Note that we don't disable EFI variable creation completely on the affected machines, it's just that any pstore dump-* files won't appear in sysfs until the next boot. Reported-by: Andre Heider <a.heider@gmail.com> Reported-by: Lingzhu Xiang <lxiang@redhat.com> Tested-by: Lingzhu Xiang <lxiang@redhat.com> Cc: Seiji Aguchi <seiji.aguchi@hds.com> Cc: <stable@vger.kernel.org> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Diffstat (limited to 'drivers/firmware')
-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,