[PATCH v4 21/31] firmware: arm_scmi: stlmfs: Add basic mount options
Cristian Marussi
cristian.marussi at arm.com
Fri Jun 12 15:37:51 PDT 2026
Add mount options to choose different uid/gid/umask for all the created
files; reject handling changes to these options while remounting.
Signed-off-by: Cristian Marussi <cristian.marussi at arm.com>
---
.../firmware/arm_scmi/scmi_system_telemetry.c | 146 +++++++++++++++++-
1 file changed, 143 insertions(+), 3 deletions(-)
diff --git a/drivers/firmware/arm_scmi/scmi_system_telemetry.c b/drivers/firmware/arm_scmi/scmi_system_telemetry.c
index 567585dfb036..f4d284335ac0 100644
--- a/drivers/firmware/arm_scmi/scmi_system_telemetry.c
+++ b/drivers/firmware/arm_scmi/scmi_system_telemetry.c
@@ -34,6 +34,32 @@
#define MAX_AVAILABLE_INTERV_CHAR_LENGTH 25
#define MAX_BULK_LINE_CHAR_LENGTH 64
+enum {
+ Opt_uid,
+ Opt_gid,
+ Opt_umask,
+};
+
+static const struct fs_parameter_spec stlmfs_param_spec[] = {
+ fsparam_uid("uid", Opt_uid),
+ fsparam_gid("gid", Opt_gid),
+ fsparam_u32oct("umask", Opt_umask),
+ {}
+};
+
+struct stlmfs_fs_context {
+ unsigned int opts;
+ kuid_t uid;
+ kgid_t gid;
+ umode_t umask;
+};
+
+struct stlmfs_sb_info {
+ kuid_t uid;
+ kgid_t gid;
+ umode_t umask;
+};
+
static struct kmem_cache *stlmfs_inode_cachep;
static DEFINE_MUTEX(stlmfs_mtx);
@@ -202,10 +228,12 @@ static struct inode *stlmfs_get_inode(struct super_block *sb, umode_t mode)
struct inode *inode = new_inode(sb);
if (inode) {
+ struct stlmfs_sb_info *sbi = sb->s_fs_info;
+
inode->i_ino = get_next_ino();
- inode->i_uid = GLOBAL_ROOT_UID;
- inode->i_gid = GLOBAL_ROOT_GID;
- inode->i_mode = mode & ~SCMI_TLM_DEFAULT_UMASK;
+ inode->i_uid = sbi->uid;
+ inode->i_gid = sbi->gid;
+ inode->i_mode = mode & ~sbi->umask;
simple_inode_init_ts(inode);
}
@@ -1282,10 +1310,25 @@ static void stlmfs_free_inode(struct inode *inode)
kmem_cache_free(stlmfs_inode_cachep, tlmi);
}
+static int stlmfs_show_options(struct seq_file *seq, struct dentry *root)
+{
+ struct stlmfs_sb_info *sbi = root->d_sb->s_fs_info;
+
+ if (!uid_eq(sbi->uid, GLOBAL_ROOT_UID))
+ seq_printf(seq, ",uid=%u", from_kuid_munged(&init_user_ns, sbi->uid));
+ if (!gid_eq(sbi->gid, GLOBAL_ROOT_GID))
+ seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, sbi->gid));
+ if (sbi->umask != SCMI_TLM_DEFAULT_UMASK)
+ seq_printf(seq, ",umask=%04u", sbi->umask);
+
+ return 0;
+}
+
static const struct super_operations tlm_sops = {
.statfs = simple_statfs,
.alloc_inode = stlmfs_alloc_inode,
.free_inode = stlmfs_free_inode,
+ .show_options = stlmfs_show_options,
};
static struct dentry *stlmfs_create_root_dentry(struct super_block *sb)
@@ -1366,10 +1409,26 @@ static int scmi_telemetry_instance_register(struct super_block *sb,
static int stlmfs_fill_super(struct super_block *sb, struct fs_context *fc)
{
+ struct stlmfs_fs_context *ctx;
struct scmi_tlm_instance *ti;
struct dentry *root_dentry;
int ret;
+ /* Bail out if already initialized */
+ if (sb->s_fs_info)
+ return 0;
+
+ struct stlmfs_sb_info *sbi __free(kfree) =
+ kzalloc(sizeof(*sbi), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+
+ ctx = fc->fs_private;
+ sbi->uid = ctx->uid;
+ sbi->gid = ctx->gid;
+ sbi->umask = ctx->umask;
+
+ sb->s_fs_info = sbi;
sb->s_magic = TLM_FS_MAGIC;
sb->s_blocksize = PAGE_SIZE;
sb->s_blocksize_bits = PAGE_SHIFT;
@@ -1379,6 +1438,7 @@ static int stlmfs_fill_super(struct super_block *sb, struct fs_context *fc)
if (IS_ERR(root_dentry))
return PTR_ERR(root_dentry);
+ retain_and_null_ptr(sbi);
sb->s_root = root_dentry;
mutex_lock(&stlmfs_mtx);
@@ -1396,17 +1456,93 @@ static int stlmfs_fill_super(struct super_block *sb, struct fs_context *fc)
return 0;
}
+static void stlmfs_free(struct fs_context *fc)
+{
+ struct stlmfs_fs_context *ctx;
+
+ ctx = fc->fs_private;
+
+ kfree(ctx);
+}
+
static int stlmfs_get_tree(struct fs_context *fc)
{
return get_tree_single(fc, stlmfs_fill_super);
}
+static int stlmfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
+{
+ struct stlmfs_fs_context *ctx;
+ struct fs_parse_result result;
+ int opt;
+
+ opt = fs_parse(fc, stlmfs_param_spec, param, &result);
+ if (opt < 0)
+ return opt;
+
+ ctx = fc->fs_private;
+
+ switch (opt) {
+ case Opt_uid:
+ if (!kuid_has_mapping(fc->user_ns, result.uid))
+ return invalfc(fc, "Invalid uid");
+ ctx->uid = result.uid;
+ ctx->opts |= BIT(Opt_uid);
+ break;
+ case Opt_gid:
+ if (!kgid_has_mapping(fc->user_ns, result.gid))
+ return invalfc(fc, "Invalid gid");
+ ctx->gid = result.gid;
+ ctx->opts |= BIT(Opt_gid);
+ break;
+ case Opt_umask:
+ ctx->umask = result.uint_32 & 07777;
+ ctx->opts |= BIT(Opt_umask);
+ break;
+ default:
+ return -ENOPARAM;
+ }
+
+ return 0;
+}
+
+static int stlmfs_reconfigure(struct fs_context *fc)
+{
+ struct stlmfs_fs_context *ctx = fc->fs_private;
+
+ sync_filesystem(fc->root->d_sb);
+
+ if (ctx->opts & BIT(Opt_uid))
+ return invalfc(fc, "uid cannot be changed on remount");
+ if (ctx->opts & BIT(Opt_gid))
+ return invalfc(fc, "gid cannot be changed on remount");
+ if (ctx->opts & BIT(Opt_umask))
+ return invalfc(fc, "umask cannot be changed on remount");
+
+ return 0;
+}
+
static const struct fs_context_operations stlmfs_fc_ops = {
.get_tree = stlmfs_get_tree,
+ .parse_param = stlmfs_parse_param,
+ .free = stlmfs_free,
+ .reconfigure = stlmfs_reconfigure,
};
static int stlmfs_init_fs_context(struct fs_context *fc)
{
+ struct stlmfs_fs_context *ctx;
+
+ ctx = kzalloc_obj(*ctx);
+ if (!ctx)
+ return -ENOMEM;
+
+ /* defaults */
+ ctx->uid = GLOBAL_ROOT_UID;
+ ctx->gid = GLOBAL_ROOT_GID;
+ ctx->umask = SCMI_TLM_DEFAULT_UMASK;
+
+ fc->fs_private = ctx;
fc->ops = &stlmfs_fc_ops;
return 0;
@@ -1414,11 +1550,15 @@ static int stlmfs_init_fs_context(struct fs_context *fc)
static void stlmfs_kill_sb(struct super_block *sb)
{
+ struct stlmfs_sb_info *sbi = sb->s_fs_info;
+
mutex_lock(&stlmfs_mtx);
stlmfs_sb = NULL;
mutex_unlock(&stlmfs_mtx);
kill_anon_super(sb);
+
+ kfree(sbi);
}
static struct file_system_type scmi_telemetry_fs = {
--
2.54.0
More information about the linux-arm-kernel
mailing list