Commit 94f7f618 authored by Masahisa Kojima's avatar Masahisa Kojima Committed by Ard Biesheuvel
Browse files

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: default avatarMasahisa Kojima <masahisa.kojima@linaro.org>
[ardb: use per-superblock instance of the notifier block]
Signed-off-by: default avatarArd Biesheuvel <ardb@kernel.org>
parent c44b6be6
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#include <linux/ucs2_string.h>
#include <linux/memblock.h>
#include <linux/security.h>
#include <linux/notifier.h>

#include <asm/early_ioremap.h>

@@ -187,6 +188,9 @@ static const struct attribute_group efi_subsys_attr_group = {
	.is_visible = efi_attr_is_visible,
};

struct blocking_notifier_head efivar_ops_nh;
EXPORT_SYMBOL_GPL(efivar_ops_nh);

static struct efivars generic_efivars;
static struct efivar_operations generic_ops;

@@ -431,6 +435,8 @@ static int __init efisubsys_init(void)
		platform_device_register_simple("efivars", 0, NULL, 0);
	}

	BLOCKING_INIT_NOTIFIER_HEAD(&efivar_ops_nh);

	error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
	if (error) {
		pr_err("efi: Sysfs attribute export failed with error %d.\n",
+8 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ int efivars_register(struct efivars *efivars,
		     const struct efivar_operations *ops)
{
	int rv;
	int event;

	if (down_interruptible(&efivars_lock))
		return -EINTR;
@@ -77,6 +78,13 @@ int efivars_register(struct efivars *efivars,

	__efivars = efivars;

	if (efivar_supports_writes())
		event = EFIVAR_OPS_RDWR;
	else
		event = EFIVAR_OPS_RDONLY;

	blocking_notifier_call_chain(&efivar_ops_nh, event, NULL);

	pr_info("Registered efivars operations\n");
	rv = 0;
out:
+2 −0
Original line number Diff line number Diff line
@@ -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 {
+27 −0
Original line number Diff line number Diff line
@@ -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 */
+8 −0
Original line number Diff line number Diff line
@@ -1349,6 +1349,14 @@ bool efi_config_table_is_usable(const efi_guid_t *guid, unsigned long table)

umode_t efi_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n);

/*
 * efivar ops event type
 */
#define EFIVAR_OPS_RDONLY 0
#define EFIVAR_OPS_RDWR 1

extern struct blocking_notifier_head efivar_ops_nh;

void efivars_generic_ops_register(void);
void efivars_generic_ops_unregister(void);