efivars: Keep a private global pointer to efivars
[cascardo/linux.git] / drivers / firmware / efivars.c
index 34c8783..eab4ec4 100644 (file)
@@ -125,7 +125,6 @@ struct efi_variable {
 } __attribute__((packed));
 
 struct efivar_entry {
-       struct efivars *efivars;
        struct efi_variable var;
        struct list_head list;
        struct kobject kobj;
@@ -137,8 +136,8 @@ struct efivar_attribute {
        ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count);
 };
 
-static struct efivars __efivars;
-static struct efivar_operations ops;
+/* Private pointer to registered efivars */
+static struct efivars *__efivars;
 
 #define PSTORE_EFI_ATTRIBUTES \
        (EFI_VARIABLE_NON_VOLATILE | \
@@ -479,7 +478,7 @@ efivar_attr_read(struct efivar_entry *entry, char *buf)
        if (!entry || !buf)
                return -EINVAL;
 
-       status = get_var_data(entry->efivars, var);
+       status = get_var_data(__efivars, var);
        if (status != EFI_SUCCESS)
                return -EIO;
 
@@ -513,7 +512,7 @@ efivar_size_read(struct efivar_entry *entry, char *buf)
        if (!entry || !buf)
                return -EINVAL;
 
-       status = get_var_data(entry->efivars, var);
+       status = get_var_data(__efivars, var);
        if (status != EFI_SUCCESS)
                return -EIO;
 
@@ -530,7 +529,7 @@ efivar_data_read(struct efivar_entry *entry, char *buf)
        if (!entry || !buf)
                return -EINVAL;
 
-       status = get_var_data(entry->efivars, var);
+       status = get_var_data(__efivars, var);
        if (status != EFI_SUCCESS)
                return -EIO;
 
@@ -545,7 +544,7 @@ static ssize_t
 efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
 {
        struct efi_variable *new_var, *var = &entry->var;
-       struct efivars *efivars = entry->efivars;
+       struct efivars *efivars = __efivars;
        efi_status_t status = EFI_NOT_FOUND;
 
        if (count != sizeof(struct efi_variable))
@@ -606,7 +605,7 @@ efivar_show_raw(struct efivar_entry *entry, char *buf)
        if (!entry || !buf)
                return 0;
 
-       status = get_var_data(entry->efivars, var);
+       status = get_var_data(__efivars, var);
        if (status != EFI_SUCCESS)
                return -EIO;
 
@@ -728,7 +727,7 @@ static ssize_t efivarfs_file_write(struct file *file,
                const char __user *userbuf, size_t count, loff_t *ppos)
 {
        struct efivar_entry *var = file->private_data;
-       struct efivars *efivars;
+       struct efivars *efivars = __efivars;
        efi_status_t status;
        void *data;
        u32 attributes;
@@ -746,8 +745,6 @@ static ssize_t efivarfs_file_write(struct file *file,
        if (attributes & ~(EFI_VARIABLE_MASK))
                return -EINVAL;
 
-       efivars = var->efivars;
-
        /*
         * Ensure that the user can't allocate arbitrarily large
         * amounts of memory. Pick a default size of 64K if
@@ -855,7 +852,7 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
                size_t count, loff_t *ppos)
 {
        struct efivar_entry *var = file->private_data;
-       struct efivars *efivars = var->efivars;
+       struct efivars *efivars = __efivars;
        efi_status_t status;
        unsigned long datasize = 0;
        u32 attributes;
@@ -1009,7 +1006,7 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
                          umode_t mode, bool excl)
 {
        struct inode *inode;
-       struct efivars *efivars = &__efivars;
+       struct efivars *efivars = __efivars;
        struct efivar_entry *var;
        int namelen, i = 0, err = 0;
 
@@ -1038,7 +1035,6 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
        var->var.VariableName[i] = '\0';
 
        inode->i_private = var;
-       var->efivars = efivars;
        var->kobj.kset = efivars->kset;
 
        err = kobject_init_and_add(&var->kobj, &efivar_ktype, NULL, "%s",
@@ -1063,7 +1059,7 @@ out:
 static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
 {
        struct efivar_entry *var = dentry->d_inode->i_private;
-       struct efivars *efivars = var->efivars;
+       struct efivars *efivars = __efivars;
        efi_status_t status;
 
        spin_lock_irq(&efivars->lock);
@@ -1175,7 +1171,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
        struct inode *inode = NULL;
        struct dentry *root;
        struct efivar_entry *entry, *n;
-       struct efivars *efivars = &__efivars;
+       struct efivars *efivars = __efivars;
        char *name;
        int err = -ENOMEM;
 
@@ -1302,7 +1298,7 @@ static const struct inode_operations efivarfs_dir_inode_operations = {
 
 static int efi_pstore_open(struct pstore_info *psi)
 {
-       struct efivars *efivars = psi->data;
+       struct efivars *efivars = __efivars;
 
        spin_lock_irq(&efivars->lock);
        efivars->walk_entry = list_first_entry(&efivars->list,
@@ -1312,7 +1308,7 @@ static int efi_pstore_open(struct pstore_info *psi)
 
 static int efi_pstore_close(struct pstore_info *psi)
 {
-       struct efivars *efivars = psi->data;
+       struct efivars *efivars = __efivars;
 
        spin_unlock_irq(&efivars->lock);
        return 0;
@@ -1323,7 +1319,7 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
                               char **buf, struct pstore_info *psi)
 {
        efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
-       struct efivars *efivars = psi->data;
+       struct efivars *efivars = __efivars;
        char name[DUMP_NAME_LEN];
        int i;
        int cnt;
@@ -1386,7 +1382,7 @@ static int efi_pstore_write(enum pstore_type_id type,
        char name[DUMP_NAME_LEN];
        efi_char16_t efi_name[DUMP_NAME_LEN];
        efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
-       struct efivars *efivars = psi->data;
+       struct efivars *efivars = __efivars;
        int i, ret = 0;
        efi_status_t status = EFI_NOT_FOUND;
        unsigned long flags;
@@ -1443,7 +1439,7 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
        char name_old[DUMP_NAME_LEN];
        efi_char16_t efi_name_old[DUMP_NAME_LEN];
        efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
-       struct efivars *efivars = psi->data;
+       struct efivars *efivars = __efivars;
        struct efivar_entry *entry, *found = NULL;
        int i;
 
@@ -1535,7 +1531,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
                             char *buf, loff_t pos, size_t count)
 {
        struct efi_variable *new_var = (struct efi_variable *)buf;
-       struct efivars *efivars = bin_attr->private;
+       struct efivars *efivars = __efivars;
        struct efivar_entry *search_efivar, *n;
        unsigned long strsize1, strsize2;
        efi_status_t status = EFI_NOT_FOUND;
@@ -1612,7 +1608,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
                             char *buf, loff_t pos, size_t count)
 {
        struct efi_variable *del_var = (struct efi_variable *)buf;
-       struct efivars *efivars = bin_attr->private;
+       struct efivars *efivars = __efivars;
        struct efivar_entry *search_efivar, *n;
        unsigned long strsize1, strsize2;
        efi_status_t status = EFI_NOT_FOUND;
@@ -1670,7 +1666,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
 static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor)
 {
        struct efivar_entry *entry, *n;
-       struct efivars *efivars = &__efivars;
+       struct efivars *efivars = __efivars;
        unsigned long strsize1, strsize2;
        bool found = false;
 
@@ -1716,7 +1712,7 @@ static unsigned long var_name_strnsize(efi_char16_t *variable_name,
 
 static void efivar_update_sysfs_entries(struct work_struct *work)
 {
-       struct efivars *efivars = &__efivars;
+       struct efivars *efivars = __efivars;
        efi_guid_t vendor;
        efi_char16_t *variable_name;
        unsigned long variable_name_size = 1024;
@@ -1843,7 +1839,6 @@ efivar_create_sysfs_entry(struct efivars *efivars,
                return 1;
        }
 
-       new_efivar->efivars = efivars;
        memcpy(new_efivar->var.VariableName, variable_name,
                variable_name_size);
        memcpy(&(new_efivar->var.VendorGuid), vendor_guid, sizeof(efi_guid_t));
@@ -1942,6 +1937,8 @@ void unregister_efivars(struct efivars *efivars)
 {
        struct efivar_entry *entry, *n;
 
+       __efivars = NULL;
+
        list_for_each_entry_safe(entry, n, &efivars->list, list) {
                spin_lock_irq(&efivars->lock);
                list_del(&entry->list);
@@ -1998,6 +1995,8 @@ int register_efivars(struct efivars *efivars,
        unsigned long variable_name_size = 1024;
        int error = 0;
 
+       __efivars = efivars;
+
        variable_name = kzalloc(variable_name_size, GFP_KERNEL);
        if (!variable_name) {
                printk(KERN_ERR "efivars: Memory allocation failed.\n");
@@ -2085,6 +2084,24 @@ out:
 }
 EXPORT_SYMBOL_GPL(register_efivars);
 
+static struct efivars generic_efivars;
+static struct efivar_operations generic_ops;
+
+static int generic_ops_register(void)
+{
+       generic_ops.get_variable = efi.get_variable;
+       generic_ops.set_variable = efi.set_variable;
+       generic_ops.get_next_variable = efi.get_next_variable;
+       generic_ops.query_variable_info = efi.query_variable_info;
+
+       return register_efivars(&generic_efivars, &generic_ops, efi_kobj);
+}
+
+static void generic_ops_unregister(void)
+{
+       unregister_efivars(&generic_efivars);
+}
+
 /*
  * For now we register the efi subsystem with the firmware subsystem
  * and the vars subsystem with the efi subsystem.  In the future, it
@@ -2111,12 +2128,7 @@ efivars_init(void)
                return -ENOMEM;
        }
 
-       ops.get_variable = efi.get_variable;
-       ops.set_variable = efi.set_variable;
-       ops.get_next_variable = efi.get_next_variable;
-       ops.query_variable_info = efi.query_variable_info;
-
-       error = register_efivars(&__efivars, &ops, efi_kobj);
+       error = generic_ops_register();
        if (error)
                goto err_put;
 
@@ -2132,7 +2144,7 @@ efivars_init(void)
        return 0;
 
 err_unregister:
-       unregister_efivars(&__efivars);
+       generic_ops_unregister();
 err_put:
        kobject_put(efi_kobj);
        return error;
@@ -2144,7 +2156,7 @@ efivars_exit(void)
        cancel_work_sync(&efivar_work);
 
        if (efi_enabled(EFI_RUNTIME_SERVICES)) {
-               unregister_efivars(&__efivars);
+               generic_ops_unregister();
                kobject_put(efi_kobj);
        }
 }