0001
0002
0003
0004
0005
0006
0007 #include <linux/ctype.h>
0008 #include <linux/efi.h>
0009 #include <linux/fs.h>
0010 #include <linux/fs_context.h>
0011 #include <linux/module.h>
0012 #include <linux/pagemap.h>
0013 #include <linux/ucs2_string.h>
0014 #include <linux/slab.h>
0015 #include <linux/magic.h>
0016
0017 #include "internal.h"
0018
0019 LIST_HEAD(efivarfs_list);
0020
0021 static void efivarfs_evict_inode(struct inode *inode)
0022 {
0023 clear_inode(inode);
0024 }
0025
0026 static const struct super_operations efivarfs_ops = {
0027 .statfs = simple_statfs,
0028 .drop_inode = generic_delete_inode,
0029 .evict_inode = efivarfs_evict_inode,
0030 };
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043 static int efivarfs_d_compare(const struct dentry *dentry,
0044 unsigned int len, const char *str,
0045 const struct qstr *name)
0046 {
0047 int guid = len - EFI_VARIABLE_GUID_LEN;
0048
0049 if (name->len != len)
0050 return 1;
0051
0052
0053 if (memcmp(str, name->name, guid))
0054 return 1;
0055
0056
0057 return strncasecmp(name->name + guid, str + guid, EFI_VARIABLE_GUID_LEN);
0058 }
0059
0060 static int efivarfs_d_hash(const struct dentry *dentry, struct qstr *qstr)
0061 {
0062 unsigned long hash = init_name_hash(dentry);
0063 const unsigned char *s = qstr->name;
0064 unsigned int len = qstr->len;
0065
0066 if (!efivarfs_valid_name(s, len))
0067 return -EINVAL;
0068
0069 while (len-- > EFI_VARIABLE_GUID_LEN)
0070 hash = partial_name_hash(*s++, hash);
0071
0072
0073 while (len--)
0074 hash = partial_name_hash(tolower(*s++), hash);
0075
0076 qstr->hash = end_name_hash(hash);
0077 return 0;
0078 }
0079
0080 static const struct dentry_operations efivarfs_d_ops = {
0081 .d_compare = efivarfs_d_compare,
0082 .d_hash = efivarfs_d_hash,
0083 .d_delete = always_delete_dentry,
0084 };
0085
0086 static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
0087 {
0088 struct dentry *d;
0089 struct qstr q;
0090 int err;
0091
0092 q.name = name;
0093 q.len = strlen(name);
0094
0095 err = efivarfs_d_hash(parent, &q);
0096 if (err)
0097 return ERR_PTR(err);
0098
0099 d = d_alloc(parent, &q);
0100 if (d)
0101 return d;
0102
0103 return ERR_PTR(-ENOMEM);
0104 }
0105
0106 static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
0107 unsigned long name_size, void *data)
0108 {
0109 struct super_block *sb = (struct super_block *)data;
0110 struct efivar_entry *entry;
0111 struct inode *inode = NULL;
0112 struct dentry *dentry, *root = sb->s_root;
0113 unsigned long size = 0;
0114 char *name;
0115 int len;
0116 int err = -ENOMEM;
0117 bool is_removable = false;
0118
0119 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
0120 if (!entry)
0121 return err;
0122
0123 memcpy(entry->var.VariableName, name16, name_size);
0124 memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
0125
0126 len = ucs2_utf8size(entry->var.VariableName);
0127
0128
0129 name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL);
0130 if (!name)
0131 goto fail;
0132
0133 ucs2_as_utf8(name, entry->var.VariableName, len);
0134
0135 if (efivar_variable_is_removable(entry->var.VendorGuid, name, len))
0136 is_removable = true;
0137
0138 name[len] = '-';
0139
0140 efi_guid_to_str(&entry->var.VendorGuid, name + len + 1);
0141
0142 name[len + EFI_VARIABLE_GUID_LEN+1] = '\0';
0143
0144
0145 strreplace(name, '/', '!');
0146
0147 inode = efivarfs_get_inode(sb, d_inode(root), S_IFREG | 0644, 0,
0148 is_removable);
0149 if (!inode)
0150 goto fail_name;
0151
0152 dentry = efivarfs_alloc_dentry(root, name);
0153 if (IS_ERR(dentry)) {
0154 err = PTR_ERR(dentry);
0155 goto fail_inode;
0156 }
0157
0158 __efivar_entry_get(entry, NULL, &size, NULL);
0159 __efivar_entry_add(entry, &efivarfs_list);
0160
0161
0162 kfree(name);
0163
0164 inode_lock(inode);
0165 inode->i_private = entry;
0166 i_size_write(inode, size + sizeof(entry->var.Attributes));
0167 inode_unlock(inode);
0168 d_add(dentry, inode);
0169
0170 return 0;
0171
0172 fail_inode:
0173 iput(inode);
0174 fail_name:
0175 kfree(name);
0176 fail:
0177 kfree(entry);
0178 return err;
0179 }
0180
0181 static int efivarfs_destroy(struct efivar_entry *entry, void *data)
0182 {
0183 efivar_entry_remove(entry);
0184 kfree(entry);
0185 return 0;
0186 }
0187
0188 static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
0189 {
0190 struct inode *inode = NULL;
0191 struct dentry *root;
0192 int err;
0193
0194 sb->s_maxbytes = MAX_LFS_FILESIZE;
0195 sb->s_blocksize = PAGE_SIZE;
0196 sb->s_blocksize_bits = PAGE_SHIFT;
0197 sb->s_magic = EFIVARFS_MAGIC;
0198 sb->s_op = &efivarfs_ops;
0199 sb->s_d_op = &efivarfs_d_ops;
0200 sb->s_time_gran = 1;
0201
0202 if (!efivar_supports_writes())
0203 sb->s_flags |= SB_RDONLY;
0204
0205 inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0, true);
0206 if (!inode)
0207 return -ENOMEM;
0208 inode->i_op = &efivarfs_dir_inode_operations;
0209
0210 root = d_make_root(inode);
0211 sb->s_root = root;
0212 if (!root)
0213 return -ENOMEM;
0214
0215 INIT_LIST_HEAD(&efivarfs_list);
0216
0217 err = efivar_init(efivarfs_callback, (void *)sb, true, &efivarfs_list);
0218 if (err)
0219 efivar_entry_iter(efivarfs_destroy, &efivarfs_list, NULL);
0220
0221 return err;
0222 }
0223
0224 static int efivarfs_get_tree(struct fs_context *fc)
0225 {
0226 return get_tree_single(fc, efivarfs_fill_super);
0227 }
0228
0229 static const struct fs_context_operations efivarfs_context_ops = {
0230 .get_tree = efivarfs_get_tree,
0231 };
0232
0233 static int efivarfs_init_fs_context(struct fs_context *fc)
0234 {
0235 fc->ops = &efivarfs_context_ops;
0236 return 0;
0237 }
0238
0239 static void efivarfs_kill_sb(struct super_block *sb)
0240 {
0241 kill_litter_super(sb);
0242
0243
0244 efivar_entry_iter(efivarfs_destroy, &efivarfs_list, NULL);
0245 }
0246
0247 static struct file_system_type efivarfs_type = {
0248 .owner = THIS_MODULE,
0249 .name = "efivarfs",
0250 .init_fs_context = efivarfs_init_fs_context,
0251 .kill_sb = efivarfs_kill_sb,
0252 };
0253
0254 static __init int efivarfs_init(void)
0255 {
0256 if (!efivars_kobject())
0257 return -ENODEV;
0258
0259 return register_filesystem(&efivarfs_type);
0260 }
0261
0262 static __exit void efivarfs_exit(void)
0263 {
0264 unregister_filesystem(&efivarfs_type);
0265 }
0266
0267 MODULE_AUTHOR("Matthew Garrett, Jeremy Kerr");
0268 MODULE_DESCRIPTION("EFI Variable Filesystem");
0269 MODULE_LICENSE("GPL");
0270 MODULE_ALIAS_FS("efivarfs");
0271
0272 module_init(efivarfs_init);
0273 module_exit(efivarfs_exit);