summaryrefslogtreecommitdiff
path: root/drivers/firmware/efivars.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware/efivars.c')
-rw-r--r--drivers/firmware/efivars.c501
1 files changed, 119 insertions, 382 deletions
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index b07cb37..f5596db 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -79,7 +79,6 @@
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/pstore.h>
-#include <linux/ctype.h>
#include <linux/fs.h>
#include <linux/ramfs.h>
@@ -103,11 +102,6 @@ MODULE_VERSION(EFIVARS_VERSION);
*/
#define GUID_LEN 36
-static bool efivars_pstore_disable =
- IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE);
-
-module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644);
-
/*
* The maximum size of VariableName + Data = 1024
* Therefore, it's reasonable to save that much
@@ -411,11 +405,10 @@ static efi_status_t
get_var_data(struct efivars *efivars, struct efi_variable *var)
{
efi_status_t status;
- unsigned long flags;
- spin_lock_irqsave(&efivars->lock, flags);
+ spin_lock(&efivars->lock);
status = get_var_data_locked(efivars, var);
- spin_unlock_irqrestore(&efivars->lock, flags);
+ spin_unlock(&efivars->lock);
if (status != EFI_SUCCESS) {
printk(KERN_WARNING "efivars: get_variable() failed 0x%lx!\n",
@@ -424,44 +417,6 @@ get_var_data(struct efivars *efivars, struct efi_variable *var)
return status;
}
-static efi_status_t
-check_var_size_locked(struct efivars *efivars, u32 attributes,
- unsigned long size)
-{
- u64 storage_size, remaining_size, max_size;
- efi_status_t status;
- const struct efivar_operations *fops = efivars->ops;
-
- if (!efivars->ops->query_variable_info)
- return EFI_UNSUPPORTED;
-
- status = fops->query_variable_info(attributes, &storage_size,
- &remaining_size, &max_size);
-
- if (status != EFI_SUCCESS)
- return status;
-
- if (!storage_size || size > remaining_size || size > max_size ||
- (remaining_size - size) < (storage_size / 2))
- return EFI_OUT_OF_RESOURCES;
-
- return status;
-}
-
-
-static efi_status_t
-check_var_size(struct efivars *efivars, u32 attributes, unsigned long size)
-{
- efi_status_t status;
- unsigned long flags;
-
- spin_lock_irqsave(&efivars->lock, flags);
- status = check_var_size_locked(efivars, attributes, size);
- spin_unlock_irqrestore(&efivars->lock, flags);
-
- return status;
-}
-
static ssize_t
efivar_guid_read(struct efivar_entry *entry, char *buf)
{
@@ -582,19 +537,14 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
return -EINVAL;
}
- spin_lock_irq(&efivars->lock);
-
- status = check_var_size_locked(efivars, new_var->Attributes,
- new_var->DataSize + utf16_strsize(new_var->VariableName, 1024));
-
- if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED)
- status = efivars->ops->set_variable(new_var->VariableName,
- &new_var->VendorGuid,
- new_var->Attributes,
- new_var->DataSize,
- new_var->Data);
+ spin_lock(&efivars->lock);
+ status = efivars->ops->set_variable(new_var->VariableName,
+ &new_var->VendorGuid,
+ new_var->Attributes,
+ new_var->DataSize,
+ new_var->Data);
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
if (status != EFI_SUCCESS) {
printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
@@ -743,7 +693,8 @@ static ssize_t efivarfs_file_write(struct file *file,
u32 attributes;
struct inode *inode = file->f_mapping->host;
unsigned long datasize = count - sizeof(attributes);
- unsigned long newdatasize, varsize;
+ unsigned long newdatasize;
+ u64 storage_size, remaining_size, max_size;
ssize_t bytes = 0;
if (count < sizeof(attributes))
@@ -762,18 +713,28 @@ static ssize_t efivarfs_file_write(struct file *file,
* amounts of memory. Pick a default size of 64K if
* QueryVariableInfo() isn't supported by the firmware.
*/
+ spin_lock(&efivars->lock);
+
+ if (!efivars->ops->query_variable_info)
+ status = EFI_UNSUPPORTED;
+ else {
+ const struct efivar_operations *fops = efivars->ops;
+ status = fops->query_variable_info(attributes, &storage_size,
+ &remaining_size, &max_size);
+ }
- varsize = datasize + utf16_strsize(var->var.VariableName, 1024);
- status = check_var_size(efivars, attributes, varsize);
+ spin_unlock(&efivars->lock);
if (status != EFI_SUCCESS) {
if (status != EFI_UNSUPPORTED)
return efi_status_to_err(status);
- if (datasize > 65536)
- return -ENOSPC;
+ remaining_size = 65536;
}
+ if (datasize > remaining_size)
+ return -ENOSPC;
+
data = kmalloc(datasize, GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -793,20 +754,7 @@ static ssize_t efivarfs_file_write(struct file *file,
* set_variable call, and removal of the variable from the efivars
* list (in the case of an authenticated delete).
*/
- spin_lock_irq(&efivars->lock);
-
- /*
- * Ensure that the available space hasn't shrunk below the safe level
- */
-
- status = check_var_size_locked(efivars, attributes, varsize);
-
- if (status != EFI_SUCCESS && status != EFI_UNSUPPORTED) {
- spin_unlock_irq(&efivars->lock);
- kfree(data);
-
- return efi_status_to_err(status);
- }
+ spin_lock(&efivars->lock);
status = efivars->ops->set_variable(var->var.VariableName,
&var->var.VendorGuid,
@@ -814,7 +762,7 @@ static ssize_t efivarfs_file_write(struct file *file,
data);
if (status != EFI_SUCCESS) {
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
kfree(data);
return efi_status_to_err(status);
@@ -835,21 +783,21 @@ static ssize_t efivarfs_file_write(struct file *file,
NULL);
if (status == EFI_BUFFER_TOO_SMALL) {
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
mutex_lock(&inode->i_mutex);
i_size_write(inode, newdatasize + sizeof(attributes));
mutex_unlock(&inode->i_mutex);
} else if (status == EFI_NOT_FOUND) {
list_del(&var->list);
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
efivar_unregister(var);
drop_nlink(inode);
d_delete(file->f_dentry);
dput(file->f_dentry);
} else {
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
pr_warn("efivarfs: inconsistent EFI variable implementation? "
"status = %lx\n", status);
}
@@ -871,11 +819,11 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
void *data;
ssize_t size = 0;
- spin_lock_irq(&efivars->lock);
+ spin_lock(&efivars->lock);
status = efivars->ops->get_variable(var->var.VariableName,
&var->var.VendorGuid,
&attributes, &datasize, NULL);
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
if (status != EFI_BUFFER_TOO_SMALL)
return efi_status_to_err(status);
@@ -885,12 +833,12 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
if (!data)
return -ENOMEM;
- spin_lock_irq(&efivars->lock);
+ spin_lock(&efivars->lock);
status = efivars->ops->get_variable(var->var.VariableName,
&var->var.VendorGuid,
&attributes, &datasize,
(data + sizeof(attributes)));
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
if (status != EFI_SUCCESS) {
size = efi_status_to_err(status);
@@ -952,48 +900,6 @@ static struct inode *efivarfs_get_inode(struct super_block *sb,
return inode;
}
-/*
- * Return true if 'str' is a valid efivarfs filename of the form,
- *
- * VariableName-12345678-1234-1234-1234-1234567891bc
- */
-static bool efivarfs_valid_name(const char *str, int len)
-{
- static const char dashes[GUID_LEN] = {
- [8] = 1, [13] = 1, [18] = 1, [23] = 1
- };
- const char *s = str + len - GUID_LEN;
- int i;
-
- /*
- * We need a GUID, plus at least one letter for the variable name,
- * plus the '-' separator
- */
- if (len < GUID_LEN + 2)
- return false;
-
- /* GUID must be preceded by a '-' */
- if (*(s - 1) != '-')
- return false;
-
- /*
- * Validate that 's' is of the correct format, e.g.
- *
- * 12345678-1234-1234-1234-123456789abc
- */
- for (i = 0; i < GUID_LEN; i++) {
- if (dashes[i]) {
- if (*s++ != '-')
- return false;
- } else {
- if (!isxdigit(*s++))
- return false;
- }
- }
-
- return true;
-}
-
static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid)
{
guid->b[0] = hex_to_bin(str[6]) << 4 | hex_to_bin(str[7]);
@@ -1022,7 +928,11 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
struct efivar_entry *var;
int namelen, i = 0, err = 0;
- if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len))
+ /*
+ * We need a GUID, plus at least one letter for the variable name,
+ * plus the '-' separator
+ */
+ if (dentry->d_name.len < GUID_LEN + 2)
return -EINVAL;
inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0);
@@ -1056,9 +966,9 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
goto out;
kobject_uevent(&var->kobj, KOBJ_ADD);
- spin_lock_irq(&efivars->lock);
+ spin_lock(&efivars->lock);
list_add(&var->list, &efivars->list);
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
d_instantiate(dentry, inode);
dget(dentry);
out:
@@ -1075,7 +985,7 @@ static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
struct efivars *efivars = var->efivars;
efi_status_t status;
- spin_lock_irq(&efivars->lock);
+ spin_lock(&efivars->lock);
status = efivars->ops->set_variable(var->var.VariableName,
&var->var.VendorGuid,
@@ -1083,102 +993,17 @@ static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
if (status == EFI_SUCCESS || status == EFI_NOT_FOUND) {
list_del(&var->list);
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
efivar_unregister(var);
drop_nlink(dentry->d_inode);
dput(dentry);
return 0;
}
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
return -EINVAL;
};
-/*
- * Compare two efivarfs file names.
- *
- * An efivarfs filename is composed of two parts,
- *
- * 1. A case-sensitive variable name
- * 2. A case-insensitive GUID
- *
- * So we need to perform a case-sensitive match on part 1 and a
- * case-insensitive match on part 2.
- */
-static int efivarfs_d_compare(const struct dentry *parent, const struct inode *pinode,
- const struct dentry *dentry, const struct inode *inode,
- unsigned int len, const char *str,
- const struct qstr *name)
-{
- int guid = len - GUID_LEN;
-
- if (name->len != len)
- return 1;
-
- /* Case-sensitive compare for the variable name */
- if (memcmp(str, name->name, guid))
- return 1;
-
- /* Case-insensitive compare for the GUID */
- return strncasecmp(name->name + guid, str + guid, GUID_LEN);
-}
-
-static int efivarfs_d_hash(const struct dentry *dentry,
- const struct inode *inode, struct qstr *qstr)
-{
- unsigned long hash = init_name_hash();
- const unsigned char *s = qstr->name;
- unsigned int len = qstr->len;
-
- if (!efivarfs_valid_name(s, len))
- return -EINVAL;
-
- while (len-- > GUID_LEN)
- hash = partial_name_hash(*s++, hash);
-
- /* GUID is case-insensitive. */
- while (len--)
- hash = partial_name_hash(tolower(*s++), hash);
-
- qstr->hash = end_name_hash(hash);
- return 0;
-}
-
-/*
- * Retaining negative dentries for an in-memory filesystem just wastes
- * memory and lookup time: arrange for them to be deleted immediately.
- */
-static int efivarfs_delete_dentry(const struct dentry *dentry)
-{
- return 1;
-}
-
-static struct dentry_operations efivarfs_d_ops = {
- .d_compare = efivarfs_d_compare,
- .d_hash = efivarfs_d_hash,
- .d_delete = efivarfs_delete_dentry,
-};
-
-static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
-{
- struct dentry *d;
- struct qstr q;
- int err;
-
- q.name = name;
- q.len = strlen(name);
-
- err = efivarfs_d_hash(NULL, NULL, &q);
- if (err)
- return ERR_PTR(err);
-
- d = d_alloc(parent, &q);
- if (d)
- return d;
-
- return ERR_PTR(-ENOMEM);
-}
-
static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode = NULL;
@@ -1186,7 +1011,6 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
struct efivar_entry *entry, *n;
struct efivars *efivars = &__efivars;
char *name;
- int err = -ENOMEM;
efivarfs_sb = sb;
@@ -1195,7 +1019,6 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = EFIVARFS_MAGIC;
sb->s_op = &efivarfs_ops;
- sb->s_d_op = &efivarfs_d_ops;
sb->s_time_gran = 1;
inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0);
@@ -1236,22 +1059,20 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
if (!inode)
goto fail_name;
- dentry = efivarfs_alloc_dentry(root, name);
- if (IS_ERR(dentry)) {
- err = PTR_ERR(dentry);
+ dentry = d_alloc_name(root, name);
+ if (!dentry)
goto fail_inode;
- }
/* copied by the above to local storage in the dentry. */
kfree(name);
- spin_lock_irq(&efivars->lock);
+ spin_lock(&efivars->lock);
efivars->ops->get_variable(entry->var.VariableName,
&entry->var.VendorGuid,
&entry->var.Attributes,
&size,
NULL);
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
mutex_lock(&inode->i_mutex);
inode->i_private = entry;
@@ -1267,7 +1088,7 @@ fail_inode:
fail_name:
kfree(name);
fail:
- return err;
+ return -ENOMEM;
}
static struct dentry *efivarfs_mount(struct file_system_type *fs_type,
@@ -1288,31 +1109,21 @@ static struct file_system_type efivarfs_type = {
.kill_sb = efivarfs_kill_sb,
};
-/*
- * Handle negative dentry.
- */
-static struct dentry *efivarfs_lookup(struct inode *dir, struct dentry *dentry,
- unsigned int flags)
-{
- if (dentry->d_name.len > NAME_MAX)
- return ERR_PTR(-ENAMETOOLONG);
- d_add(dentry, NULL);
- return NULL;
-}
-
static const struct inode_operations efivarfs_dir_inode_operations = {
- .lookup = efivarfs_lookup,
+ .lookup = simple_lookup,
.unlink = efivarfs_unlink,
.create = efivarfs_create,
};
-#ifdef CONFIG_EFI_VARS_PSTORE
+static struct pstore_info efi_pstore_info;
+
+#ifdef CONFIG_PSTORE
static int efi_pstore_open(struct pstore_info *psi)
{
struct efivars *efivars = psi->data;
- spin_lock_irq(&efivars->lock);
+ spin_lock(&efivars->lock);
efivars->walk_entry = list_first_entry(&efivars->list,
struct efivar_entry, list);
return 0;
@@ -1322,7 +1133,7 @@ static int efi_pstore_close(struct pstore_info *psi)
{
struct efivars *efivars = psi->data;
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
return 0;
}
@@ -1396,22 +1207,22 @@ static int efi_pstore_write(enum pstore_type_id type,
efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
struct efivars *efivars = psi->data;
int i, ret = 0;
+ u64 storage_space, remaining_space, max_variable_size;
efi_status_t status = EFI_NOT_FOUND;
- unsigned long flags;
- spin_lock_irqsave(&efivars->lock, flags);
+ spin_lock(&efivars->lock);
/*
* Check if there is a space enough to log.
* size: a size of logging data
* DUMP_NAME_LEN * 2: a maximum size of variable name
*/
-
- status = check_var_size_locked(efivars, PSTORE_EFI_ATTRIBUTES,
- size + DUMP_NAME_LEN * 2);
-
- if (status) {
- spin_unlock_irqrestore(&efivars->lock, flags);
+ status = efivars->ops->query_variable_info(PSTORE_EFI_ATTRIBUTES,
+ &storage_space,
+ &remaining_space,
+ &max_variable_size);
+ if (status || remaining_space < size + DUMP_NAME_LEN * 2) {
+ spin_unlock(&efivars->lock);
*id = part;
return -ENOSPC;
}
@@ -1425,7 +1236,7 @@ static int efi_pstore_write(enum pstore_type_id type,
efivars->ops->set_variable(efi_name, &vendor, PSTORE_EFI_ATTRIBUTES,
size, psi->buf);
- spin_unlock_irqrestore(&efivars->lock, flags);
+ spin_unlock(&efivars->lock);
if (size)
ret = efivar_create_sysfs_entry(efivars,
@@ -1452,7 +1263,7 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count,
time.tv_sec);
- spin_lock_irq(&efivars->lock);
+ spin_lock(&efivars->lock);
for (i = 0; i < DUMP_NAME_LEN; i++)
efi_name[i] = name[i];
@@ -1496,13 +1307,45 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
if (found)
list_del(&found->list);
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
if (found)
efivar_unregister(found);
return 0;
}
+#else
+static int efi_pstore_open(struct pstore_info *psi)
+{
+ return 0;
+}
+
+static int efi_pstore_close(struct pstore_info *psi)
+{
+ return 0;
+}
+
+static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, int *count,
+ struct timespec *timespec,
+ char **buf, struct pstore_info *psi)
+{
+ return -1;
+}
+
+static int efi_pstore_write(enum pstore_type_id type,
+ enum kmsg_dump_reason reason, u64 *id,
+ unsigned int part, int count, size_t size,
+ struct pstore_info *psi)
+{
+ return 0;
+}
+
+static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
+ struct timespec time, struct pstore_info *psi)
+{
+ return 0;
+}
+#endif
static struct pstore_info efi_pstore_info = {
.owner = THIS_MODULE,
@@ -1514,24 +1357,6 @@ static struct pstore_info efi_pstore_info = {
.erase = efi_pstore_erase,
};
-static void efivar_pstore_register(struct efivars *efivars)
-{
- efivars->efi_pstore_info = efi_pstore_info;
- efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL);
- if (efivars->efi_pstore_info.buf) {
- efivars->efi_pstore_info.bufsize = 1024;
- efivars->efi_pstore_info.data = efivars;
- spin_lock_init(&efivars->efi_pstore_info.buf_lock);
- pstore_register(&efivars->efi_pstore_info);
- }
-}
-#else
-static void efivar_pstore_register(struct efivars *efivars)
-{
- return;
-}
-#endif
-
static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t count)
@@ -1552,7 +1377,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
return -EINVAL;
}
- spin_lock_irq(&efivars->lock);
+ spin_lock(&efivars->lock);
/*
* Does this variable already exist?
@@ -1570,18 +1395,10 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
}
}
if (found) {
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
return -EINVAL;
}
- status = check_var_size_locked(efivars, new_var->Attributes,
- new_var->DataSize + utf16_strsize(new_var->VariableName, 1024));
-
- if (status && status != EFI_UNSUPPORTED) {
- spin_unlock_irq(&efivars->lock);
- return efi_status_to_err(status);
- }
-
/* now *really* create the variable via EFI */
status = efivars->ops->set_variable(new_var->VariableName,
&new_var->VendorGuid,
@@ -1592,10 +1409,10 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
if (status != EFI_SUCCESS) {
printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
status);
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
return -EIO;
}
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
/* Create the entry in sysfs. Locking is not required here */
status = efivar_create_sysfs_entry(efivars,
@@ -1623,7 +1440,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- spin_lock_irq(&efivars->lock);
+ spin_lock(&efivars->lock);
/*
* Does this variable already exist?
@@ -1641,7 +1458,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
}
}
if (!found) {
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
return -EINVAL;
}
/* force the Attributes/DataSize to 0 to ensure deletion */
@@ -1657,65 +1474,18 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
if (status != EFI_SUCCESS) {
printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
status);
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
return -EIO;
}
list_del(&search_efivar->list);
/* We need to release this lock before unregistering. */
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
efivar_unregister(search_efivar);
/* It's dead Jim.... */
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;
-}
-
-/*
- * Returns the size of variable_name, in bytes, including the
- * terminating NULL character, or variable_name_size if no NULL
- * character is found among the first variable_name_size bytes.
- */
-static unsigned long var_name_strnsize(efi_char16_t *variable_name,
- unsigned long variable_name_size)
-{
- unsigned long len;
- efi_char16_t c;
-
- /*
- * The variable name is, by definition, a NULL-terminated
- * string, so make absolutely sure that variable_name_size is
- * the value we expect it to be. If not, return the real size.
- */
- for (len = 2; len <= variable_name_size; len += sizeof(c)) {
- c = variable_name[(len / sizeof(c)) - 1];
- if (!c)
- break;
- }
-
- return min(len, variable_name_size);
-}
-
/*
* Let's not leave out systab information that snuck into
* the efivars driver
@@ -1824,9 +1594,9 @@ efivar_create_sysfs_entry(struct efivars *efivars,
kfree(short_name);
short_name = NULL;
- spin_lock_irq(&efivars->lock);
+ spin_lock(&efivars->lock);
list_add(&new_efivar->list, &efivars->list);
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
return 0;
}
@@ -1895,9 +1665,9 @@ void unregister_efivars(struct efivars *efivars)
struct efivar_entry *entry, *n;
list_for_each_entry_safe(entry, n, &efivars->list, list) {
- spin_lock_irq(&efivars->lock);
+ spin_lock(&efivars->lock);
list_del(&entry->list);
- spin_unlock_irq(&efivars->lock);
+ spin_unlock(&efivars->lock);
efivar_unregister(entry);
}
if (efivars->new_var)
@@ -1911,28 +1681,6 @@ void unregister_efivars(struct efivars *efivars)
}
EXPORT_SYMBOL_GPL(unregister_efivars);
-/*
- * 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,
- unsigned long len16)
-{
- size_t i, len8 = len16 / sizeof(efi_char16_t);
- char *s8;
-
- s8 = kzalloc(len8, GFP_KERNEL);
- if (!s8)
- return;
-
- for (i = 0; i < len8; i++)
- s8[i] = s16[i];
-
- printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n",
- s8, vendor_guid);
- kfree(s8);
-}
-
int register_efivars(struct efivars *efivars,
const struct efivar_operations *ops,
struct kobject *parent_kobj)
@@ -1981,24 +1729,6 @@ int register_efivars(struct efivars *efivars,
&vendor_guid);
switch (status) {
case EFI_SUCCESS:
- variable_name_size = var_name_strnsize(variable_name,
- variable_name_size);
-
- /*
- * Some firmware implementations return the
- * same variable name on multiple calls to
- * get_next_variable(). Terminate the loop
- * immediately as there is no guarantee that
- * we'll ever see a different variable name,
- * and may end up looping here forever.
- */
- if (variable_is_present(variable_name, &vendor_guid)) {
- dup_variable_bug(variable_name, &vendor_guid,
- variable_name_size);
- status = EFI_NOT_FOUND;
- break;
- }
-
efivar_create_sysfs_entry(efivars,
variable_name_size,
variable_name,
@@ -2018,8 +1748,15 @@ int register_efivars(struct efivars *efivars,
if (error)
unregister_efivars(efivars);
- if (!efivars_pstore_disable)
- efivar_pstore_register(efivars);
+ efivars->efi_pstore_info = efi_pstore_info;
+
+ efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL);
+ if (efivars->efi_pstore_info.buf) {
+ efivars->efi_pstore_info.bufsize = 1024;
+ efivars->efi_pstore_info.data = efivars;
+ spin_lock_init(&efivars->efi_pstore_info.buf_lock);
+ pstore_register(&efivars->efi_pstore_info);
+ }
register_filesystem(&efivarfs_type);