Commit 3fab70c165795431f00ddf9be8b84ddd07bd1f8f

Authored by Lingzhu Xiang
Committed by Matt Fleming
1 parent f722406faa

efivarfs: Never return ENOENT from firmware again

Previously in 1fa7e69 efi_status_to_err() translated firmware status
EFI_NOT_FOUND to -EIO instead of -ENOENT for efivarfs operations to
avoid confusion. After refactoring in e14ab23, it is also used in other
places where the translation may be unnecessary.

So move the translation to efivarfs specific code. Also return EOF
for reading zero-length files, which is what users would expect.

Cc: Josh Boyer <jwboyer@redhat.com>
Cc: Jeremy Kerr <jk@ozlabs.org>
Cc: Lee, Chun-Yi <jlee@suse.com>
Cc: Andy Whitcroft <apw@canonical.com>
Signed-off-by: Lingzhu Xiang <lxiang@redhat.com>
Signed-off-by: Matt Fleming <matt.fleming@intel.com>

Showing 1 changed file with 12 additions and 2 deletions Inline Diff

1 /* 1 /*
2 * Copyright (C) 2012 Red Hat, Inc. 2 * Copyright (C) 2012 Red Hat, Inc.
3 * Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com> 3 * Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 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 6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 */ 8 */
9 9
10 #include <linux/efi.h> 10 #include <linux/efi.h>
11 #include <linux/fs.h> 11 #include <linux/fs.h>
12 #include <linux/slab.h> 12 #include <linux/slab.h>
13 13
14 #include "internal.h" 14 #include "internal.h"
15 15
16 static ssize_t efivarfs_file_write(struct file *file, 16 static ssize_t efivarfs_file_write(struct file *file,
17 const char __user *userbuf, size_t count, loff_t *ppos) 17 const char __user *userbuf, size_t count, loff_t *ppos)
18 { 18 {
19 struct efivar_entry *var = file->private_data; 19 struct efivar_entry *var = file->private_data;
20 void *data; 20 void *data;
21 u32 attributes; 21 u32 attributes;
22 struct inode *inode = file->f_mapping->host; 22 struct inode *inode = file->f_mapping->host;
23 unsigned long datasize = count - sizeof(attributes); 23 unsigned long datasize = count - sizeof(attributes);
24 ssize_t bytes = 0; 24 ssize_t bytes = 0;
25 bool set = false; 25 bool set = false;
26 26
27 if (count < sizeof(attributes)) 27 if (count < sizeof(attributes))
28 return -EINVAL; 28 return -EINVAL;
29 29
30 if (copy_from_user(&attributes, userbuf, sizeof(attributes))) 30 if (copy_from_user(&attributes, userbuf, sizeof(attributes)))
31 return -EFAULT; 31 return -EFAULT;
32 32
33 if (attributes & ~(EFI_VARIABLE_MASK)) 33 if (attributes & ~(EFI_VARIABLE_MASK))
34 return -EINVAL; 34 return -EINVAL;
35 35
36 data = kmalloc(datasize, GFP_KERNEL); 36 data = kmalloc(datasize, GFP_KERNEL);
37 if (!data) 37 if (!data)
38 return -ENOMEM; 38 return -ENOMEM;
39 39
40 if (copy_from_user(data, userbuf + sizeof(attributes), datasize)) { 40 if (copy_from_user(data, userbuf + sizeof(attributes), datasize)) {
41 bytes = -EFAULT; 41 bytes = -EFAULT;
42 goto out; 42 goto out;
43 } 43 }
44 44
45 bytes = efivar_entry_set_get_size(var, attributes, &datasize, 45 bytes = efivar_entry_set_get_size(var, attributes, &datasize,
46 data, &set); 46 data, &set);
47 if (!set && bytes) 47 if (!set && bytes) {
48 if (bytes == -ENOENT)
49 bytes = -EIO;
48 goto out; 50 goto out;
51 }
49 52
50 if (bytes == -ENOENT) { 53 if (bytes == -ENOENT) {
51 drop_nlink(inode); 54 drop_nlink(inode);
52 d_delete(file->f_dentry); 55 d_delete(file->f_dentry);
53 dput(file->f_dentry); 56 dput(file->f_dentry);
54 } else { 57 } else {
55 mutex_lock(&inode->i_mutex); 58 mutex_lock(&inode->i_mutex);
56 i_size_write(inode, datasize + sizeof(attributes)); 59 i_size_write(inode, datasize + sizeof(attributes));
57 mutex_unlock(&inode->i_mutex); 60 mutex_unlock(&inode->i_mutex);
58 } 61 }
59 62
60 bytes = count; 63 bytes = count;
61 64
62 out: 65 out:
63 kfree(data); 66 kfree(data);
64 67
65 return bytes; 68 return bytes;
66 } 69 }
67 70
68 static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf, 71 static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
69 size_t count, loff_t *ppos) 72 size_t count, loff_t *ppos)
70 { 73 {
71 struct efivar_entry *var = file->private_data; 74 struct efivar_entry *var = file->private_data;
72 unsigned long datasize = 0; 75 unsigned long datasize = 0;
73 u32 attributes; 76 u32 attributes;
74 void *data; 77 void *data;
75 ssize_t size = 0; 78 ssize_t size = 0;
76 int err; 79 int err;
77 80
78 err = efivar_entry_size(var, &datasize); 81 err = efivar_entry_size(var, &datasize);
79 if (err) 82
83 /*
84 * efivarfs represents uncommitted variables with
85 * zero-length files. Reading them should return EOF.
86 */
87 if (err == -ENOENT)
88 return 0;
89 else if (err)
80 return err; 90 return err;
81 91
82 data = kmalloc(datasize + sizeof(attributes), GFP_KERNEL); 92 data = kmalloc(datasize + sizeof(attributes), GFP_KERNEL);
83 93
84 if (!data) 94 if (!data)
85 return -ENOMEM; 95 return -ENOMEM;
86 96
87 size = efivar_entry_get(var, &attributes, &datasize, 97 size = efivar_entry_get(var, &attributes, &datasize,
88 data + sizeof(attributes)); 98 data + sizeof(attributes));
89 if (size) 99 if (size)
90 goto out_free; 100 goto out_free;
91 101
92 memcpy(data, &attributes, sizeof(attributes)); 102 memcpy(data, &attributes, sizeof(attributes));
93 size = simple_read_from_buffer(userbuf, count, ppos, 103 size = simple_read_from_buffer(userbuf, count, ppos,
94 data, datasize + sizeof(attributes)); 104 data, datasize + sizeof(attributes));
95 out_free: 105 out_free:
96 kfree(data); 106 kfree(data);
97 107
98 return size; 108 return size;
99 } 109 }
100 110
101 const struct file_operations efivarfs_file_operations = { 111 const struct file_operations efivarfs_file_operations = {
102 .open = simple_open, 112 .open = simple_open,
103 .read = efivarfs_file_read, 113 .read = efivarfs_file_read,
104 .write = efivarfs_file_write, 114 .write = efivarfs_file_write,
105 .llseek = no_llseek, 115 .llseek = no_llseek,
106 }; 116 };
107 117