1 /* 2 * Copyright (C) 2012 Red Hat, Inc. 3 * Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 */ 9 10 #include <linux/ctype.h> 11 #include <linux/efi.h> 12 #include <linux/fs.h> 13 #include <linux/module.h> 14 #include <linux/pagemap.h> 15 #include <linux/ucs2_string.h> 16 #include <linux/slab.h> 17 #include <linux/magic.h> 18 19 #include "internal.h" 20 21 LIST_HEAD(efivarfs_list); 22 23 static void efivarfs_evict_inode(struct inode *inode) 24 { 25 clear_inode(inode); 26 } 27 28 static const struct super_operations efivarfs_ops = { 29 .statfs = simple_statfs, 30 .drop_inode = generic_delete_inode, 31 .evict_inode = efivarfs_evict_inode, 32 .show_options = generic_show_options, 33 }; 34 35 static struct super_block *efivarfs_sb; 36 37 /* 38 * Compare two efivarfs file names. 39 * 40 * An efivarfs filename is composed of two parts, 41 * 42 * 1. A case-sensitive variable name 43 * 2. A case-insensitive GUID 44 * 45 * So we need to perform a case-sensitive match on part 1 and a 46 * case-insensitive match on part 2. 47 */ 48 static int efivarfs_d_compare(const struct dentry *parent, const struct inode *pinode, 49 const struct dentry *dentry, const struct inode *inode, 50 unsigned int len, const char *str, 51 const struct qstr *name) 52 { 53 int guid = len - EFI_VARIABLE_GUID_LEN; 54 55 if (name->len != len) 56 return 1; 57 58 /* Case-sensitive compare for the variable name */ 59 if (memcmp(str, name->name, guid)) 60 return 1; 61 62 /* Case-insensitive compare for the GUID */ 63 return strncasecmp(name->name + guid, str + guid, EFI_VARIABLE_GUID_LEN); 64 } 65 66 static int efivarfs_d_hash(const struct dentry *dentry, 67 const struct inode *inode, struct qstr *qstr) 68 { 69 unsigned long hash = init_name_hash(); 70 const unsigned char *s = qstr->name; 71 unsigned int len = qstr->len; 72 73 if (!efivarfs_valid_name(s, len)) 74 return -EINVAL; 75 76 while (len-- > EFI_VARIABLE_GUID_LEN) 77 hash = partial_name_hash(*s++, hash); 78 79 /* GUID is case-insensitive. */ 80 while (len--) 81 hash = partial_name_hash(tolower(*s++), hash); 82 83 qstr->hash = end_name_hash(hash); 84 return 0; 85 } 86 87 /* 88 * Retaining negative dentries for an in-memory filesystem just wastes 89 * memory and lookup time: arrange for them to be deleted immediately. 90 */ 91 static int efivarfs_delete_dentry(const struct dentry *dentry) 92 { 93 return 1; 94 } 95 96 static struct dentry_operations efivarfs_d_ops = { 97 .d_compare = efivarfs_d_compare, 98 .d_hash = efivarfs_d_hash, 99 .d_delete = efivarfs_delete_dentry, 100 }; 101 102 static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name) 103 { 104 struct dentry *d; 105 struct qstr q; 106 int err; 107 108 q.name = name; 109 q.len = strlen(name); 110 111 err = efivarfs_d_hash(NULL, NULL, &q); 112 if (err) 113 return ERR_PTR(err); 114 115 d = d_alloc(parent, &q); 116 if (d) 117 return d; 118 119 return ERR_PTR(-ENOMEM); 120 } 121 122 static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, 123 unsigned long name_size, void *data) 124 { 125 struct super_block *sb = (struct super_block *)data; 126 struct efivar_entry *entry; 127 struct inode *inode = NULL; 128 struct dentry *dentry, *root = sb->s_root; 129 unsigned long size = 0; 130 char *name; 131 int len, i; 132 int err = -ENOMEM; 133 134 entry = kmalloc(sizeof(*entry), GFP_KERNEL); 135 if (!entry) 136 return err; 137 138 memcpy(entry->var.VariableName, name16, name_size); 139 memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); 140 141 len = ucs2_strlen(entry->var.VariableName); 142 143 /* name, plus '-', plus GUID, plus NUL*/ 144 name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL); 145 if (!name) 146 goto fail; 147 148 for (i = 0; i < len; i++) 149 name[i] = entry->var.VariableName[i] & 0xFF; 150 151 name[len] = '-'; 152 153 efi_guid_unparse(&entry->var.VendorGuid, name + len + 1); 154 155 name[len + EFI_VARIABLE_GUID_LEN+1] = '\0'; 156 157 inode = efivarfs_get_inode(sb, root->d_inode, S_IFREG | 0644, 0); 158 if (!inode) 159 goto fail_name; 160 161 dentry = efivarfs_alloc_dentry(root, name); 162 if (IS_ERR(dentry)) { 163 err = PTR_ERR(dentry); 164 goto fail_inode; 165 } 166 167 /* copied by the above to local storage in the dentry. */ 168 kfree(name); 169 170 efivar_entry_size(entry, &size); 171 efivar_entry_add(entry, &efivarfs_list); 172 173 mutex_lock(&inode->i_mutex); 174 inode->i_private = entry; 175 i_size_write(inode, size + sizeof(entry->var.Attributes)); 176 mutex_unlock(&inode->i_mutex); 177 d_add(dentry, inode); 178 179 return 0; 180 181 fail_inode: 182 iput(inode); 183 fail_name: 184 kfree(name); 185 fail: 186 kfree(entry); 187 return err; 188 } 189 190 static int efivarfs_destroy(struct efivar_entry *entry, void *data) 191 { 192 efivar_entry_remove(entry); 193 kfree(entry); 194 return 0; 195 } 196 197 static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) 198 { 199 struct inode *inode = NULL; 200 struct dentry *root; 201 int err; 202 203 efivarfs_sb = sb; 204 205 sb->s_maxbytes = MAX_LFS_FILESIZE; 206 sb->s_blocksize = PAGE_CACHE_SIZE; 207 sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 208 sb->s_magic = EFIVARFS_MAGIC; 209 sb->s_op = &efivarfs_ops; 210 sb->s_d_op = &efivarfs_d_ops; 211 sb->s_time_gran = 1; 212 213 inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0); 214 if (!inode) 215 return -ENOMEM; 216 inode->i_op = &efivarfs_dir_inode_operations; 217 218 root = d_make_root(inode); 219 sb->s_root = root; 220 if (!root) 221 return -ENOMEM; 222 223 INIT_LIST_HEAD(&efivarfs_list); 224 225 err = efivar_init(efivarfs_callback, (void *)sb, false, 226 true, &efivarfs_list); 227 if (err) 228 __efivar_entry_iter(efivarfs_destroy, &efivarfs_list, NULL, NULL); 229 230 return err; 231 } 232 233 static struct dentry *efivarfs_mount(struct file_system_type *fs_type, 234 int flags, const char *dev_name, void *data) 235 { 236 return mount_single(fs_type, flags, data, efivarfs_fill_super); 237 } 238 239 static void efivarfs_kill_sb(struct super_block *sb) 240 { 241 kill_litter_super(sb); 242 efivarfs_sb = NULL; 243 244 /* Remove all entries and destroy */ 245 __efivar_entry_iter(efivarfs_destroy, &efivarfs_list, NULL, NULL); 246 } 247 248 static struct file_system_type efivarfs_type = { 249 .name = "efivarfs", 250 .mount = efivarfs_mount, 251 .kill_sb = efivarfs_kill_sb, 252 }; 253 254 static __init int efivarfs_init(void) 255 { 256 if (!efi_enabled(EFI_RUNTIME_SERVICES)) 257 return 0; 258 259 if (!efivars_kobject()) 260 return 0; 261 262 return register_filesystem(&efivarfs_type); 263 } 264 265 MODULE_AUTHOR("Matthew Garrett, Jeremy Kerr"); 266 MODULE_DESCRIPTION("EFI Variable Filesystem"); 267 MODULE_LICENSE("GPL"); 268 MODULE_ALIAS_FS("efivarfs"); 269 270 module_init(efivarfs_init); 271