summaryrefslogtreecommitdiffstats
path: root/fs/efivarfs
diff options
context:
space:
mode:
authorMasahisa Kojima <masahisa.kojima@linaro.org>2023-11-07 14:40:55 +0900
committerArd Biesheuvel <ardb@kernel.org>2023-12-11 11:19:18 +0100
commit94f7f6182c72ba642c1f20111681f9cc8621c95f (patch)
treea469f9da0e5bdfd8416b779c7d908a7ee9fc1e5e /fs/efivarfs
parentc44b6be62e8dd4ee0a308c36a70620613e6fc55f (diff)
downloadlinux-94f7f6182c72ba642c1f20111681f9cc8621c95f.tar.gz
linux-94f7f6182c72ba642c1f20111681f9cc8621c95f.tar.bz2
linux-94f7f6182c72ba642c1f20111681f9cc8621c95f.zip
efivarfs: automatically update super block flag
efivar operation is updated when the tee_stmm_efi module is probed. tee_stmm_efi module supports SetVariable runtime service, but user needs to manually remount the efivarfs as RW to enable the write access if the previous efivar operation does not support SetVariable and efivarfs is mounted as read-only. This commit notifies the update of efivar operation to efivarfs subsystem, then drops SB_RDONLY flag if the efivar operation supports SetVariable. Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org> [ardb: use per-superblock instance of the notifier block] Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Diffstat (limited to 'fs/efivarfs')
-rw-r--r--fs/efivarfs/internal.h2
-rw-r--r--fs/efivarfs/super.c27
2 files changed, 29 insertions, 0 deletions
diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h
index 1dc0ccce3cc3..169252e6dc46 100644
--- a/fs/efivarfs/internal.h
+++ b/fs/efivarfs/internal.h
@@ -17,6 +17,8 @@ struct efivarfs_mount_opts {
struct efivarfs_fs_info {
struct efivarfs_mount_opts mount_opts;
struct list_head efivarfs_list;
+ struct super_block *sb;
+ struct notifier_block nb;
};
struct efi_variable {
diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
index cee325b5bbdd..6038dd39367a 100644
--- a/fs/efivarfs/super.c
+++ b/fs/efivarfs/super.c
@@ -15,10 +15,30 @@
#include <linux/slab.h>
#include <linux/magic.h>
#include <linux/statfs.h>
+#include <linux/notifier.h>
#include <linux/printk.h>
#include "internal.h"
+static int efivarfs_ops_notifier(struct notifier_block *nb, unsigned long event,
+ void *data)
+{
+ struct efivarfs_fs_info *sfi = container_of(nb, struct efivarfs_fs_info, nb);
+
+ switch (event) {
+ case EFIVAR_OPS_RDONLY:
+ sfi->sb->s_flags |= SB_RDONLY;
+ break;
+ case EFIVAR_OPS_RDWR:
+ sfi->sb->s_flags &= ~SB_RDONLY;
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+
+ return NOTIFY_OK;
+}
+
static void efivarfs_evict_inode(struct inode *inode)
{
clear_inode(inode);
@@ -317,6 +337,12 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
if (!root)
return -ENOMEM;
+ sfi->sb = sb;
+ sfi->nb.notifier_call = efivarfs_ops_notifier;
+ err = blocking_notifier_chain_register(&efivar_ops_nh, &sfi->nb);
+ if (err)
+ return err;
+
err = efivar_init(efivarfs_callback, (void *)sb, true,
&sfi->efivarfs_list);
if (err)
@@ -371,6 +397,7 @@ static void efivarfs_kill_sb(struct super_block *sb)
{
struct efivarfs_fs_info *sfi = sb->s_fs_info;
+ blocking_notifier_chain_unregister(&efivar_ops_nh, &sfi->nb);
kill_litter_super(sb);
/* Remove all entries and destroy */