0854ddf
From bc390c0e405a4fe896dfc54c8e6e737e41661e28 Mon Sep 17 00:00:00 2001
0854ddf
From: Matthew Garrett <mjg@redhat.com>
0854ddf
Date: Fri, 5 Oct 2012 13:54:56 +0800
0854ddf
Subject: [PATCH 01/17] efi: Add support for a UEFI variable filesystem
0854ddf
0854ddf
The existing EFI variables code only supports variables of up to 1024
0854ddf
bytes. This limitation existed in version 0.99 of the EFI specification,
0854ddf
but was removed before any full releases. Since variables can now be
0854ddf
larger than a single page, sysfs isn't the best interface for this. So,
0854ddf
instead, let's add a filesystem. Variables can be read, written and
0854ddf
created, with the first 4 bytes of each variable representing its UEFI
0854ddf
attributes. The create() method doesn't actually commit to flash since
0854ddf
zero-length variables can't exist per-spec.
0854ddf
0854ddf
Updates from Jeremy Kerr <jeremy.kerr@canonical.com>.
0854ddf
0854ddf
Signed-off-by: Matthew Garrett <mjg@redhat.com>
0854ddf
Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
0854ddf
---
0854ddf
 drivers/firmware/efivars.c | 384 ++++++++++++++++++++++++++++++++++++++++++++-
0854ddf
 include/linux/efi.h        |   5 +
0854ddf
 2 files changed, 383 insertions(+), 6 deletions(-)
0854ddf
0854ddf
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
0854ddf
index d10c987..b605c48 100644
0854ddf
--- a/drivers/firmware/efivars.c
0854ddf
+++ b/drivers/firmware/efivars.c
0854ddf
@@ -80,6 +80,10 @@
0854ddf
 #include <linux/slab.h>
0854ddf
 #include <linux/pstore.h>
0854ddf
 
0854ddf
+#include <linux/fs.h>
0854ddf
+#include <linux/ramfs.h>
0854ddf
+#include <linux/pagemap.h>
0854ddf
+
0854ddf
 #include <asm/uaccess.h>
0854ddf
 
0854ddf
 #define EFIVARS_VERSION "0.08"
0854ddf
@@ -91,6 +95,7 @@ MODULE_LICENSE("GPL");
0854ddf
 MODULE_VERSION(EFIVARS_VERSION);
0854ddf
 
0854ddf
 #define DUMP_NAME_LEN 52
0854ddf
+#define GUID_LEN 37
0854ddf
 
0854ddf
 /*
0854ddf
  * The maximum size of VariableName + Data = 1024
0854ddf
@@ -108,7 +113,6 @@ struct efi_variable {
0854ddf
 	__u32         Attributes;
0854ddf
 } __attribute__((packed));
0854ddf
 
0854ddf
-
0854ddf
 struct efivar_entry {
0854ddf
 	struct efivars *efivars;
0854ddf
 	struct efi_variable var;
0854ddf
@@ -122,6 +126,9 @@ struct efivar_attribute {
0854ddf
 	ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count);
0854ddf
 };
0854ddf
 
0854ddf
+static struct efivars __efivars;
0854ddf
+static struct efivar_operations ops;
0854ddf
+
0854ddf
 #define PSTORE_EFI_ATTRIBUTES \
0854ddf
 	(EFI_VARIABLE_NON_VOLATILE | \
0854ddf
 	 EFI_VARIABLE_BOOTSERVICE_ACCESS | \
0854ddf
@@ -629,14 +636,380 @@ static struct kobj_type efivar_ktype = {
0854ddf
 	.default_attrs = def_attrs,
0854ddf
 };
0854ddf
 
0854ddf
-static struct pstore_info efi_pstore_info;
0854ddf
-
0854ddf
 static inline void
0854ddf
 efivar_unregister(struct efivar_entry *var)
0854ddf
 {
0854ddf
 	kobject_put(&var->kobj);
0854ddf
 }
0854ddf
 
0854ddf
+static int efivarfs_file_open(struct inode *inode, struct file *file)
0854ddf
+{
0854ddf
+	file->private_data = inode->i_private;
0854ddf
+	return 0;
0854ddf
+}
0854ddf
+
0854ddf
+static ssize_t efivarfs_file_write(struct file *file,
0854ddf
+		const char __user *userbuf, size_t count, loff_t *ppos)
0854ddf
+{
0854ddf
+	struct efivar_entry *var = file->private_data;
0854ddf
+	struct efivars *efivars;
0854ddf
+	efi_status_t status;
0854ddf
+	void *data;
0854ddf
+	u32 attributes;
0854ddf
+	struct inode *inode = file->f_mapping->host;
0854ddf
+	int datasize = count - sizeof(attributes);
0854ddf
+
0854ddf
+	if (count < sizeof(attributes))
0854ddf
+		return -EINVAL;
0854ddf
+
0854ddf
+	data = kmalloc(datasize, GFP_KERNEL);
0854ddf
+
0854ddf
+	if (!data)
0854ddf
+		return -ENOMEM;
0854ddf
+
0854ddf
+	efivars = var->efivars;
0854ddf
+
0854ddf
+	if (copy_from_user(&attributes, userbuf, sizeof(attributes))) {
0854ddf
+		count = -EFAULT;
0854ddf
+		goto out;
0854ddf
+	}
0854ddf
+
0854ddf
+	if (attributes & ~(EFI_VARIABLE_MASK)) {
0854ddf
+		count = -EINVAL;
0854ddf
+		goto out;
0854ddf
+	}
0854ddf
+
0854ddf
+	if (copy_from_user(data, userbuf + sizeof(attributes), datasize)) {
0854ddf
+		count = -EFAULT;
0854ddf
+		goto out;
0854ddf
+	}
0854ddf
+
0854ddf
+	if (validate_var(&var->var, data, datasize) == false) {
0854ddf
+		count = -EINVAL;
0854ddf
+		goto out;
0854ddf
+	}
0854ddf
+
0854ddf
+	status = efivars->ops->set_variable(var->var.VariableName,
0854ddf
+					    &var->var.VendorGuid,
0854ddf
+					    attributes, datasize,
0854ddf
+					    data);
0854ddf
+
0854ddf
+	switch (status) {
0854ddf
+	case EFI_SUCCESS:
0854ddf
+		mutex_lock(&inode->i_mutex);
0854ddf
+		i_size_write(inode, count);
0854ddf
+		mutex_unlock(&inode->i_mutex);
0854ddf
+		break;
0854ddf
+	case EFI_INVALID_PARAMETER:
0854ddf
+		count = -EINVAL;
0854ddf
+		break;
0854ddf
+	case EFI_OUT_OF_RESOURCES:
0854ddf
+		count = -ENOSPC;
0854ddf
+		break;
0854ddf
+	case EFI_DEVICE_ERROR:
0854ddf
+		count = -EIO;
0854ddf
+		break;
0854ddf
+	case EFI_WRITE_PROTECTED:
0854ddf
+		count = -EROFS;
0854ddf
+		break;
0854ddf
+	case EFI_SECURITY_VIOLATION:
0854ddf
+		count = -EACCES;
0854ddf
+		break;
0854ddf
+	case EFI_NOT_FOUND:
0854ddf
+		count = -ENOENT;
0854ddf
+		break;
0854ddf
+	default:
0854ddf
+		count = -EINVAL;
0854ddf
+		break;
0854ddf
+	}
0854ddf
+out:
0854ddf
+	kfree(data);
0854ddf
+
0854ddf
+	return count;
0854ddf
+}
0854ddf
+
0854ddf
+static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
0854ddf
+		size_t count, loff_t *ppos)
0854ddf
+{
0854ddf
+	struct efivar_entry *var = file->private_data;
0854ddf
+	struct efivars *efivars = var->efivars;
0854ddf
+	efi_status_t status;
0854ddf
+	unsigned long datasize = 0;
0854ddf
+	u32 attributes;
0854ddf
+	void *data;
0854ddf
+	ssize_t size;
0854ddf
+
0854ddf
+	status = efivars->ops->get_variable(var->var.VariableName,
0854ddf
+					    &var->var.VendorGuid,
0854ddf
+					    &attributes, &datasize, NULL);
0854ddf
+
0854ddf
+	if (status != EFI_BUFFER_TOO_SMALL)
0854ddf
+		return 0;
0854ddf
+
0854ddf
+	data = kmalloc(datasize + 4, GFP_KERNEL);
0854ddf
+
0854ddf
+	if (!data)
0854ddf
+		return 0;
0854ddf
+
0854ddf
+	status = efivars->ops->get_variable(var->var.VariableName,
0854ddf
+					    &var->var.VendorGuid,
0854ddf
+					    &attributes, &datasize,
0854ddf
+					    (data + 4));
0854ddf
+
0854ddf
+	if (status != EFI_SUCCESS)
0854ddf
+		return 0;
0854ddf
+
0854ddf
+	memcpy(data, &attributes, 4);
0854ddf
+	size = simple_read_from_buffer(userbuf, count, ppos,
0854ddf
+					data, datasize + 4);
0854ddf
+	kfree(data);
0854ddf
+
0854ddf
+	return size;
0854ddf
+}
0854ddf
+
0854ddf
+static void efivarfs_evict_inode(struct inode *inode)
0854ddf
+{
0854ddf
+	clear_inode(inode);
0854ddf
+}
0854ddf
+
0854ddf
+static const struct super_operations efivarfs_ops = {
0854ddf
+	.statfs = simple_statfs,
0854ddf
+	.drop_inode = generic_delete_inode,
0854ddf
+	.evict_inode = efivarfs_evict_inode,
0854ddf
+	.show_options = generic_show_options,
0854ddf
+};
0854ddf
+
0854ddf
+static struct super_block *efivarfs_sb;
0854ddf
+
0854ddf
+static const struct inode_operations efivarfs_dir_inode_operations;
0854ddf
+
0854ddf
+static const struct file_operations efivarfs_file_operations = {
0854ddf
+	.open	= efivarfs_file_open,
0854ddf
+	.read	= efivarfs_file_read,
0854ddf
+	.write	= efivarfs_file_write,
0854ddf
+	.llseek	= no_llseek,
0854ddf
+};
0854ddf
+
0854ddf
+static struct inode *efivarfs_get_inode(struct super_block *sb,
0854ddf
+				const struct inode *dir, int mode, dev_t dev)
0854ddf
+{
0854ddf
+	struct inode *inode = new_inode(sb);
0854ddf
+
0854ddf
+	if (inode) {
0854ddf
+		inode->i_ino = get_next_ino();
0854ddf
+		inode->i_uid = inode->i_gid = 0;
0854ddf
+		inode->i_mode = mode;
0854ddf
+		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
0854ddf
+		switch (mode & S_IFMT) {
0854ddf
+		case S_IFREG:
0854ddf
+			inode->i_fop = &efivarfs_file_operations;
0854ddf
+			break;
0854ddf
+		case S_IFDIR:
0854ddf
+			inode->i_op = &efivarfs_dir_inode_operations;
0854ddf
+			inode->i_fop = &simple_dir_operations;
0854ddf
+			inc_nlink(inode);
0854ddf
+			break;
0854ddf
+		}
0854ddf
+	}
0854ddf
+	return inode;
0854ddf
+}
0854ddf
+
0854ddf
+static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid)
0854ddf
+{
0854ddf
+	guid->b[0] = hex_to_bin(str[6]) << 4 | hex_to_bin(str[7]);
0854ddf
+	guid->b[1] = hex_to_bin(str[4]) << 4 | hex_to_bin(str[5]);
0854ddf
+	guid->b[2] = hex_to_bin(str[2]) << 4 | hex_to_bin(str[3]);
0854ddf
+	guid->b[3] = hex_to_bin(str[0]) << 4 | hex_to_bin(str[1]);
0854ddf
+	guid->b[4] = hex_to_bin(str[11]) << 4 | hex_to_bin(str[12]);
0854ddf
+	guid->b[5] = hex_to_bin(str[9]) << 4 | hex_to_bin(str[10]);
0854ddf
+	guid->b[6] = hex_to_bin(str[16]) << 4 | hex_to_bin(str[17]);
0854ddf
+	guid->b[7] = hex_to_bin(str[14]) << 4 | hex_to_bin(str[15]);
0854ddf
+	guid->b[8] = hex_to_bin(str[19]) << 4 | hex_to_bin(str[20]);
0854ddf
+	guid->b[9] = hex_to_bin(str[21]) << 4 | hex_to_bin(str[22]);
0854ddf
+	guid->b[10] = hex_to_bin(str[24]) << 4 | hex_to_bin(str[25]);
0854ddf
+	guid->b[11] = hex_to_bin(str[26]) << 4 | hex_to_bin(str[27]);
0854ddf
+	guid->b[12] = hex_to_bin(str[28]) << 4 | hex_to_bin(str[29]);
0854ddf
+	guid->b[13] = hex_to_bin(str[30]) << 4 | hex_to_bin(str[31]);
0854ddf
+	guid->b[14] = hex_to_bin(str[32]) << 4 | hex_to_bin(str[33]);
0854ddf
+	guid->b[15] = hex_to_bin(str[34]) << 4 | hex_to_bin(str[35]);
0854ddf
+}
0854ddf
+
0854ddf
+static int efivarfs_create(struct inode *dir, struct dentry *dentry,
0854ddf
+			  umode_t mode, bool excl)
0854ddf
+{
0854ddf
+	struct inode *inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0);
0854ddf
+	struct efivars *efivars = &__efivars;
0854ddf
+	struct efivar_entry *var;
0854ddf
+	int namelen, i = 0, err = 0;
0854ddf
+
0854ddf
+	if (dentry->d_name.len < 38)
0854ddf
+		return -EINVAL;
0854ddf
+
0854ddf
+	if (!inode)
0854ddf
+		return -ENOSPC;
0854ddf
+
0854ddf
+	var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
0854ddf
+
0854ddf
+	if (!var)
0854ddf
+		return -ENOMEM;
0854ddf
+
0854ddf
+	namelen = dentry->d_name.len - GUID_LEN;
0854ddf
+
0854ddf
+	efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1,
0854ddf
+			&var->var.VendorGuid);
0854ddf
+
0854ddf
+	for (i = 0; i < namelen; i++)
0854ddf
+		var->var.VariableName[i] = dentry->d_name.name[i];
0854ddf
+
0854ddf
+	var->var.VariableName[i] = '\0';
0854ddf
+
0854ddf
+	inode->i_private = var;
0854ddf
+	var->efivars = efivars;
0854ddf
+	var->kobj.kset = efivars->kset;
0854ddf
+
0854ddf
+	err = kobject_init_and_add(&var->kobj, &efivar_ktype, NULL, "%s",
0854ddf
+			     dentry->d_name.name);
0854ddf
+	if (err)
0854ddf
+		goto out;
0854ddf
+
0854ddf
+	kobject_uevent(&var->kobj, KOBJ_ADD);
0854ddf
+	spin_lock(&efivars->lock);
0854ddf
+	list_add(&var->list, &efivars->list);
0854ddf
+	spin_unlock(&efivars->lock);
0854ddf
+	d_instantiate(dentry, inode);
0854ddf
+	dget(dentry);
0854ddf
+out:
0854ddf
+	if (err)
0854ddf
+		kfree(var);
0854ddf
+	return err;
0854ddf
+}
0854ddf
+
0854ddf
+static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
0854ddf
+{
0854ddf
+	struct efivar_entry *var = dentry->d_inode->i_private;
0854ddf
+	struct efivars *efivars = var->efivars;
0854ddf
+	efi_status_t status;
0854ddf
+
0854ddf
+	spin_lock(&efivars->lock);
0854ddf
+
0854ddf
+	status = efivars->ops->set_variable(var->var.VariableName,
0854ddf
+					    &var->var.VendorGuid,
0854ddf
+					    0, 0, NULL);
0854ddf
+
0854ddf
+	if (status == EFI_SUCCESS || status == EFI_NOT_FOUND) {
0854ddf
+		list_del(&var->list);
0854ddf
+		spin_unlock(&efivars->lock);
0854ddf
+		efivar_unregister(var);
0854ddf
+		drop_nlink(dir);
0854ddf
+		dput(dentry);
0854ddf
+		return 0;
0854ddf
+	}
0854ddf
+
0854ddf
+	spin_unlock(&efivars->lock);
0854ddf
+	return -EINVAL;
0854ddf
+};
0854ddf
+
0854ddf
+int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
0854ddf
+{
0854ddf
+	struct inode *inode = NULL;
0854ddf
+	struct dentry *root;
0854ddf
+	struct efivar_entry *entry, *n;
0854ddf
+	struct efivars *efivars = &__efivars;
0854ddf
+	int err;
0854ddf
+
0854ddf
+	efivarfs_sb = sb;
0854ddf
+
0854ddf
+	sb->s_maxbytes          = MAX_LFS_FILESIZE;
0854ddf
+	sb->s_blocksize         = PAGE_CACHE_SIZE;
0854ddf
+	sb->s_blocksize_bits    = PAGE_CACHE_SHIFT;
0854ddf
+	sb->s_magic             = PSTOREFS_MAGIC;
0854ddf
+	sb->s_op                = &efivarfs_ops;
0854ddf
+	sb->s_time_gran         = 1;
0854ddf
+
0854ddf
+	inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0);
0854ddf
+	if (!inode) {
0854ddf
+		err = -ENOMEM;
0854ddf
+		goto fail;
0854ddf
+	}
0854ddf
+	inode->i_op = &efivarfs_dir_inode_operations;
0854ddf
+
0854ddf
+	root = d_make_root(inode);
0854ddf
+	sb->s_root = root;
0854ddf
+	if (!root) {
0854ddf
+		err = -ENOMEM;
0854ddf
+		goto fail;
0854ddf
+	}
0854ddf
+
0854ddf
+	list_for_each_entry_safe(entry, n, &efivars->list, list) {
0854ddf
+		struct inode *inode;
0854ddf
+		struct dentry *dentry, *root = efivarfs_sb->s_root;
0854ddf
+		char *name;
0854ddf
+		unsigned long size = 0;
0854ddf
+		int len, i;
0854ddf
+
0854ddf
+		len = utf16_strlen(entry->var.VariableName);
0854ddf
+
0854ddf
+		/* GUID plus trailing NULL */
0854ddf
+		name = kmalloc(len + 38, GFP_ATOMIC);
0854ddf
+
0854ddf
+		for (i = 0; i < len; i++)
0854ddf
+			name[i] = entry->var.VariableName[i] & 0xFF;
0854ddf
+
0854ddf
+		name[len] = '-';
0854ddf
+
0854ddf
+		efi_guid_unparse(&entry->var.VendorGuid, name + len + 1);
0854ddf
+
0854ddf
+		name[len+GUID_LEN] = '\0';
0854ddf
+
0854ddf
+		inode = efivarfs_get_inode(efivarfs_sb, root->d_inode,
0854ddf
+					  S_IFREG | 0644, 0);
0854ddf
+		dentry = d_alloc_name(root, name);
0854ddf
+
0854ddf
+		efivars->ops->get_variable(entry->var.VariableName,
0854ddf
+					   &entry->var.VendorGuid,
0854ddf
+					   &entry->var.Attributes,
0854ddf
+					   &size,
0854ddf
+					   NULL);
0854ddf
+
0854ddf
+		mutex_lock(&inode->i_mutex);
0854ddf
+		inode->i_private = entry;
0854ddf
+		i_size_write(inode, size+4);
0854ddf
+		mutex_unlock(&inode->i_mutex);
0854ddf
+		d_add(dentry, inode);
0854ddf
+	}
0854ddf
+
0854ddf
+	return 0;
0854ddf
+fail:
0854ddf
+	iput(inode);
0854ddf
+	return err;
0854ddf
+}
0854ddf
+
0854ddf
+static struct dentry *efivarfs_mount(struct file_system_type *fs_type,
0854ddf
+				    int flags, const char *dev_name, void *data)
0854ddf
+{
0854ddf
+	return mount_single(fs_type, flags, data, efivarfs_fill_super);
0854ddf
+}
0854ddf
+
0854ddf
+static void efivarfs_kill_sb(struct super_block *sb)
0854ddf
+{
0854ddf
+	kill_litter_super(sb);
0854ddf
+	efivarfs_sb = NULL;
0854ddf
+}
0854ddf
+
0854ddf
+static struct file_system_type efivarfs_type = {
0854ddf
+	.name    = "efivarfs",
0854ddf
+	.mount   = efivarfs_mount,
0854ddf
+	.kill_sb = efivarfs_kill_sb,
0854ddf
+};
0854ddf
+
0854ddf
+static const struct inode_operations efivarfs_dir_inode_operations = {
0854ddf
+	.lookup = simple_lookup,
0854ddf
+	.unlink = efivarfs_unlink,
0854ddf
+	.create = efivarfs_create,
0854ddf
+};
0854ddf
+
0854ddf
+static struct pstore_info efi_pstore_info;
0854ddf
+
0854ddf
 #ifdef CONFIG_PSTORE
0854ddf
 
0854ddf
 static int efi_pstore_open(struct pstore_info *psi)
0854ddf
@@ -1198,6 +1571,8 @@ int register_efivars(struct efivars *efivars,
0854ddf
 		pstore_register(&efivars->efi_pstore_info);
0854ddf
 	}
0854ddf
 
0854ddf
+	register_filesystem(&efivarfs_type);
0854ddf
+
0854ddf
 out:
0854ddf
 	kfree(variable_name);
0854ddf
 
0854ddf
@@ -1205,9 +1580,6 @@ out:
0854ddf
 }
0854ddf
 EXPORT_SYMBOL_GPL(register_efivars);
0854ddf
 
0854ddf
-static struct efivars __efivars;
0854ddf
-static struct efivar_operations ops;
0854ddf
-
0854ddf
 /*
0854ddf
  * For now we register the efi subsystem with the firmware subsystem
0854ddf
  * and the vars subsystem with the efi subsystem.  In the future, it
0854ddf
diff --git a/include/linux/efi.h b/include/linux/efi.h
0854ddf
index 5782114..2f1db28 100644
0854ddf
--- a/include/linux/efi.h
0854ddf
+++ b/include/linux/efi.h
0854ddf
@@ -29,7 +29,12 @@
0854ddf
 #define EFI_UNSUPPORTED		( 3 | (1UL << (BITS_PER_LONG-1)))
0854ddf
 #define EFI_BAD_BUFFER_SIZE     ( 4 | (1UL << (BITS_PER_LONG-1)))
0854ddf
 #define EFI_BUFFER_TOO_SMALL	( 5 | (1UL << (BITS_PER_LONG-1)))
0854ddf
+#define EFI_NOT_READY		( 6 | (1UL << (BITS_PER_LONG-1)))
0854ddf
+#define EFI_DEVICE_ERROR	( 7 | (1UL << (BITS_PER_LONG-1)))
0854ddf
+#define EFI_WRITE_PROTECTED	( 8 | (1UL << (BITS_PER_LONG-1)))
0854ddf
+#define EFI_OUT_OF_RESOURCES	( 9 | (1UL << (BITS_PER_LONG-1)))
0854ddf
 #define EFI_NOT_FOUND		(14 | (1UL << (BITS_PER_LONG-1)))
0854ddf
+#define EFI_SECURITY_VIOLATION	(26 | (1UL << (BITS_PER_LONG-1)))
0854ddf
 
0854ddf
 typedef unsigned long efi_status_t;
0854ddf
 typedef u8 efi_bool_t;
0854ddf
-- 
0854ddf
1.7.12.1
0854ddf
0854ddf
0854ddf
From 47c7d712bac1ba86ae9d3f8bb5594d8d9ab57537 Mon Sep 17 00:00:00 2001
0854ddf
From: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Date: Fri, 5 Oct 2012 13:54:56 +0800
0854ddf
Subject: [PATCH 02/17] efi: Handle deletions and size changes in
0854ddf
 efivarfs_write_file
0854ddf
0854ddf
A write to an efivarfs file will not always result in a variable of
0854ddf
'count' size after the EFI SetVariable() call. We may have appended to
0854ddf
the existing data (ie, with the EFI_VARIABLE_APPEND_WRITE attribute), or
0854ddf
even have deleted the variable (with an authenticated variable update,
0854ddf
with a zero datasize).
0854ddf
0854ddf
This change re-reads the updated variable from firmware, to check for
0854ddf
size changes and deletions. In the latter case, we need to drop the
0854ddf
dentry.
0854ddf
0854ddf
Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
0854ddf
---
0854ddf
 drivers/firmware/efivars.c | 49 ++++++++++++++++++++++++++++++++++++----------
0854ddf
 1 file changed, 39 insertions(+), 10 deletions(-)
0854ddf
0854ddf
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
0854ddf
index b605c48..d7658b4 100644
0854ddf
--- a/drivers/firmware/efivars.c
0854ddf
+++ b/drivers/firmware/efivars.c
0854ddf
@@ -658,6 +658,7 @@ static ssize_t efivarfs_file_write(struct file *file,
0854ddf
 	u32 attributes;
0854ddf
 	struct inode *inode = file->f_mapping->host;
0854ddf
 	int datasize = count - sizeof(attributes);
0854ddf
+	unsigned long newdatasize;
0854ddf
 
0854ddf
 	if (count < sizeof(attributes))
0854ddf
 		return -EINVAL;
0854ddf
@@ -696,32 +697,60 @@ static ssize_t efivarfs_file_write(struct file *file,
0854ddf
 
0854ddf
 	switch (status) {
0854ddf
 	case EFI_SUCCESS:
0854ddf
-		mutex_lock(&inode->i_mutex);
0854ddf
-		i_size_write(inode, count);
0854ddf
-		mutex_unlock(&inode->i_mutex);
0854ddf
 		break;
0854ddf
 	case EFI_INVALID_PARAMETER:
0854ddf
 		count = -EINVAL;
0854ddf
-		break;
0854ddf
+		goto out;
0854ddf
 	case EFI_OUT_OF_RESOURCES:
0854ddf
 		count = -ENOSPC;
0854ddf
-		break;
0854ddf
+		goto out;
0854ddf
 	case EFI_DEVICE_ERROR:
0854ddf
 		count = -EIO;
0854ddf
-		break;
0854ddf
+		goto out;
0854ddf
 	case EFI_WRITE_PROTECTED:
0854ddf
 		count = -EROFS;
0854ddf
-		break;
0854ddf
+		goto out;
0854ddf
 	case EFI_SECURITY_VIOLATION:
0854ddf
 		count = -EACCES;
0854ddf
-		break;
0854ddf
+		goto out;
0854ddf
 	case EFI_NOT_FOUND:
0854ddf
 		count = -ENOENT;
0854ddf
-		break;
0854ddf
+		goto out;
0854ddf
 	default:
0854ddf
 		count = -EINVAL;
0854ddf
-		break;
0854ddf
+		goto out;
0854ddf
 	}
0854ddf
+
0854ddf
+	/*
0854ddf
+	 * Writing to the variable may have caused a change in size (which
0854ddf
+	 * could either be an append or an overwrite), or the variable to be
0854ddf
+	 * deleted. Perform a GetVariable() so we can tell what actually
0854ddf
+	 * happened.
0854ddf
+	 */
0854ddf
+	newdatasize = 0;
0854ddf
+	status = efivars->ops->get_variable(var->var.VariableName,
0854ddf
+					    &var->var.VendorGuid,
0854ddf
+					    NULL, &newdatasize,
0854ddf
+					    NULL);
0854ddf
+
0854ddf
+	if (status == EFI_BUFFER_TOO_SMALL) {
0854ddf
+		mutex_lock(&inode->i_mutex);
0854ddf
+		i_size_write(inode, newdatasize + sizeof(attributes));
0854ddf
+		mutex_unlock(&inode->i_mutex);
0854ddf
+
0854ddf
+	} else if (status == EFI_NOT_FOUND) {
0854ddf
+		spin_lock(&efivars->lock);
0854ddf
+		list_del(&var->list);
0854ddf
+		spin_unlock(&efivars->lock);
0854ddf
+		efivar_unregister(var);
0854ddf
+		drop_nlink(inode);
0854ddf
+		dput(file->f_dentry);
0854ddf
+
0854ddf
+	} else {
0854ddf
+		pr_warn("efivarfs: inconsistent EFI variable implementation? "
0854ddf
+				"status = %lx\n", status);
0854ddf
+	}
0854ddf
+
0854ddf
 out:
0854ddf
 	kfree(data);
0854ddf
 
0854ddf
-- 
0854ddf
1.7.12.1
0854ddf
0854ddf
0854ddf
From 48173c3d1e7014574d5b2517a471587775e4cb91 Mon Sep 17 00:00:00 2001
0854ddf
From: "Lee, Chun-Yi" <joeyli.kernel@gmail.com>
0854ddf
Date: Fri, 5 Oct 2012 13:54:56 +0800
0854ddf
Subject: [PATCH 03/17] efi: add efivars kobject to efi sysfs folder
0854ddf
0854ddf
UEFI variable filesystem need a new mount point, so this patch add
0854ddf
efivars kobject to efi_kobj for create a /sys/firmware/efi/efivars
0854ddf
folder.
0854ddf
0854ddf
Cc: Matthew Garrett <mjg@redhat.com>
0854ddf
Cc: H. Peter Anvin <hpa@zytor.com>
0854ddf
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
0854ddf
Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
0854ddf
---
0854ddf
 drivers/firmware/efivars.c | 9 +++++++++
0854ddf
 include/linux/efi.h        | 1 +
0854ddf
 2 files changed, 10 insertions(+)
0854ddf
0854ddf
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
0854ddf
index d7658b4..6793965 100644
0854ddf
--- a/drivers/firmware/efivars.c
0854ddf
+++ b/drivers/firmware/efivars.c
0854ddf
@@ -1527,6 +1527,7 @@ void unregister_efivars(struct efivars *efivars)
0854ddf
 		sysfs_remove_bin_file(&efivars->kset->kobj, efivars->del_var);
0854ddf
 	kfree(efivars->new_var);
0854ddf
 	kfree(efivars->del_var);
0854ddf
+	kobject_put(efivars->kobject);
0854ddf
 	kset_unregister(efivars->kset);
0854ddf
 }
0854ddf
 EXPORT_SYMBOL_GPL(unregister_efivars);
0854ddf
@@ -1558,6 +1559,14 @@ int register_efivars(struct efivars *efivars,
0854ddf
 		goto out;
0854ddf
 	}
0854ddf
 
0854ddf
+	efivars->kobject = kobject_create_and_add("efivars", parent_kobj);
0854ddf
+	if (!efivars->kobject) {
0854ddf
+		pr_err("efivars: Subsystem registration failed.\n");
0854ddf
+		error = -ENOMEM;
0854ddf
+		kset_unregister(efivars->kset);
0854ddf
+		goto out;
0854ddf
+	}
0854ddf
+
0854ddf
 	/*
0854ddf
 	 * Per EFI spec, the maximum storage allocated for both
0854ddf
 	 * the variable name and variable data is 1024 bytes.
0854ddf
diff --git a/include/linux/efi.h b/include/linux/efi.h
0854ddf
index 2f1db28..bff4b5e 100644
0854ddf
--- a/include/linux/efi.h
0854ddf
+++ b/include/linux/efi.h
0854ddf
@@ -659,6 +659,7 @@ struct efivars {
0854ddf
 	spinlock_t lock;
0854ddf
 	struct list_head list;
0854ddf
 	struct kset *kset;
0854ddf
+	struct kobject *kobject;
0854ddf
 	struct bin_attribute *new_var, *del_var;
0854ddf
 	const struct efivar_operations *ops;
0854ddf
 	struct efivar_entry *walk_entry;
0854ddf
-- 
0854ddf
1.7.12.1
0854ddf
0854ddf
0854ddf
From 8c209f22c606ba8c4fa939245efae9921fb1988a Mon Sep 17 00:00:00 2001
0854ddf
From: Matt Fleming <matt.fleming@intel.com>
0854ddf
Date: Thu, 4 Oct 2012 09:57:31 +0100
0854ddf
Subject: [PATCH 04/17] efivarfs: Add documentation for the EFI variable
0854ddf
 filesystem
0854ddf
0854ddf
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
0854ddf
---
0854ddf
 Documentation/filesystems/00-INDEX     |  2 ++
0854ddf
 Documentation/filesystems/efivarfs.txt | 16 ++++++++++++++++
0854ddf
 2 files changed, 18 insertions(+)
0854ddf
 create mode 100644 Documentation/filesystems/efivarfs.txt
0854ddf
0854ddf
diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX
0854ddf
index 8c624a1..7b52ba7 100644
0854ddf
--- a/Documentation/filesystems/00-INDEX
0854ddf
+++ b/Documentation/filesystems/00-INDEX
0854ddf
@@ -38,6 +38,8 @@ dnotify_test.c
0854ddf
 	- example program for dnotify
0854ddf
 ecryptfs.txt
0854ddf
 	- docs on eCryptfs: stacked cryptographic filesystem for Linux.
0854ddf
+efivarfs.txt
0854ddf
+	- info for the efivarfs filesystem.
0854ddf
 exofs.txt
0854ddf
 	- info, usage, mount options, design about EXOFS.
0854ddf
 ext2.txt
0854ddf
diff --git a/Documentation/filesystems/efivarfs.txt b/Documentation/filesystems/efivarfs.txt
0854ddf
new file mode 100644
0854ddf
index 0000000..c477af0
0854ddf
--- /dev/null
0854ddf
+++ b/Documentation/filesystems/efivarfs.txt
0854ddf
@@ -0,0 +1,16 @@
0854ddf
+
0854ddf
+efivarfs - a (U)EFI variable filesystem
0854ddf
+
0854ddf
+The efivarfs filesystem was created to address the shortcomings of
0854ddf
+using entries in sysfs to maintain EFI variables. The old sysfs EFI
0854ddf
+variables code only supported variables of up to 1024 bytes. This
0854ddf
+limitation existed in version 0.99 of the EFI specification, but was
0854ddf
+removed before any full releases. Since variables can now be larger
0854ddf
+than a single page, sysfs isn't the best interface for this.
0854ddf
+
0854ddf
+Variables can be created, deleted and modified with the efivarfs
0854ddf
+filesystem.
0854ddf
+
0854ddf
+efivarfs is typically mounted like this,
0854ddf
+
0854ddf
+	mount -t efivarfs none /sys/firmware/efi/efivars
0854ddf
-- 
0854ddf
1.7.12.1
0854ddf
0854ddf
0854ddf
From 5897a97e56e999e3fe1d5b9d018496f2656f33fb Mon Sep 17 00:00:00 2001
0854ddf
From: Andy Whitcroft <apw@canonical.com>
0854ddf
Date: Thu, 11 Oct 2012 11:32:17 +0100
0854ddf
Subject: [PATCH 05/17] efivarfs: efivarfs_file_read ensure we free data in
0854ddf
 error paths
0854ddf
0854ddf
Signed-off-by: Andy Whitcroft <apw@canonical.com>
0854ddf
Acked-by: Matthew Garrett <mjg@redhat.com>
0854ddf
Acked-by: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
0854ddf
---
0854ddf
 drivers/firmware/efivars.c | 6 +++---
0854ddf
 1 file changed, 3 insertions(+), 3 deletions(-)
0854ddf
0854ddf
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
0854ddf
index 6793965..b7c9a32 100644
0854ddf
--- a/drivers/firmware/efivars.c
0854ddf
+++ b/drivers/firmware/efivars.c
0854ddf
@@ -766,7 +766,7 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
0854ddf
 	unsigned long datasize = 0;
0854ddf
 	u32 attributes;
0854ddf
 	void *data;
0854ddf
-	ssize_t size;
0854ddf
+	ssize_t size = 0;
0854ddf
 
0854ddf
 	status = efivars->ops->get_variable(var->var.VariableName,
0854ddf
 					    &var->var.VendorGuid,
0854ddf
@@ -784,13 +784,13 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
0854ddf
 					    &var->var.VendorGuid,
0854ddf
 					    &attributes, &datasize,
0854ddf
 					    (data + 4));
0854ddf
-
0854ddf
 	if (status != EFI_SUCCESS)
0854ddf
-		return 0;
0854ddf
+		goto out_free;
0854ddf
 
0854ddf
 	memcpy(data, &attributes, 4);
0854ddf
 	size = simple_read_from_buffer(userbuf, count, ppos,
0854ddf
 					data, datasize + 4);
0854ddf
+out_free:
0854ddf
 	kfree(data);
0854ddf
 
0854ddf
 	return size;
0854ddf
-- 
0854ddf
1.7.12.1
0854ddf
0854ddf
0854ddf
From e1f15611b82a3137949ec11b09a7c1230eec1b8e Mon Sep 17 00:00:00 2001
0854ddf
From: Andy Whitcroft <apw@canonical.com>
0854ddf
Date: Thu, 11 Oct 2012 11:32:18 +0100
0854ddf
Subject: [PATCH 06/17] efivarfs: efivarfs_create() ensure we drop our
0854ddf
 reference on inode on error
0854ddf
0854ddf
Signed-off-by: Andy Whitcroft <apw@canonical.com>
0854ddf
Acked-by: Matthew Garrett <mjg@redhat.com>
0854ddf
Acked-by: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
0854ddf
---
0854ddf
 drivers/firmware/efivars.c | 14 +++++++++-----
0854ddf
 1 file changed, 9 insertions(+), 5 deletions(-)
0854ddf
0854ddf
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
0854ddf
index b7c9a32..6e5f367 100644
0854ddf
--- a/drivers/firmware/efivars.c
0854ddf
+++ b/drivers/firmware/efivars.c
0854ddf
@@ -866,7 +866,7 @@ static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid)
0854ddf
 static int efivarfs_create(struct inode *dir, struct dentry *dentry,
0854ddf
 			  umode_t mode, bool excl)
0854ddf
 {
0854ddf
-	struct inode *inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0);
0854ddf
+	struct inode *inode;
0854ddf
 	struct efivars *efivars = &__efivars;
0854ddf
 	struct efivar_entry *var;
0854ddf
 	int namelen, i = 0, err = 0;
0854ddf
@@ -874,13 +874,15 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
0854ddf
 	if (dentry->d_name.len < 38)
0854ddf
 		return -EINVAL;
0854ddf
 
0854ddf
+	inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0);
0854ddf
 	if (!inode)
0854ddf
 		return -ENOSPC;
0854ddf
 
0854ddf
 	var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
0854ddf
-
0854ddf
-	if (!var)
0854ddf
-		return -ENOMEM;
0854ddf
+	if (!var) {
0854ddf
+		err = -ENOMEM;
0854ddf
+		goto out;
0854ddf
+	}
0854ddf
 
0854ddf
 	namelen = dentry->d_name.len - GUID_LEN;
0854ddf
 
0854ddf
@@ -908,8 +910,10 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
0854ddf
 	d_instantiate(dentry, inode);
0854ddf
 	dget(dentry);
0854ddf
 out:
0854ddf
-	if (err)
0854ddf
+	if (err) {
0854ddf
 		kfree(var);
0854ddf
+		iput(inode);
0854ddf
+	}
0854ddf
 	return err;
0854ddf
 }
0854ddf
 
0854ddf
-- 
0854ddf
1.7.12.1
0854ddf
0854ddf
0854ddf
From da03533239fd31112b355b2e1c1b8aa168a27440 Mon Sep 17 00:00:00 2001
0854ddf
From: Andy Whitcroft <apw@canonical.com>
0854ddf
Date: Thu, 11 Oct 2012 11:32:19 +0100
0854ddf
Subject: [PATCH 07/17] efivarfs: efivarfs_fill_super() fix inode reference
0854ddf
 counts
0854ddf
0854ddf
When d_make_root() fails it will automatically drop the reference
0854ddf
on the root inode.  We should not be doing so as well.
0854ddf
0854ddf
Signed-off-by: Andy Whitcroft <apw@canonical.com>
0854ddf
Acked-by: Matthew Garrett <mjg@redhat.com>
0854ddf
Acked-by: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
0854ddf
---
0854ddf
 drivers/firmware/efivars.c | 16 ++++------------
0854ddf
 1 file changed, 4 insertions(+), 12 deletions(-)
0854ddf
0854ddf
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
0854ddf
index 6e5f367..adfc486 100644
0854ddf
--- a/drivers/firmware/efivars.c
0854ddf
+++ b/drivers/firmware/efivars.c
0854ddf
@@ -948,7 +948,6 @@ int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
0854ddf
 	struct dentry *root;
0854ddf
 	struct efivar_entry *entry, *n;
0854ddf
 	struct efivars *efivars = &__efivars;
0854ddf
-	int err;
0854ddf
 
0854ddf
 	efivarfs_sb = sb;
0854ddf
 
0854ddf
@@ -960,18 +959,14 @@ int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
0854ddf
 	sb->s_time_gran         = 1;
0854ddf
 
0854ddf
 	inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0);
0854ddf
-	if (!inode) {
0854ddf
-		err = -ENOMEM;
0854ddf
-		goto fail;
0854ddf
-	}
0854ddf
+	if (!inode)
0854ddf
+		return -ENOMEM;
0854ddf
 	inode->i_op = &efivarfs_dir_inode_operations;
0854ddf
 
0854ddf
 	root = d_make_root(inode);
0854ddf
 	sb->s_root = root;
0854ddf
-	if (!root) {
0854ddf
-		err = -ENOMEM;
0854ddf
-		goto fail;
0854ddf
-	}
0854ddf
+	if (!root)
0854ddf
+		return -ENOMEM;
0854ddf
 
0854ddf
 	list_for_each_entry_safe(entry, n, &efivars->list, list) {
0854ddf
 		struct inode *inode;
0854ddf
@@ -1012,9 +1007,6 @@ int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
0854ddf
 	}
0854ddf
 
0854ddf
 	return 0;
0854ddf
-fail:
0854ddf
-	iput(inode);
0854ddf
-	return err;
0854ddf
 }
0854ddf
 
0854ddf
 static struct dentry *efivarfs_mount(struct file_system_type *fs_type,
0854ddf
-- 
0854ddf
1.7.12.1
0854ddf
0854ddf
0854ddf
From 2e2b7d34a6b3b4534165d5cc22705b3c60e48f0a Mon Sep 17 00:00:00 2001
0854ddf
From: Andy Whitcroft <apw@canonical.com>
0854ddf
Date: Thu, 11 Oct 2012 11:32:20 +0100
0854ddf
Subject: [PATCH 08/17] efivarfs: efivarfs_fill_super() ensure we free our
0854ddf
 temporary name
0854ddf
0854ddf
d_alloc_name() copies the passed name to new storage, once complete we
0854ddf
no longer need our name.
0854ddf
0854ddf
Signed-off-by: Andy Whitcroft <apw@canonical.com>
0854ddf
Acked-by: Matthew Garrett <mjg@redhat.com>
0854ddf
Acked-by: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
0854ddf
---
0854ddf
 drivers/firmware/efivars.c | 2 ++
0854ddf
 1 file changed, 2 insertions(+)
0854ddf
0854ddf
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
0854ddf
index adfc486..36b3dd6 100644
0854ddf
--- a/drivers/firmware/efivars.c
0854ddf
+++ b/drivers/firmware/efivars.c
0854ddf
@@ -992,6 +992,8 @@ int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
0854ddf
 		inode = efivarfs_get_inode(efivarfs_sb, root->d_inode,
0854ddf
 					  S_IFREG | 0644, 0);
0854ddf
 		dentry = d_alloc_name(root, name);
0854ddf
+		/* copied by the above to local storage in the dentry. */
0854ddf
+		kfree(name);
0854ddf
 
0854ddf
 		efivars->ops->get_variable(entry->var.VariableName,
0854ddf
 					   &entry->var.VendorGuid,
0854ddf
-- 
0854ddf
1.7.12.1
0854ddf
0854ddf
0854ddf
From 247fd819a9fa1920ed7149bdbe13a16beb0ad44f Mon Sep 17 00:00:00 2001
0854ddf
From: Andy Whitcroft <apw@canonical.com>
0854ddf
Date: Thu, 11 Oct 2012 11:32:21 +0100
0854ddf
Subject: [PATCH 09/17] efivarfs: efivarfs_fill_super() ensure we clean up
0854ddf
 correctly on error
0854ddf
0854ddf
Ensure we free both the name and inode on error when building the
0854ddf
individual variables.
0854ddf
0854ddf
Signed-off-by: Andy Whitcroft <apw@canonical.com>
0854ddf
Acked-by: Matthew Garrett <mjg@redhat.com>
0854ddf
Acked-by: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
0854ddf
---
0854ddf
 drivers/firmware/efivars.c | 20 ++++++++++++++++++--
0854ddf
 1 file changed, 18 insertions(+), 2 deletions(-)
0854ddf
0854ddf
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
0854ddf
index 36b3dd6..216086d 100644
0854ddf
--- a/drivers/firmware/efivars.c
0854ddf
+++ b/drivers/firmware/efivars.c
0854ddf
@@ -948,6 +948,7 @@ int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
0854ddf
 	struct dentry *root;
0854ddf
 	struct efivar_entry *entry, *n;
0854ddf
 	struct efivars *efivars = &__efivars;
0854ddf
+	char *name;
0854ddf
 
0854ddf
 	efivarfs_sb = sb;
0854ddf
 
0854ddf
@@ -969,16 +970,18 @@ int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
0854ddf
 		return -ENOMEM;
0854ddf
 
0854ddf
 	list_for_each_entry_safe(entry, n, &efivars->list, list) {
0854ddf
-		struct inode *inode;
0854ddf
 		struct dentry *dentry, *root = efivarfs_sb->s_root;
0854ddf
-		char *name;
0854ddf
 		unsigned long size = 0;
0854ddf
 		int len, i;
0854ddf
 
0854ddf
+		inode = NULL;
0854ddf
+
0854ddf
 		len = utf16_strlen(entry->var.VariableName);
0854ddf
 
0854ddf
 		/* GUID plus trailing NULL */
0854ddf
 		name = kmalloc(len + 38, GFP_ATOMIC);
0854ddf
+		if (!name)
0854ddf
+			goto fail;
0854ddf
 
0854ddf
 		for (i = 0; i < len; i++)
0854ddf
 			name[i] = entry->var.VariableName[i] & 0xFF;
0854ddf
@@ -991,7 +994,13 @@ int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
0854ddf
 
0854ddf
 		inode = efivarfs_get_inode(efivarfs_sb, root->d_inode,
0854ddf
 					  S_IFREG | 0644, 0);
0854ddf
+		if (!inode)
0854ddf
+			goto fail_name;
0854ddf
+
0854ddf
 		dentry = d_alloc_name(root, name);
0854ddf
+		if (!dentry)
0854ddf
+			goto fail_inode;
0854ddf
+
0854ddf
 		/* copied by the above to local storage in the dentry. */
0854ddf
 		kfree(name);
0854ddf
 
0854ddf
@@ -1009,6 +1018,13 @@ int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
0854ddf
 	}
0854ddf
 
0854ddf
 	return 0;
0854ddf
+
0854ddf
+fail_inode:
0854ddf
+	iput(inode);
0854ddf
+fail_name:
0854ddf
+	kfree(name);
0854ddf
+fail:
0854ddf
+	return -ENOMEM;
0854ddf
 }
0854ddf
 
0854ddf
 static struct dentry *efivarfs_mount(struct file_system_type *fs_type,
0854ddf
-- 
0854ddf
1.7.12.1
0854ddf
0854ddf
0854ddf
From 01eb8510eb659fd1471d92166bfd7a4d939b2b21 Mon Sep 17 00:00:00 2001
0854ddf
From: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Date: Thu, 11 Oct 2012 21:19:11 +0800
0854ddf
Subject: [PATCH 10/17] efivarfs: Implement exclusive access for
0854ddf
 {get,set}_variable
0854ddf
0854ddf
Currently, efivarfs does not enforce exclusion over the get_variable and
0854ddf
set_variable operations. Section 7.1 of UEFI requires us to only allow a
0854ddf
single processor to enter {get,set}_variable services at once.
0854ddf
0854ddf
This change acquires the efivars->lock over calls to these operations
0854ddf
from the efivarfs paths.
0854ddf
0854ddf
Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
0854ddf
---
0854ddf
 drivers/firmware/efivars.c | 68 +++++++++++++++++++++++++++++-----------------
0854ddf
 1 file changed, 43 insertions(+), 25 deletions(-)
0854ddf
0854ddf
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
0854ddf
index 216086d..d478c56 100644
0854ddf
--- a/drivers/firmware/efivars.c
0854ddf
+++ b/drivers/firmware/efivars.c
0854ddf
@@ -690,35 +690,45 @@ static ssize_t efivarfs_file_write(struct file *file,
0854ddf
 		goto out;
0854ddf
 	}
0854ddf
 
0854ddf
+	/*
0854ddf
+	 * The lock here protects the get_variable call, the conditional
0854ddf
+	 * set_variable call, and removal of the variable from the efivars
0854ddf
+	 * list (in the case of an authenticated delete).
0854ddf
+	 */
0854ddf
+	spin_lock(&efivars->lock);
0854ddf
+
0854ddf
 	status = efivars->ops->set_variable(var->var.VariableName,
0854ddf
 					    &var->var.VendorGuid,
0854ddf
 					    attributes, datasize,
0854ddf
 					    data);
0854ddf
 
0854ddf
-	switch (status) {
0854ddf
-	case EFI_SUCCESS:
0854ddf
-		break;
0854ddf
-	case EFI_INVALID_PARAMETER:
0854ddf
-		count = -EINVAL;
0854ddf
-		goto out;
0854ddf
-	case EFI_OUT_OF_RESOURCES:
0854ddf
-		count = -ENOSPC;
0854ddf
-		goto out;
0854ddf
-	case EFI_DEVICE_ERROR:
0854ddf
-		count = -EIO;
0854ddf
-		goto out;
0854ddf
-	case EFI_WRITE_PROTECTED:
0854ddf
-		count = -EROFS;
0854ddf
-		goto out;
0854ddf
-	case EFI_SECURITY_VIOLATION:
0854ddf
-		count = -EACCES;
0854ddf
-		goto out;
0854ddf
-	case EFI_NOT_FOUND:
0854ddf
-		count = -ENOENT;
0854ddf
-		goto out;
0854ddf
-	default:
0854ddf
-		count = -EINVAL;
0854ddf
-		goto out;
0854ddf
+	if (status != EFI_SUCCESS) {
0854ddf
+		spin_unlock(&efivars->lock);
0854ddf
+		kfree(data);
0854ddf
+
0854ddf
+		switch (status) {
0854ddf
+		case EFI_INVALID_PARAMETER:
0854ddf
+			count = -EINVAL;
0854ddf
+			break;
0854ddf
+		case EFI_OUT_OF_RESOURCES:
0854ddf
+			count = -ENOSPC;
0854ddf
+			break;
0854ddf
+		case EFI_DEVICE_ERROR:
0854ddf
+			count = -EIO;
0854ddf
+			break;
0854ddf
+		case EFI_WRITE_PROTECTED:
0854ddf
+			count = -EROFS;
0854ddf
+			break;
0854ddf
+		case EFI_SECURITY_VIOLATION:
0854ddf
+			count = -EACCES;
0854ddf
+			break;
0854ddf
+		case EFI_NOT_FOUND:
0854ddf
+			count = -ENOENT;
0854ddf
+			break;
0854ddf
+		default:
0854ddf
+			count = -EINVAL;
0854ddf
+		}
0854ddf
+		return count;
0854ddf
 	}
0854ddf
 
0854ddf
 	/*
0854ddf
@@ -734,12 +744,12 @@ static ssize_t efivarfs_file_write(struct file *file,
0854ddf
 					    NULL);
0854ddf
 
0854ddf
 	if (status == EFI_BUFFER_TOO_SMALL) {
0854ddf
+		spin_unlock(&efivars->lock);
0854ddf
 		mutex_lock(&inode->i_mutex);
0854ddf
 		i_size_write(inode, newdatasize + sizeof(attributes));
0854ddf
 		mutex_unlock(&inode->i_mutex);
0854ddf
 
0854ddf
 	} else if (status == EFI_NOT_FOUND) {
0854ddf
-		spin_lock(&efivars->lock);
0854ddf
 		list_del(&var->list);
0854ddf
 		spin_unlock(&efivars->lock);
0854ddf
 		efivar_unregister(var);
0854ddf
@@ -747,6 +757,7 @@ static ssize_t efivarfs_file_write(struct file *file,
0854ddf
 		dput(file->f_dentry);
0854ddf
 
0854ddf
 	} else {
0854ddf
+		spin_unlock(&efivars->lock);
0854ddf
 		pr_warn("efivarfs: inconsistent EFI variable implementation? "
0854ddf
 				"status = %lx\n", status);
0854ddf
 	}
0854ddf
@@ -768,9 +779,11 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
0854ddf
 	void *data;
0854ddf
 	ssize_t size = 0;
0854ddf
 
0854ddf
+	spin_lock(&efivars->lock);
0854ddf
 	status = efivars->ops->get_variable(var->var.VariableName,
0854ddf
 					    &var->var.VendorGuid,
0854ddf
 					    &attributes, &datasize, NULL);
0854ddf
+	spin_unlock(&efivars->lock);
0854ddf
 
0854ddf
 	if (status != EFI_BUFFER_TOO_SMALL)
0854ddf
 		return 0;
0854ddf
@@ -780,10 +793,13 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
0854ddf
 	if (!data)
0854ddf
 		return 0;
0854ddf
 
0854ddf
+	spin_lock(&efivars->lock);
0854ddf
 	status = efivars->ops->get_variable(var->var.VariableName,
0854ddf
 					    &var->var.VendorGuid,
0854ddf
 					    &attributes, &datasize,
0854ddf
 					    (data + 4));
0854ddf
+	spin_unlock(&efivars->lock);
0854ddf
+
0854ddf
 	if (status != EFI_SUCCESS)
0854ddf
 		goto out_free;
0854ddf
 
0854ddf
@@ -1004,11 +1020,13 @@ int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
0854ddf
 		/* copied by the above to local storage in the dentry. */
0854ddf
 		kfree(name);
0854ddf
 
0854ddf
+		spin_lock(&efivars->lock);
0854ddf
 		efivars->ops->get_variable(entry->var.VariableName,
0854ddf
 					   &entry->var.VendorGuid,
0854ddf
 					   &entry->var.Attributes,
0854ddf
 					   &size,
0854ddf
 					   NULL);
0854ddf
+		spin_unlock(&efivars->lock);
0854ddf
 
0854ddf
 		mutex_lock(&inode->i_mutex);
0854ddf
 		inode->i_private = entry;
0854ddf
-- 
0854ddf
1.7.12.1
0854ddf
0854ddf
0854ddf
From 871a36dd8509c2833d02930d6f166a65f85c4f92 Mon Sep 17 00:00:00 2001
0854ddf
From: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Date: Fri, 19 Oct 2012 15:16:45 +0800
0854ddf
Subject: [PATCH 11/17] efi: Clarify GUID length calculations
0854ddf
0854ddf
At present, the handling of GUIDs in efivar file names isn't consistent.
0854ddf
We use GUID_LEN in some places, and 38 in others (GUID_LEN plus
0854ddf
separator), and implicitly use the presence of the trailing NUL.
0854ddf
0854ddf
This change removes the trailing NUL from GUID_LEN, so that we're
0854ddf
explicitly adding it when required. We also replace magic numbers
0854ddf
with GUID_LEN, and clarify the comments where appropriate.
0854ddf
0854ddf
We also fix the allocation size in efivar_create_sysfs_entry, where
0854ddf
we're allocating one byte too much, due to counting the trailing NUL
0854ddf
twice - once when calculating short_name_size, and once in the kzalloc.
0854ddf
0854ddf
Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
0854ddf
---
0854ddf
 drivers/firmware/efivars.c | 33 +++++++++++++++++++++++++--------
0854ddf
 1 file changed, 25 insertions(+), 8 deletions(-)
0854ddf
0854ddf
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
0854ddf
index d478c56..a93e401 100644
0854ddf
--- a/drivers/firmware/efivars.c
0854ddf
+++ b/drivers/firmware/efivars.c
0854ddf
@@ -95,7 +95,12 @@ MODULE_LICENSE("GPL");
0854ddf
 MODULE_VERSION(EFIVARS_VERSION);
0854ddf
 
0854ddf
 #define DUMP_NAME_LEN 52
0854ddf
-#define GUID_LEN 37
0854ddf
+
0854ddf
+/*
0854ddf
+ * Length of a GUID string (strlen("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"))
0854ddf
+ * not including trailing NUL
0854ddf
+ */
0854ddf
+#define GUID_LEN 36
0854ddf
 
0854ddf
 /*
0854ddf
  * The maximum size of VariableName + Data = 1024
0854ddf
@@ -887,7 +892,11 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
0854ddf
 	struct efivar_entry *var;
0854ddf
 	int namelen, i = 0, err = 0;
0854ddf
 
0854ddf
-	if (dentry->d_name.len < 38)
0854ddf
+	/*
0854ddf
+	 * We need a GUID, plus at least one letter for the variable name,
0854ddf
+	 * plus the '-' separator
0854ddf
+	 */
0854ddf
+	if (dentry->d_name.len < GUID_LEN + 2)
0854ddf
 		return -EINVAL;
0854ddf
 
0854ddf
 	inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0);
0854ddf
@@ -900,7 +909,8 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
0854ddf
 		goto out;
0854ddf
 	}
0854ddf
 
0854ddf
-	namelen = dentry->d_name.len - GUID_LEN;
0854ddf
+	/* length of the variable name itself: remove GUID and separator */
0854ddf
+	namelen = dentry->d_name.len - GUID_LEN - 1;
0854ddf
 
0854ddf
 	efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1,
0854ddf
 			&var->var.VendorGuid);
0854ddf
@@ -994,8 +1004,8 @@ int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
0854ddf
 
0854ddf
 		len = utf16_strlen(entry->var.VariableName);
0854ddf
 
0854ddf
-		/* GUID plus trailing NULL */
0854ddf
-		name = kmalloc(len + 38, GFP_ATOMIC);
0854ddf
+		/* name, plus '-', plus GUID, plus NUL*/
0854ddf
+		name = kmalloc(len + 1 + GUID_LEN + 1, GFP_ATOMIC);
0854ddf
 		if (!name)
0854ddf
 			goto fail;
0854ddf
 
0854ddf
@@ -1006,7 +1016,7 @@ int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
0854ddf
 
0854ddf
 		efi_guid_unparse(&entry->var.VendorGuid, name + len + 1);
0854ddf
 
0854ddf
-		name[len+GUID_LEN] = '\0';
0854ddf
+		name[len+GUID_LEN+1] = '\0';
0854ddf
 
0854ddf
 		inode = efivarfs_get_inode(efivarfs_sb, root->d_inode,
0854ddf
 					  S_IFREG | 0644, 0);
0854ddf
@@ -1435,11 +1445,18 @@ efivar_create_sysfs_entry(struct efivars *efivars,
0854ddf
 			  efi_char16_t *variable_name,
0854ddf
 			  efi_guid_t *vendor_guid)
0854ddf
 {
0854ddf
-	int i, short_name_size = variable_name_size / sizeof(efi_char16_t) + 38;
0854ddf
+	int i, short_name_size;
0854ddf
 	char *short_name;
0854ddf
 	struct efivar_entry *new_efivar;
0854ddf
 
0854ddf
-	short_name = kzalloc(short_name_size + 1, GFP_KERNEL);
0854ddf
+	/*
0854ddf
+	 * Length of the variable bytes in ASCII, plus the '-' separator,
0854ddf
+	 * plus the GUID, plus trailing NUL
0854ddf
+	 */
0854ddf
+	short_name_size = variable_name_size / sizeof(efi_char16_t)
0854ddf
+				+ 1 + GUID_LEN + 1;
0854ddf
+
0854ddf
+	short_name = kzalloc(short_name_size, GFP_KERNEL);
0854ddf
 	new_efivar = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
0854ddf
 
0854ddf
 	if (!short_name || !new_efivar)  {
0854ddf
-- 
0854ddf
1.7.12.1
0854ddf
0854ddf
0854ddf
From 5d2cf34731c10e035387ae65f6cf461fd7a53304 Mon Sep 17 00:00:00 2001
0854ddf
From: Matt Fleming <matt.fleming@intel.com>
0854ddf
Date: Tue, 16 Oct 2012 15:58:07 +0100
0854ddf
Subject: [PATCH 12/17] efivarfs: Return an error if we fail to read a
0854ddf
 variable
0854ddf
0854ddf
Instead of always returning 0 in efivarfs_file_read(), even when we
0854ddf
fail to successfully read the variable, convert the EFI status to
0854ddf
something meaningful and return that to the caller. This way the user
0854ddf
will have some hint as to why the read failed.
0854ddf
0854ddf
Acked-by: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
0854ddf
---
0854ddf
 drivers/firmware/efivars.c | 62 +++++++++++++++++++++++++++-------------------
0854ddf
 1 file changed, 36 insertions(+), 26 deletions(-)
0854ddf
0854ddf
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
0854ddf
index a93e401..277e426 100644
0854ddf
--- a/drivers/firmware/efivars.c
0854ddf
+++ b/drivers/firmware/efivars.c
0854ddf
@@ -653,6 +653,36 @@ static int efivarfs_file_open(struct inode *inode, struct file *file)
0854ddf
 	return 0;
0854ddf
 }
0854ddf
 
0854ddf
+static int efi_status_to_err(efi_status_t status)
0854ddf
+{
0854ddf
+	int err;
0854ddf
+
0854ddf
+	switch (status) {
0854ddf
+	case EFI_INVALID_PARAMETER:
0854ddf
+		err = -EINVAL;
0854ddf
+		break;
0854ddf
+	case EFI_OUT_OF_RESOURCES:
0854ddf
+		err = -ENOSPC;
0854ddf
+		break;
0854ddf
+	case EFI_DEVICE_ERROR:
0854ddf
+		err = -EIO;
0854ddf
+		break;
0854ddf
+	case EFI_WRITE_PROTECTED:
0854ddf
+		err = -EROFS;
0854ddf
+		break;
0854ddf
+	case EFI_SECURITY_VIOLATION:
0854ddf
+		err = -EACCES;
0854ddf
+		break;
0854ddf
+	case EFI_NOT_FOUND:
0854ddf
+		err = -ENOENT;
0854ddf
+		break;
0854ddf
+	default:
0854ddf
+		err = -EINVAL;
0854ddf
+	}
0854ddf
+
0854ddf
+	return err;
0854ddf
+}
0854ddf
+
0854ddf
 static ssize_t efivarfs_file_write(struct file *file,
0854ddf
 		const char __user *userbuf, size_t count, loff_t *ppos)
0854ddf
 {
0854ddf
@@ -711,29 +741,7 @@ static ssize_t efivarfs_file_write(struct file *file,
0854ddf
 		spin_unlock(&efivars->lock);
0854ddf
 		kfree(data);
0854ddf
 
0854ddf
-		switch (status) {
0854ddf
-		case EFI_INVALID_PARAMETER:
0854ddf
-			count = -EINVAL;
0854ddf
-			break;
0854ddf
-		case EFI_OUT_OF_RESOURCES:
0854ddf
-			count = -ENOSPC;
0854ddf
-			break;
0854ddf
-		case EFI_DEVICE_ERROR:
0854ddf
-			count = -EIO;
0854ddf
-			break;
0854ddf
-		case EFI_WRITE_PROTECTED:
0854ddf
-			count = -EROFS;
0854ddf
-			break;
0854ddf
-		case EFI_SECURITY_VIOLATION:
0854ddf
-			count = -EACCES;
0854ddf
-			break;
0854ddf
-		case EFI_NOT_FOUND:
0854ddf
-			count = -ENOENT;
0854ddf
-			break;
0854ddf
-		default:
0854ddf
-			count = -EINVAL;
0854ddf
-		}
0854ddf
-		return count;
0854ddf
+		return efi_status_to_err(status);
0854ddf
 	}
0854ddf
 
0854ddf
 	/*
0854ddf
@@ -791,12 +799,12 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
0854ddf
 	spin_unlock(&efivars->lock);
0854ddf
 
0854ddf
 	if (status != EFI_BUFFER_TOO_SMALL)
0854ddf
-		return 0;
0854ddf
+		return efi_status_to_err(status);
0854ddf
 
0854ddf
 	data = kmalloc(datasize + 4, GFP_KERNEL);
0854ddf
 
0854ddf
 	if (!data)
0854ddf
-		return 0;
0854ddf
+		return -ENOMEM;
0854ddf
 
0854ddf
 	spin_lock(&efivars->lock);
0854ddf
 	status = efivars->ops->get_variable(var->var.VariableName,
0854ddf
@@ -805,8 +813,10 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
0854ddf
 					    (data + 4));
0854ddf
 	spin_unlock(&efivars->lock);
0854ddf
 
0854ddf
-	if (status != EFI_SUCCESS)
0854ddf
+	if (status != EFI_SUCCESS) {
0854ddf
+		size = efi_status_to_err(status);
0854ddf
 		goto out_free;
0854ddf
+	}
0854ddf
 
0854ddf
 	memcpy(data, &attributes, 4);
0854ddf
 	size = simple_read_from_buffer(userbuf, count, ppos,
0854ddf
-- 
0854ddf
1.7.12.1
0854ddf
0854ddf
0854ddf
From 0bdf9e5f271f74b7079d8bd06aea7973ffa43562 Mon Sep 17 00:00:00 2001
0854ddf
From: Matt Fleming <matt.fleming@intel.com>
0854ddf
Date: Mon, 22 Oct 2012 15:23:29 +0100
0854ddf
Subject: [PATCH 13/17] efivarfs: Replace magic number with sizeof(attributes)
0854ddf
0854ddf
Seeing "+ 4" littered throughout the functions gets a bit
0854ddf
confusing. Use "sizeof(attributes)" which clearly explains what
0854ddf
quantity we're adding.
0854ddf
0854ddf
Acked-by: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
0854ddf
---
0854ddf
 drivers/firmware/efivars.c | 8 ++++----
0854ddf
 1 file changed, 4 insertions(+), 4 deletions(-)
0854ddf
0854ddf
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
0854ddf
index 277e426..2c04434 100644
0854ddf
--- a/drivers/firmware/efivars.c
0854ddf
+++ b/drivers/firmware/efivars.c
0854ddf
@@ -801,7 +801,7 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
0854ddf
 	if (status != EFI_BUFFER_TOO_SMALL)
0854ddf
 		return efi_status_to_err(status);
0854ddf
 
0854ddf
-	data = kmalloc(datasize + 4, GFP_KERNEL);
0854ddf
+	data = kmalloc(datasize + sizeof(attributes), GFP_KERNEL);
0854ddf
 
0854ddf
 	if (!data)
0854ddf
 		return -ENOMEM;
0854ddf
@@ -810,7 +810,7 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
0854ddf
 	status = efivars->ops->get_variable(var->var.VariableName,
0854ddf
 					    &var->var.VendorGuid,
0854ddf
 					    &attributes, &datasize,
0854ddf
-					    (data + 4));
0854ddf
+					    (data + sizeof(attributes)));
0854ddf
 	spin_unlock(&efivars->lock);
0854ddf
 
0854ddf
 	if (status != EFI_SUCCESS) {
0854ddf
@@ -818,9 +818,9 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
0854ddf
 		goto out_free;
0854ddf
 	}
0854ddf
 
0854ddf
-	memcpy(data, &attributes, 4);
0854ddf
+	memcpy(data, &attributes, sizeof(attributes));
0854ddf
 	size = simple_read_from_buffer(userbuf, count, ppos,
0854ddf
-					data, datasize + 4);
0854ddf
+				       data, datasize + sizeof(attributes));
0854ddf
 out_free:
0854ddf
 	kfree(data);
0854ddf
 
0854ddf
-- 
0854ddf
1.7.12.1
0854ddf
0854ddf
0854ddf
From 2835e3a8a7774d72c3e82b6f5350b4c6750c07db Mon Sep 17 00:00:00 2001
0854ddf
From: Matt Fleming <matt.fleming@intel.com>
0854ddf
Date: Mon, 22 Oct 2012 15:51:45 +0100
0854ddf
Subject: [PATCH 14/17] efivarfs: Add unique magic number
0854ddf
0854ddf
Using pstore's superblock magic number is no doubt going to cause
0854ddf
problems in the future. Give efivarfs its own magic number.
0854ddf
0854ddf
Acked-by: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
0854ddf
---
0854ddf
 drivers/firmware/efivars.c | 2 +-
0854ddf
 include/linux/magic.h      | 1 +
0854ddf
 2 files changed, 2 insertions(+), 1 deletion(-)
0854ddf
0854ddf
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
0854ddf
index 2c04434..3b0cf9a 100644
0854ddf
--- a/drivers/firmware/efivars.c
0854ddf
+++ b/drivers/firmware/efivars.c
0854ddf
@@ -991,7 +991,7 @@ int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
0854ddf
 	sb->s_maxbytes          = MAX_LFS_FILESIZE;
0854ddf
 	sb->s_blocksize         = PAGE_CACHE_SIZE;
0854ddf
 	sb->s_blocksize_bits    = PAGE_CACHE_SHIFT;
0854ddf
-	sb->s_magic             = PSTOREFS_MAGIC;
0854ddf
+	sb->s_magic             = EFIVARFS_MAGIC;
0854ddf
 	sb->s_op                = &efivarfs_ops;
0854ddf
 	sb->s_time_gran         = 1;
0854ddf
 
0854ddf
diff --git a/include/linux/magic.h b/include/linux/magic.h
0854ddf
index e15192c..12f68c7 100644
0854ddf
--- a/include/linux/magic.h
0854ddf
+++ b/include/linux/magic.h
0854ddf
@@ -27,6 +27,7 @@
0854ddf
 #define ISOFS_SUPER_MAGIC	0x9660
0854ddf
 #define JFFS2_SUPER_MAGIC	0x72b6
0854ddf
 #define PSTOREFS_MAGIC		0x6165676C
0854ddf
+#define EFIVARFS_MAGIC		0xde5e81e4
0854ddf
 
0854ddf
 #define MINIX_SUPER_MAGIC	0x137F		/* minix v1 fs, 14 char names */
0854ddf
 #define MINIX_SUPER_MAGIC2	0x138F		/* minix v1 fs, 30 char names */
0854ddf
-- 
0854ddf
1.7.12.1
0854ddf
0854ddf
0854ddf
From 6cd03d922cfcdf802a0b7cb28a2d12b85064e1cf Mon Sep 17 00:00:00 2001
0854ddf
From: Matt Fleming <matt.fleming@intel.com>
0854ddf
Date: Tue, 23 Oct 2012 12:35:43 +0100
0854ddf
Subject: [PATCH 15/17] efivarfs: Make 'datasize' unsigned long
0854ddf
0854ddf
There's no reason to declare 'datasize' as an int, since the majority
0854ddf
of the functions it's passed to expect an unsigned long anyway. Plus,
0854ddf
this way we avoid any sign problems during arithmetic.
0854ddf
0854ddf
Acked-by: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
0854ddf
---
0854ddf
 drivers/firmware/efivars.c | 2 +-
0854ddf
 1 file changed, 1 insertion(+), 1 deletion(-)
0854ddf
0854ddf
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
0854ddf
index 3b0cf9a..6a858d1 100644
0854ddf
--- a/drivers/firmware/efivars.c
0854ddf
+++ b/drivers/firmware/efivars.c
0854ddf
@@ -692,7 +692,7 @@ static ssize_t efivarfs_file_write(struct file *file,
0854ddf
 	void *data;
0854ddf
 	u32 attributes;
0854ddf
 	struct inode *inode = file->f_mapping->host;
0854ddf
-	int datasize = count - sizeof(attributes);
0854ddf
+	unsigned long datasize = count - sizeof(attributes);
0854ddf
 	unsigned long newdatasize;
0854ddf
 
0854ddf
 	if (count < sizeof(attributes))
0854ddf
-- 
0854ddf
1.7.12.1
0854ddf
0854ddf
0854ddf
From b96ed46670ff62693e169066da6c44014b487da6 Mon Sep 17 00:00:00 2001
0854ddf
From: Matt Fleming <matt.fleming@intel.com>
0854ddf
Date: Tue, 23 Oct 2012 12:41:03 +0100
0854ddf
Subject: [PATCH 16/17] efivarfs: Return a consistent error when
0854ddf
 efivarfs_get_inode() fails
0854ddf
0854ddf
Instead of returning -ENOSPC if efivarfs_get_inode() fails we should
0854ddf
be returning -ENOMEM, since running out of memory is the only reason
0854ddf
it can fail.  Furthermore, that's the error value used everywhere else
0854ddf
in this file. It's also less likely to confuse users that hit this
0854ddf
error case.
0854ddf
0854ddf
Acked-by: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
0854ddf
---
0854ddf
 drivers/firmware/efivars.c | 2 +-
0854ddf
 1 file changed, 1 insertion(+), 1 deletion(-)
0854ddf
0854ddf
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
0854ddf
index 6a858d1..58cec62 100644
0854ddf
--- a/drivers/firmware/efivars.c
0854ddf
+++ b/drivers/firmware/efivars.c
0854ddf
@@ -911,7 +911,7 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
0854ddf
 
0854ddf
 	inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0);
0854ddf
 	if (!inode)
0854ddf
-		return -ENOSPC;
0854ddf
+		return -ENOMEM;
0854ddf
 
0854ddf
 	var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
0854ddf
 	if (!var) {
0854ddf
-- 
0854ddf
1.7.12.1
0854ddf
0854ddf
0854ddf
From d537167e87d99d6fffa04f7f36de80a9bc7ffd4f Mon Sep 17 00:00:00 2001
0854ddf
From: Matt Fleming <matt.fleming@intel.com>
0854ddf
Date: Fri, 26 Oct 2012 12:18:53 +0100
0854ddf
Subject: [PATCH 17/17] efivarfs: Fix return value of efivarfs_file_write()
0854ddf
0854ddf
We're stuffing a variable of type size_t (unsigned) into a ssize_t
0854ddf
(signed) which, even though both types should be the same number of
0854ddf
bits, it's just asking for sign issues to be introduced.
0854ddf
0854ddf
Cc: Jeremy Kerr <jeremy.kerr@canonical.com>
0854ddf
Reported-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
0854ddf
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
0854ddf
---
0854ddf
 drivers/firmware/efivars.c | 13 ++++++++-----
0854ddf
 1 file changed, 8 insertions(+), 5 deletions(-)
0854ddf
0854ddf
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
0854ddf
index 58cec62..9ac9340 100644
0854ddf
--- a/drivers/firmware/efivars.c
0854ddf
+++ b/drivers/firmware/efivars.c
0854ddf
@@ -694,6 +694,7 @@ static ssize_t efivarfs_file_write(struct file *file,
0854ddf
 	struct inode *inode = file->f_mapping->host;
0854ddf
 	unsigned long datasize = count - sizeof(attributes);
0854ddf
 	unsigned long newdatasize;
0854ddf
+	ssize_t bytes = 0;
0854ddf
 
0854ddf
 	if (count < sizeof(attributes))
0854ddf
 		return -EINVAL;
0854ddf
@@ -706,22 +707,22 @@ static ssize_t efivarfs_file_write(struct file *file,
0854ddf
 	efivars = var->efivars;
0854ddf
 
0854ddf
 	if (copy_from_user(&attributes, userbuf, sizeof(attributes))) {
0854ddf
-		count = -EFAULT;
0854ddf
+		bytes = -EFAULT;
0854ddf
 		goto out;
0854ddf
 	}
0854ddf
 
0854ddf
 	if (attributes & ~(EFI_VARIABLE_MASK)) {
0854ddf
-		count = -EINVAL;
0854ddf
+		bytes = -EINVAL;
0854ddf
 		goto out;
0854ddf
 	}
0854ddf
 
0854ddf
 	if (copy_from_user(data, userbuf + sizeof(attributes), datasize)) {
0854ddf
-		count = -EFAULT;
0854ddf
+		bytes = -EFAULT;
0854ddf
 		goto out;
0854ddf
 	}
0854ddf
 
0854ddf
 	if (validate_var(&var->var, data, datasize) == false) {
0854ddf
-		count = -EINVAL;
0854ddf
+		bytes = -EINVAL;
0854ddf
 		goto out;
0854ddf
 	}
0854ddf
 
0854ddf
@@ -744,6 +745,8 @@ static ssize_t efivarfs_file_write(struct file *file,
0854ddf
 		return efi_status_to_err(status);
0854ddf
 	}
0854ddf
 
0854ddf
+	bytes = count;
0854ddf
+
0854ddf
 	/*
0854ddf
 	 * Writing to the variable may have caused a change in size (which
0854ddf
 	 * could either be an append or an overwrite), or the variable to be
0854ddf
@@ -778,7 +781,7 @@ static ssize_t efivarfs_file_write(struct file *file,
0854ddf
 out:
0854ddf
 	kfree(data);
0854ddf
 
0854ddf
-	return count;
0854ddf
+	return bytes;
0854ddf
 }
0854ddf
 
0854ddf
 static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
0854ddf
-- 
0854ddf
1.7.12.1
0854ddf