* Re: [PATCH] devtmpfs: restore mount option reconfiguration on get_tree
2026-08-10 8:34 [PATCH] devtmpfs: restore mount option reconfiguration on get_tree Simon Liebold
@ 2026-08-10 23:23 ` Eric Sandeen
2026-08-12 21:44 ` [PATCH V2] " Eric Sandeen
1 sibling, 0 replies; 5+ messages in thread
From: Eric Sandeen @ 2026-08-10 23:23 UTC (permalink / raw)
To: Simon Liebold, Greg Kroah-Hartman, Rafael J . Wysocki,
Danilo Krummrich, Christian Brauner, driver-core, linux-kernel,
Alexander Viro
Cc: stable
On 8/10/26 3:34 AM, Simon Liebold wrote:
> Commit cb0e0a8bf4e1 ("devtmpfs: replace ->mount with ->get_tree in
> public instance") converted devtmpfs to the new mount API but dropped
> the reconfigure_single() call that reapplied mount options.
>
> This causes userspace-requested mount options to be silently ignored.
hohum, I'm not sure how I managed to re-break that - I had cc'd neilb
precisely because I knew he had fixed a regression here before, so
it must have been on my mind.
Looking back to an IRC conversation with viro I think I diverged from
his recommendation though I'm not sure why.
I had credited viro in my changelog, but looking back I don't think I
faithfully implemented what he had suggested. I'd like to revisit that
and maybe propose a different solution to fixing this.
(One concern is approach is that I think it is now passing an fc which
was not "for_reconfigure" to reconfigure, for starters, but that's on
me I think for setting it up this way ...)
Give me a day or so to try to page all this back in again? And sorry
for breaking it. :(
Thanks,
-Eric
> To reproduce, boot a system where systemd mounts /dev with a size
> option (e.g. size=4m), then check the actual size:
>
> findmnt -n -o SIZE --bytes /dev
>
> On an affected kernel this returns ~50% of RAM instead of the
> requested size.
>
> Fix by calling fc->ops->reconfigure() after obtaining the superblock
> reference in devtmpfs_get_tree().
>
> Fixes: cb0e0a8bf4e1 ("devtmpfs: replace ->mount with ->get_tree in public instance")
> Cc: stable@vger.kernel.org
> Signed-off-by: Simon Liebold <simonlie@amazon.de>
> ---
> drivers/base/devtmpfs.c | 13 ++++++++++++-
> 1 file changed, 12 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
> index b1c4ceb65026e..44683dde04377 100644
> --- a/drivers/base/devtmpfs.c
> +++ b/drivers/base/devtmpfs.c
> @@ -72,14 +72,25 @@ static struct file_system_type internal_fs_type = {
> .kill_sb = kill_anon_super,
> };
>
> -/* Simply take a ref on the existing mount */
> +/* Take a ref on the existing mount and reconfigure to apply mount options. */
> static int devtmpfs_get_tree(struct fs_context *fc)
> {
> struct super_block *sb = mnt->mnt_sb;
> + int err;
>
> atomic_inc(&sb->s_active);
> down_write(&sb->s_umount);
> fc->root = dget(sb->s_root);
> +
> + if (fc->ops->reconfigure) {
> + err = fc->ops->reconfigure(fc);
> + if (err) {
> + dput(fc->root);
> + fc->root = NULL;
> + deactivate_locked_super(sb);
> + return err;
> + }
> + }
> return 0;
> }
>
>
> base-commit: f5098b6bae761e346ebcd9da7f95622c04733cff
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH V2] devtmpfs: restore mount option reconfiguration on get_tree
2026-08-10 8:34 [PATCH] devtmpfs: restore mount option reconfiguration on get_tree Simon Liebold
2026-08-10 23:23 ` Eric Sandeen
@ 2026-08-12 21:44 ` Eric Sandeen
2026-08-13 13:51 ` Simon Liebold
2026-08-25 14:25 ` Christian Brauner
1 sibling, 2 replies; 5+ messages in thread
From: Eric Sandeen @ 2026-08-12 21:44 UTC (permalink / raw)
To: Simon Liebold, Greg Kroah-Hartman, Rafael J . Wysocki,
Danilo Krummrich, Christian Brauner, driver-core, linux-kernel,
Alexander Viro
Cc: stable
commit cb0e0a8bf4e1 ("devtmpfs: replace ->mount with ->get_tree in
public instance") converted the public devtmpfs instance to the new
mount API but broke the ability to reconfigure the shared superblock
options via subsequent mount() calls, as had been fixed once in
a6097180d884 ("devtmpfs regression fix: reconfigure on each mount")
This makes boot-time defaults permanent.
Fix this using an approach suggested by Al Viro: at init_fs_context
time, create a reconfigure-mode context via fs_context_for_reconfigure()
and save it in fc->fs_private. The devtmpfs parse ops can then use
this context to parse options appropriately for the underlying filesystem.
This also removes the devtmpfs_configure_context() one-time ops-copying
approach and the global mutable ops table it required.
Fixes: cb0e0a8bf4e1 ("devtmpfs: replace ->mount with ->get_tree in public instance")
Reported-by: Simon Liebold <simonlie@amazon.de>
Cc: stable@vger.kernel.org
Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
I think this might be a better approach; more involved, but it uses the
right type of context for reconfigure and avoids the nasty ops copying
I wrote the first time. :(
First, sorry for breaking this. Second, Al please yell if I have mis-attributed
or mis-implemented your suggestion from months back. Third, I have done only
light testing on this but it seems ok, built and booted with CONFIG_TMPFS=y
and confirmed that a fresh "mount" with new options takes hold, and confirmed
it builds without CONFIG_TMPFS configured though I don't have a system
that wants to boot that config.
Thoughts?
drivers/base/devtmpfs.c | 108 ++++++++++++++++++++++++----------------
1 file changed, 64 insertions(+), 44 deletions(-)
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index b1c4ceb65026..c32d3b963f2e 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -72,39 +72,90 @@ static struct file_system_type internal_fs_type = {
.kill_sb = kill_anon_super,
};
-/* Simply take a ref on the existing mount */
+struct devtmpfs_context {
+ struct fs_context *fc;
+};
+
+static void devtmpfs_free(struct fs_context *fc)
+{
+ struct devtmpfs_context *ctx = fc->fs_private;
+
+ if (ctx) {
+ put_fs_context(ctx->fc);
+ kfree(ctx);
+ }
+}
+
+static int devtmpfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
+{
+ struct devtmpfs_context *ctx = fc->fs_private;
+
+ return ctx->fc->ops->parse_param(ctx->fc, param);
+}
+
+static int devtmpfs_parse_monolithic(struct fs_context *fc, void *data)
+{
+ struct devtmpfs_context *ctx = fc->fs_private;
+
+ if (ctx->fc->ops->parse_monolithic)
+ return ctx->fc->ops->parse_monolithic(ctx->fc, data);
+ return generic_parse_monolithic(ctx->fc, data);
+}
+
static int devtmpfs_get_tree(struct fs_context *fc)
{
+ struct devtmpfs_context *ctx = fc->fs_private;
struct super_block *sb = mnt->mnt_sb;
+ int err;
atomic_inc(&sb->s_active);
down_write(&sb->s_umount);
+
+ if (ctx->fc->ops->reconfigure) {
+ err = ctx->fc->ops->reconfigure(ctx->fc);
+ if (err) {
+ deactivate_locked_super(sb);
+ return err;
+ }
+ }
+
fc->root = dget(sb->s_root);
return 0;
}
-/* Ops are filled in during init depending on underlying shmem or ramfs type */
-static struct fs_context_operations devtmpfs_context_ops = {};
+static const struct fs_context_operations devtmpfs_context_ops = {
+ .free = devtmpfs_free,
+ .parse_param = devtmpfs_parse_param,
+ .parse_monolithic = devtmpfs_parse_monolithic,
+ .get_tree = devtmpfs_get_tree,
+};
-/* Call the underlying initialization and set to our ops */
static int devtmpfs_init_fs_context(struct fs_context *fc)
{
- int ret;
-#ifdef CONFIG_TMPFS
- ret = shmem_init_fs_context(fc);
-#else
- ret = ramfs_init_fs_context(fc);
-#endif
- if (ret < 0)
- return ret;
+ struct devtmpfs_context *ctx;
+ int err;
+
+ ctx = kzalloc_obj(struct devtmpfs_context);
+ if (!ctx)
+ return -ENOMEM;
+
+ /* Each mount will reconfigure the shared superblock w/ new options */
+ ctx->fc = fs_context_for_reconfigure(mnt->mnt_root,
+ mnt->mnt_sb->s_flags, MS_RMT_MASK);
+ if (IS_ERR(ctx->fc)) {
+ err = PTR_ERR(ctx->fc);
+ kfree(ctx);
+ return err;
+ }
+ fc->fs_private = ctx;
fc->ops = &devtmpfs_context_ops;
return 0;
}
static struct file_system_type dev_fs_type = {
- .name = "devtmpfs",
+ .name = "devtmpfs",
.init_fs_context = devtmpfs_init_fs_context,
};
@@ -442,31 +493,6 @@ static int __ref devtmpfsd(void *p)
return 0;
}
-/*
- * Get the underlying (shmem/ramfs) context ops to build ours
- */
-static int devtmpfs_configure_context(void)
-{
- struct fs_context *fc;
-
- fc = fs_context_for_reconfigure(mnt->mnt_root, mnt->mnt_sb->s_flags,
- MS_RMT_MASK);
- if (IS_ERR(fc))
- return PTR_ERR(fc);
-
- /* Set up devtmpfs_context_ops based on underlying type */
- devtmpfs_context_ops.free = fc->ops->free;
- devtmpfs_context_ops.dup = fc->ops->dup;
- devtmpfs_context_ops.parse_param = fc->ops->parse_param;
- devtmpfs_context_ops.parse_monolithic = fc->ops->parse_monolithic;
- devtmpfs_context_ops.get_tree = &devtmpfs_get_tree;
- devtmpfs_context_ops.reconfigure = fc->ops->reconfigure;
-
- put_fs_context(fc);
-
- return 0;
-}
-
/*
* Create devtmpfs instance, driver-core devices will add their device
* nodes here.
@@ -482,12 +508,6 @@ int __init devtmpfs_init(void)
return PTR_ERR(mnt);
}
- err = devtmpfs_configure_context();
- if (err) {
- pr_err("unable to configure devtmpfs type %d\n", err);
- return err;
- }
-
err = register_filesystem(&dev_fs_type);
if (err) {
pr_err("unable to register devtmpfs type %d\n", err);
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread