2 * Copyright (C) 2012 Red Hat, Inc.
3 * Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
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.
10 #include <linux/ctype.h>
11 #include <linux/efi.h>
13 #include <linux/module.h>
14 #include <linux/pagemap.h>
18 LIST_HEAD(efivarfs_list
);
20 static void efivarfs_evict_inode(struct inode
*inode
)
25 static const struct super_operations efivarfs_ops
= {
26 .statfs
= simple_statfs
,
27 .drop_inode
= generic_delete_inode
,
28 .evict_inode
= efivarfs_evict_inode
,
29 .show_options
= generic_show_options
,
32 static struct super_block
*efivarfs_sb
;
35 * Compare two efivarfs file names.
37 * An efivarfs filename is composed of two parts,
39 * 1. A case-sensitive variable name
40 * 2. A case-insensitive GUID
42 * So we need to perform a case-sensitive match on part 1 and a
43 * case-insensitive match on part 2.
45 static int efivarfs_d_compare(const struct dentry
*parent
, const struct inode
*pinode
,
46 const struct dentry
*dentry
, const struct inode
*inode
,
47 unsigned int len
, const char *str
,
48 const struct qstr
*name
)
50 int guid
= len
- EFI_VARIABLE_GUID_LEN
;
55 /* Case-sensitive compare for the variable name */
56 if (memcmp(str
, name
->name
, guid
))
59 /* Case-insensitive compare for the GUID */
60 return strncasecmp(name
->name
+ guid
, str
+ guid
, EFI_VARIABLE_GUID_LEN
);
63 static int efivarfs_d_hash(const struct dentry
*dentry
,
64 const struct inode
*inode
, struct qstr
*qstr
)
66 unsigned long hash
= init_name_hash();
67 const unsigned char *s
= qstr
->name
;
68 unsigned int len
= qstr
->len
;
70 if (!efivarfs_valid_name(s
, len
))
73 while (len
-- > EFI_VARIABLE_GUID_LEN
)
74 hash
= partial_name_hash(*s
++, hash
);
76 /* GUID is case-insensitive. */
78 hash
= partial_name_hash(tolower(*s
++), hash
);
80 qstr
->hash
= end_name_hash(hash
);
85 * Retaining negative dentries for an in-memory filesystem just wastes
86 * memory and lookup time: arrange for them to be deleted immediately.
88 static int efivarfs_delete_dentry(const struct dentry
*dentry
)
93 static struct dentry_operations efivarfs_d_ops
= {
94 .d_compare
= efivarfs_d_compare
,
95 .d_hash
= efivarfs_d_hash
,
96 .d_delete
= efivarfs_delete_dentry
,
99 static struct dentry
*efivarfs_alloc_dentry(struct dentry
*parent
, char *name
)
106 q
.len
= strlen(name
);
108 err
= efivarfs_d_hash(NULL
, NULL
, &q
);
112 d
= d_alloc(parent
, &q
);
116 return ERR_PTR(-ENOMEM
);
119 static int efivarfs_callback(efi_char16_t
*name16
, efi_guid_t vendor
,
120 unsigned long name_size
, void *data
)
122 struct super_block
*sb
= (struct super_block
*)data
;
123 struct efivar_entry
*entry
;
124 struct inode
*inode
= NULL
;
125 struct dentry
*dentry
, *root
= sb
->s_root
;
126 unsigned long size
= 0;
131 entry
= kmalloc(sizeof(*entry
), GFP_KERNEL
);
135 memcpy(entry
->var
.VariableName
, name16
, name_size
);
136 memcpy(&(entry
->var
.VendorGuid
), &vendor
, sizeof(efi_guid_t
));
138 len
= utf16_strlen(entry
->var
.VariableName
);
140 /* name, plus '-', plus GUID, plus NUL*/
141 name
= kmalloc(len
+ 1 + EFI_VARIABLE_GUID_LEN
+ 1, GFP_KERNEL
);
145 for (i
= 0; i
< len
; i
++)
146 name
[i
] = entry
->var
.VariableName
[i
] & 0xFF;
150 efi_guid_unparse(&entry
->var
.VendorGuid
, name
+ len
+ 1);
152 name
[len
+ EFI_VARIABLE_GUID_LEN
+1] = '\0';
154 inode
= efivarfs_get_inode(sb
, root
->d_inode
, S_IFREG
| 0644, 0);
158 dentry
= efivarfs_alloc_dentry(root
, name
);
159 if (IS_ERR(dentry
)) {
160 err
= PTR_ERR(dentry
);
164 /* copied by the above to local storage in the dentry. */
167 efivar_entry_size(entry
, &size
);
168 efivar_entry_add(entry
, &efivarfs_list
);
170 mutex_lock(&inode
->i_mutex
);
171 inode
->i_private
= entry
;
172 i_size_write(inode
, size
+ sizeof(entry
->var
.Attributes
));
173 mutex_unlock(&inode
->i_mutex
);
174 d_add(dentry
, inode
);
187 static int efivarfs_destroy(struct efivar_entry
*entry
, void *data
)
189 efivar_entry_remove(entry
);
194 static int efivarfs_fill_super(struct super_block
*sb
, void *data
, int silent
)
196 struct inode
*inode
= NULL
;
202 sb
->s_maxbytes
= MAX_LFS_FILESIZE
;
203 sb
->s_blocksize
= PAGE_CACHE_SIZE
;
204 sb
->s_blocksize_bits
= PAGE_CACHE_SHIFT
;
205 sb
->s_magic
= EFIVARFS_MAGIC
;
206 sb
->s_op
= &efivarfs_ops
;
207 sb
->s_d_op
= &efivarfs_d_ops
;
210 inode
= efivarfs_get_inode(sb
, NULL
, S_IFDIR
| 0755, 0);
213 inode
->i_op
= &efivarfs_dir_inode_operations
;
215 root
= d_make_root(inode
);
220 INIT_LIST_HEAD(&efivarfs_list
);
222 err
= efivar_init(efivarfs_callback
, (void *)sb
, false,
223 true, &efivarfs_list
);
225 __efivar_entry_iter(efivarfs_destroy
, &efivarfs_list
, NULL
, NULL
);
230 static struct dentry
*efivarfs_mount(struct file_system_type
*fs_type
,
231 int flags
, const char *dev_name
, void *data
)
233 return mount_single(fs_type
, flags
, data
, efivarfs_fill_super
);
236 static void efivarfs_kill_sb(struct super_block
*sb
)
238 kill_litter_super(sb
);
241 /* Remove all entries and destroy */
242 __efivar_entry_iter(efivarfs_destroy
, &efivarfs_list
, NULL
, NULL
);
245 static struct file_system_type efivarfs_type
= {
247 .mount
= efivarfs_mount
,
248 .kill_sb
= efivarfs_kill_sb
,
251 static __init
int efivarfs_init(void)
253 if (!efi_enabled(EFI_RUNTIME_SERVICES
))
256 if (!efivars_kobject())
259 return register_filesystem(&efivarfs_type
);
262 MODULE_AUTHOR("Matthew Garrett, Jeremy Kerr");
263 MODULE_DESCRIPTION("EFI Variable Filesystem");
264 MODULE_LICENSE("GPL");
265 MODULE_ALIAS_FS("efivarfs");
267 module_init(efivarfs_init
);