0001
0002
0003
0004
0005
0006
0007 #include <linux/efi.h>
0008 #include <linux/delay.h>
0009 #include <linux/fs.h>
0010 #include <linux/slab.h>
0011 #include <linux/mount.h>
0012
0013 #include "internal.h"
0014
0015 static ssize_t efivarfs_file_write(struct file *file,
0016 const char __user *userbuf, size_t count, loff_t *ppos)
0017 {
0018 struct efivar_entry *var = file->private_data;
0019 void *data;
0020 u32 attributes;
0021 struct inode *inode = file->f_mapping->host;
0022 unsigned long datasize = count - sizeof(attributes);
0023 ssize_t bytes;
0024 bool set = false;
0025
0026 if (count < sizeof(attributes))
0027 return -EINVAL;
0028
0029 if (copy_from_user(&attributes, userbuf, sizeof(attributes)))
0030 return -EFAULT;
0031
0032 if (attributes & ~(EFI_VARIABLE_MASK))
0033 return -EINVAL;
0034
0035 data = memdup_user(userbuf + sizeof(attributes), datasize);
0036 if (IS_ERR(data))
0037 return PTR_ERR(data);
0038
0039 bytes = efivar_entry_set_get_size(var, attributes, &datasize,
0040 data, &set);
0041 if (!set && bytes) {
0042 if (bytes == -ENOENT)
0043 bytes = -EIO;
0044 goto out;
0045 }
0046
0047 if (bytes == -ENOENT) {
0048 drop_nlink(inode);
0049 d_delete(file->f_path.dentry);
0050 dput(file->f_path.dentry);
0051 } else {
0052 inode_lock(inode);
0053 i_size_write(inode, datasize + sizeof(attributes));
0054 inode->i_mtime = current_time(inode);
0055 inode_unlock(inode);
0056 }
0057
0058 bytes = count;
0059
0060 out:
0061 kfree(data);
0062
0063 return bytes;
0064 }
0065
0066 static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
0067 size_t count, loff_t *ppos)
0068 {
0069 struct efivar_entry *var = file->private_data;
0070 unsigned long datasize = 0;
0071 u32 attributes;
0072 void *data;
0073 ssize_t size = 0;
0074 int err;
0075
0076 while (!__ratelimit(&file->f_cred->user->ratelimit))
0077 msleep(50);
0078
0079 err = efivar_entry_size(var, &datasize);
0080
0081
0082
0083
0084
0085 if (err == -ENOENT)
0086 return 0;
0087 else if (err)
0088 return err;
0089
0090 data = kmalloc(datasize + sizeof(attributes), GFP_KERNEL);
0091
0092 if (!data)
0093 return -ENOMEM;
0094
0095 size = efivar_entry_get(var, &attributes, &datasize,
0096 data + sizeof(attributes));
0097 if (size)
0098 goto out_free;
0099
0100 memcpy(data, &attributes, sizeof(attributes));
0101 size = simple_read_from_buffer(userbuf, count, ppos,
0102 data, datasize + sizeof(attributes));
0103 out_free:
0104 kfree(data);
0105
0106 return size;
0107 }
0108
0109 const struct file_operations efivarfs_file_operations = {
0110 .open = simple_open,
0111 .read = efivarfs_file_read,
0112 .write = efivarfs_file_write,
0113 .llseek = no_llseek,
0114 };