Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 352985
b: refs/heads/master
c: a93bc0c
h: refs/heads/master
i:
  352983: dc06543
v: v3
  • Loading branch information
Seiji Aguchi authored and Tony Luck committed Feb 12, 2013
1 parent 8a10e74 commit 3929187
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 7 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 81fa4e581d9283f7992a0d8c534bb141eb840a14
refs/heads/master: a93bc0c6e07ed9bac44700280e65e2945d864fd4
85 changes: 80 additions & 5 deletions trunk/drivers/firmware/efivars.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,13 @@ efivar_create_sysfs_entry(struct efivars *efivars,
efi_char16_t *variable_name,
efi_guid_t *vendor_guid);

/*
* Prototype for workqueue functions updating sysfs entry
*/

static void efivar_update_sysfs_entries(struct work_struct *);
static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries);

/* Return the number of unicode characters in data */
static unsigned long
utf16_strnlen(efi_char16_t *s, size_t maxlength)
Expand Down Expand Up @@ -1248,11 +1255,8 @@ static int efi_pstore_write(enum pstore_type_id type,

spin_unlock_irqrestore(&efivars->lock, flags);

if (size)
ret = efivar_create_sysfs_entry(efivars,
utf16_strsize(efi_name,
DUMP_NAME_LEN * 2),
efi_name, &vendor);
if (reason == KMSG_DUMP_OOPS)
schedule_work(&efivar_work);

*id = part;
return ret;
Expand Down Expand Up @@ -1496,6 +1500,75 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
return count;
}

static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor)
{
struct efivar_entry *entry, *n;
struct efivars *efivars = &__efivars;
unsigned long strsize1, strsize2;
bool found = false;

strsize1 = utf16_strsize(variable_name, 1024);
list_for_each_entry_safe(entry, n, &efivars->list, list) {
strsize2 = utf16_strsize(entry->var.VariableName, 1024);
if (strsize1 == strsize2 &&
!memcmp(variable_name, &(entry->var.VariableName),
strsize2) &&
!efi_guidcmp(entry->var.VendorGuid,
*vendor)) {
found = true;
break;
}
}
return found;
}

static void efivar_update_sysfs_entries(struct work_struct *work)
{
struct efivars *efivars = &__efivars;
efi_guid_t vendor;
efi_char16_t *variable_name;
unsigned long variable_name_size = 1024;
efi_status_t status = EFI_NOT_FOUND;
bool found;

/* Add new sysfs entries */
while (1) {
variable_name = kzalloc(variable_name_size, GFP_KERNEL);
if (!variable_name) {
pr_err("efivars: Memory allocation failed.\n");
return;
}

spin_lock_irq(&efivars->lock);
found = false;
while (1) {
variable_name_size = 1024;
status = efivars->ops->get_next_variable(
&variable_name_size,
variable_name,
&vendor);
if (status != EFI_SUCCESS) {
break;
} else {
if (!variable_is_present(variable_name,
&vendor)) {
found = true;
break;
}
}
}
spin_unlock_irq(&efivars->lock);

if (!found) {
kfree(variable_name);
break;
} else
efivar_create_sysfs_entry(efivars,
variable_name_size,
variable_name, &vendor);
}
}

/*
* Let's not leave out systab information that snuck into
* the efivars driver
Expand Down Expand Up @@ -1833,6 +1906,8 @@ efivars_init(void)
static void __exit
efivars_exit(void)
{
cancel_work_sync(&efivar_work);

if (efi_enabled) {
unregister_efivars(&__efivars);
kobject_put(efi_kobj);
Expand Down
3 changes: 2 additions & 1 deletion trunk/include/linux/efi.h
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,8 @@ struct efivars {
* 1) ->list - adds, removals, reads, writes
* 2) ops.[gs]et_variable() calls.
* It must not be held when creating sysfs entries or calling kmalloc.
* ops.get_next_variable() is only called from register_efivars(),
* ops.get_next_variable() is only called from register_efivars()
* or efivar_update_sysfs_entries(),
* which is protected by the BKL, so that path is safe.
*/
spinlock_t lock;
Expand Down

0 comments on commit 3929187

Please sign in to comment.