Skip to content

Commit d86ff33

Browse files
anisseardbiesheuvel
authored andcommitted
efivarfs: expose used and total size
When writing EFI variables, one might get errors with no other message on why it fails. Being able to see how much is used by EFI variables helps analyzing such issues. Since this is not a conventional filesystem, block size is intentionally set to 1 instead of PAGE_SIZE. x86 quirks of reserved size are taken into account; so that available and free size can be different, further helping debugging space issues. With this patch, one can see the remaining space in EFI variable storage via efivarfs, like this: $ df -h /sys/firmware/efi/efivars/ Filesystem Size Used Avail Use% Mounted on efivarfs 176K 106K 66K 62% /sys/firmware/efi/efivars Signed-off-by: Anisse Astier <[email protected]> [ardb: - rename efi_reserved_space() to efivar_reserved_space() - whitespace/coding style tweaks] Signed-off-by: Ard Biesheuvel <[email protected]>
1 parent 0153431 commit d86ff33

File tree

5 files changed

+70
-1
lines changed

5 files changed

+70
-1
lines changed

arch/x86/platform/efi/quirks.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,14 @@ void efi_delete_dummy_variable(void)
114114
EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL);
115115
}
116116

117+
u64 efivar_reserved_space(void)
118+
{
119+
if (efi_no_storage_paranoia)
120+
return 0;
121+
return EFI_MIN_RESERVE;
122+
}
123+
EXPORT_SYMBOL_GPL(efivar_reserved_space);
124+
117125
/*
118126
* In the nonblocking case we do not attempt to perform garbage
119127
* collection if we do not have enough free space. Rather, we do the

drivers/firmware/efi/efi.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ static int generic_ops_register(void)
211211
generic_ops.get_variable = efi.get_variable;
212212
generic_ops.get_next_variable = efi.get_next_variable;
213213
generic_ops.query_variable_store = efi_query_variable_store;
214+
generic_ops.query_variable_info = efi.query_variable_info;
214215

215216
if (efi_rt_services_supported(EFI_RT_SUPPORTED_SET_VARIABLE)) {
216217
generic_ops.set_variable = efi.set_variable;

drivers/firmware/efi/vars.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,15 @@ efi_status_t efivar_set_variable(efi_char16_t *name, efi_guid_t *vendor,
245245
return status;
246246
}
247247
EXPORT_SYMBOL_NS_GPL(efivar_set_variable, EFIVAR);
248+
249+
efi_status_t efivar_query_variable_info(u32 attr,
250+
u64 *storage_space,
251+
u64 *remaining_space,
252+
u64 *max_variable_size)
253+
{
254+
if (!__efivars->ops->query_variable_info)
255+
return EFI_UNSUPPORTED;
256+
return __efivars->ops->query_variable_info(attr, storage_space,
257+
remaining_space, max_variable_size);
258+
}
259+
EXPORT_SYMBOL_NS_GPL(efivar_query_variable_info, EFIVAR);

fs/efivarfs/super.c

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/ucs2_string.h>
1414
#include <linux/slab.h>
1515
#include <linux/magic.h>
16+
#include <linux/statfs.h>
1617

1718
#include "internal.h"
1819

@@ -23,8 +24,44 @@ static void efivarfs_evict_inode(struct inode *inode)
2324
clear_inode(inode);
2425
}
2526

27+
static int efivarfs_statfs(struct dentry *dentry, struct kstatfs *buf)
28+
{
29+
const u32 attr = EFI_VARIABLE_NON_VOLATILE |
30+
EFI_VARIABLE_BOOTSERVICE_ACCESS |
31+
EFI_VARIABLE_RUNTIME_ACCESS;
32+
u64 storage_space, remaining_space, max_variable_size;
33+
efi_status_t status;
34+
35+
status = efivar_query_variable_info(attr, &storage_space, &remaining_space,
36+
&max_variable_size);
37+
if (status != EFI_SUCCESS)
38+
return efi_status_to_err(status);
39+
40+
/*
41+
* This is not a normal filesystem, so no point in pretending it has a block
42+
* size; we declare f_bsize to 1, so that we can then report the exact value
43+
* sent by EFI QueryVariableInfo in f_blocks and f_bfree
44+
*/
45+
buf->f_bsize = 1;
46+
buf->f_namelen = NAME_MAX;
47+
buf->f_blocks = storage_space;
48+
buf->f_bfree = remaining_space;
49+
buf->f_type = dentry->d_sb->s_magic;
50+
51+
/*
52+
* In f_bavail we declare the free space that the kernel will allow writing
53+
* when the storage_paranoia x86 quirk is active. To use more, users
54+
* should boot the kernel with efi_no_storage_paranoia.
55+
*/
56+
if (remaining_space > efivar_reserved_space())
57+
buf->f_bavail = remaining_space - efivar_reserved_space();
58+
else
59+
buf->f_bavail = 0;
60+
61+
return 0;
62+
}
2663
static const struct super_operations efivarfs_ops = {
27-
.statfs = simple_statfs,
64+
.statfs = efivarfs_statfs,
2865
.drop_inode = generic_delete_inode,
2966
.evict_inode = efivarfs_evict_inode,
3067
};

include/linux/efi.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,13 +1042,20 @@ struct efivar_operations {
10421042
efi_set_variable_t *set_variable;
10431043
efi_set_variable_t *set_variable_nonblocking;
10441044
efi_query_variable_store_t *query_variable_store;
1045+
efi_query_variable_info_t *query_variable_info;
10451046
};
10461047

10471048
struct efivars {
10481049
struct kset *kset;
10491050
const struct efivar_operations *ops;
10501051
};
10511052

1053+
#ifdef CONFIG_X86
1054+
u64 __attribute_const__ efivar_reserved_space(void);
1055+
#else
1056+
static inline u64 efivar_reserved_space(void) { return 0; }
1057+
#endif
1058+
10521059
/*
10531060
* The maximum size of VariableName + Data = 1024
10541061
* Therefore, it's reasonable to save that much
@@ -1087,6 +1094,10 @@ efi_status_t efivar_set_variable_locked(efi_char16_t *name, efi_guid_t *vendor,
10871094
efi_status_t efivar_set_variable(efi_char16_t *name, efi_guid_t *vendor,
10881095
u32 attr, unsigned long data_size, void *data);
10891096

1097+
efi_status_t efivar_query_variable_info(u32 attr, u64 *storage_space,
1098+
u64 *remaining_space,
1099+
u64 *max_variable_size);
1100+
10901101
#if IS_ENABLED(CONFIG_EFI_CAPSULE_LOADER)
10911102
extern bool efi_capsule_pending(int *reset_type);
10921103

0 commit comments

Comments
 (0)