Skip to content

Commit e7b4b1f

Browse files
committed
Merge branch 'efivarfs' into next
2 parents 8a32d46 + 908af31 commit e7b4b1f

File tree

5 files changed

+179
-232
lines changed

5 files changed

+179
-232
lines changed

fs/efivarfs/file.c

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,28 +36,41 @@ static ssize_t efivarfs_file_write(struct file *file,
3636
if (IS_ERR(data))
3737
return PTR_ERR(data);
3838

39+
inode_lock(inode);
40+
if (var->removed) {
41+
/*
42+
* file got removed; don't allow a set. Caused by an
43+
* unsuccessful create or successful delete write
44+
* racing with us.
45+
*/
46+
bytes = -EIO;
47+
goto out;
48+
}
49+
3950
bytes = efivar_entry_set_get_size(var, attributes, &datasize,
4051
data, &set);
41-
if (!set && bytes) {
52+
if (!set) {
4253
if (bytes == -ENOENT)
4354
bytes = -EIO;
4455
goto out;
4556
}
4657

4758
if (bytes == -ENOENT) {
48-
drop_nlink(inode);
49-
d_delete(file->f_path.dentry);
50-
dput(file->f_path.dentry);
59+
/*
60+
* zero size signals to release that the write deleted
61+
* the variable
62+
*/
63+
i_size_write(inode, 0);
5164
} else {
52-
inode_lock(inode);
5365
i_size_write(inode, datasize + sizeof(attributes));
5466
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
55-
inode_unlock(inode);
5667
}
5768

5869
bytes = count;
5970

6071
out:
72+
inode_unlock(inode);
73+
6174
kfree(data);
6275

6376
return bytes;
@@ -106,8 +119,36 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
106119
return size;
107120
}
108121

122+
static int efivarfs_file_release(struct inode *inode, struct file *file)
123+
{
124+
struct efivar_entry *var = inode->i_private;
125+
126+
inode_lock(inode);
127+
var->removed = (--var->open_count == 0 && i_size_read(inode) == 0);
128+
inode_unlock(inode);
129+
130+
if (var->removed)
131+
simple_recursive_removal(file->f_path.dentry, NULL);
132+
133+
return 0;
134+
}
135+
136+
static int efivarfs_file_open(struct inode *inode, struct file *file)
137+
{
138+
struct efivar_entry *entry = inode->i_private;
139+
140+
file->private_data = entry;
141+
142+
inode_lock(inode);
143+
entry->open_count++;
144+
inode_unlock(inode);
145+
146+
return 0;
147+
}
148+
109149
const struct file_operations efivarfs_file_operations = {
110-
.open = simple_open,
111-
.read = efivarfs_file_read,
112-
.write = efivarfs_file_write,
150+
.open = efivarfs_file_open,
151+
.read = efivarfs_file_read,
152+
.write = efivarfs_file_write,
153+
.release = efivarfs_file_release,
113154
};

fs/efivarfs/inode.c

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -77,61 +77,46 @@ static bool efivarfs_valid_name(const char *str, int len)
7777
static int efivarfs_create(struct mnt_idmap *idmap, struct inode *dir,
7878
struct dentry *dentry, umode_t mode, bool excl)
7979
{
80-
struct efivarfs_fs_info *info = dir->i_sb->s_fs_info;
8180
struct inode *inode = NULL;
8281
struct efivar_entry *var;
8382
int namelen, i = 0, err = 0;
8483
bool is_removable = false;
84+
efi_guid_t vendor;
8585

8686
if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len))
8787
return -EINVAL;
8888

89-
var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
90-
if (!var)
91-
return -ENOMEM;
92-
9389
/* length of the variable name itself: remove GUID and separator */
9490
namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1;
9591

96-
err = guid_parse(dentry->d_name.name + namelen + 1, &var->var.VendorGuid);
92+
err = guid_parse(dentry->d_name.name + namelen + 1, &vendor);
9793
if (err)
98-
goto out;
99-
if (guid_equal(&var->var.VendorGuid, &LINUX_EFI_RANDOM_SEED_TABLE_GUID)) {
100-
err = -EPERM;
101-
goto out;
102-
}
94+
return err;
95+
if (guid_equal(&vendor, &LINUX_EFI_RANDOM_SEED_TABLE_GUID))
96+
return -EPERM;
10397

104-
if (efivar_variable_is_removable(var->var.VendorGuid,
98+
if (efivar_variable_is_removable(vendor,
10599
dentry->d_name.name, namelen))
106100
is_removable = true;
107101

108102
inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0, is_removable);
109-
if (!inode) {
110-
err = -ENOMEM;
111-
goto out;
112-
}
103+
if (!inode)
104+
return -ENOMEM;
105+
var = efivar_entry(inode);
106+
107+
var->var.VendorGuid = vendor;
113108

114109
for (i = 0; i < namelen; i++)
115110
var->var.VariableName[i] = dentry->d_name.name[i];
116111

117112
var->var.VariableName[i] = '\0';
118113

119114
inode->i_private = var;
120-
kmemleak_ignore(var);
121-
122-
err = efivar_entry_add(var, &info->efivarfs_list);
123-
if (err)
124-
goto out;
125115

126116
d_instantiate(dentry, inode);
127117
dget(dentry);
128-
out:
129-
if (err) {
130-
kfree(var);
131-
if (inode)
132-
iput(inode);
133-
}
134-
return err;
118+
119+
return 0;
135120
}
136121

137122
static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)

fs/efivarfs/internal.h

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
#ifndef EFIVAR_FS_INTERNAL_H
77
#define EFIVAR_FS_INTERNAL_H
88

9-
#include <linux/list.h>
109
#include <linux/efi.h>
1110

1211
struct efivarfs_mount_opts {
@@ -16,30 +15,30 @@ struct efivarfs_mount_opts {
1615

1716
struct efivarfs_fs_info {
1817
struct efivarfs_mount_opts mount_opts;
19-
struct list_head efivarfs_list;
2018
struct super_block *sb;
2119
struct notifier_block nb;
2220
};
2321

2422
struct efi_variable {
2523
efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)];
2624
efi_guid_t VendorGuid;
27-
__u32 Attributes;
2825
};
2926

3027
struct efivar_entry {
3128
struct efi_variable var;
32-
struct list_head list;
33-
struct kobject kobj;
29+
struct inode vfs_inode;
30+
unsigned long open_count;
31+
bool removed;
3432
};
3533

36-
int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *,
37-
struct list_head *),
38-
void *data, struct list_head *head);
34+
static inline struct efivar_entry *efivar_entry(struct inode *inode)
35+
{
36+
return container_of(inode, struct efivar_entry, vfs_inode);
37+
}
38+
39+
int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
40+
void *data);
3941

40-
int efivar_entry_add(struct efivar_entry *entry, struct list_head *head);
41-
void __efivar_entry_add(struct efivar_entry *entry, struct list_head *head);
42-
void efivar_entry_remove(struct efivar_entry *entry);
4342
int efivar_entry_delete(struct efivar_entry *entry);
4443

4544
int efivar_entry_size(struct efivar_entry *entry, unsigned long *size);
@@ -50,13 +49,14 @@ int efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
5049
int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
5150
unsigned long *size, void *data, bool *set);
5251

53-
int efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
54-
struct list_head *head, void *data);
5552

5653
bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data,
5754
unsigned long data_size);
5855
bool efivar_variable_is_removable(efi_guid_t vendor, const char *name,
5956
size_t len);
57+
char *efivar_get_utf8name(const efi_char16_t *name16, efi_guid_t *vendor);
58+
bool efivarfs_variable_is_present(efi_char16_t *variable_name,
59+
efi_guid_t *vendor, void *data);
6060

6161
extern const struct file_operations efivarfs_file_operations;
6262
extern const struct inode_operations efivarfs_dir_inode_operations;

0 commit comments

Comments
 (0)