"2. The early init code may which to pass some content, but not all, to!
? "2. The early init code may wish to pass some content, but not all, to" Kind regards, Ulrich Windl > -----Original Message----- > From: systemd-devel <[email protected]> On > Behalf Of H. Peter Anvin > Sent: Saturday, January 24, 2026 1:40 AM > To: Alexander Viro <[email protected]>; Christian Brauner > <[email protected]>; Jan Kara <[email protected]>; Jonathan Corbet > <[email protected]>; H. Peter Anvin <[email protected]> > Cc: [email protected]; [email protected]; linux- > [email protected]; Lennart Poettering <[email protected]>; > [email protected] > Subject: [EXT] [systemd-devel] [RFC PATCH 2/3] initramfs: support mounting > filesystems during initramfs expansion > > Expanding the initramfs contents directly into the rootfs is not > always desirable. Allow the initramfs to contain instructions to mount > additional filesystems before continuing processing. > > This is done by a magic filename !!!MOUNT!!! which, instead of being > expanded as a file, is processed as a simplified fstab(5) mount > specification (see following documentation patch.) > > Some reasons this may be desirable: > > 1. The early init code may wish to expand into a separate tmpfs so it > can be pivoted, remounted, or efficiently garbage collected on > umount. > 2. The early init code may which to pass some content, but not all, to > the main userspace. This allows mounting a second tmpfs that can > then be mounted underneath somewhere the main root without having > to copy the contents. > 3. The main userspace can retain the rootfs as the only root. In that > case, the initramfs contents can be expanded into a tmpfs that is > mounted at a different path. One use case for that might be > /lib/modules. > 4. It may be convenient for the early init code to have /dev, /proc > and /sys pre-mounted. > > Signed-off-by: H. Peter Anvin (Intel) <[email protected]> > --- > init/initramfs.c | 98 > ++++++++++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 95 insertions(+), 3 deletions(-) > > diff --git a/init/initramfs.c b/init/initramfs.c > index 6ddbfb17fb8f..681ab59ab6cd 100644 > --- a/init/initramfs.c > +++ b/init/initramfs.c > @@ -222,6 +222,7 @@ static __initdata enum state { > GotName, > CopyFile, > GotSymlink, > + GotMountpoint, > Reset > } state, next_state; > > @@ -254,6 +255,9 @@ static void __init read_into(char *buf, unsigned size, > enum state next) > } > } > > +#define SYMLINK_BUF_SIZE (PATH_MAX + N_ALIGN(PATH_MAX) + 1) > +#define NAME_BUF_SIZE N_ALIGN(PATH_MAX) > + > static __initdata char *header_buf, *symlink_buf, *name_buf; > > static int __init do_start(void) > @@ -355,6 +359,37 @@ static int __init maybe_link(void) > return 0; > } > > +static int __init maybe_mountpoint(void) > +{ > + static const char mount_magic_name[] __initconst = "!!!MOUNT!!!"; > + const unsigned long mount_magic_len = sizeof(mount_magic_name)- > 1; > + unsigned long len = name_len-1; > + const char *name = collected; > + > + if (!S_ISREG(mode)) > + return 0; > + if (len < mount_magic_len) > + return 0; > + if (len > mount_magic_len && name[len-mount_magic_len] != '/') > + return 0; > + if (memcmp(name+len-mount_magic_len, mount_magic_name, > mount_magic_len)) > + return 0; > + > + /* Factor out the parent directory name and save it in name_buf */ > + len -= mount_magic_len; > + if (!len) > + name_buf[len++] = '.'; > + else > + memmove(name_buf, name, len); > + name_buf[len] = '\0'; > + > + if (body_len >= SYMLINK_BUF_SIZE) > + return 1; /* Option file too large */ > + > + read_into(symlink_buf, body_len, GotMountpoint); > + return 1; > +} > + > static __initdata struct file *wfile; > static __initdata loff_t wfile_pos; > > @@ -375,6 +410,10 @@ static int __init do_name(void) > free_hash(); > return 0; > } > + > + if (maybe_mountpoint()) > + return 0; > + > clean_path(collected, mode); > if (S_ISREG(mode)) { > int ml = maybe_link(); > @@ -392,6 +431,7 @@ static int __init do_name(void) > vfs_fchmod(wfile, mode); > if (body_len) > vfs_truncate(&wfile->f_path, body_len); > + > state = CopyFile; > } > } else if (S_ISDIR(mode)) { > @@ -451,6 +491,56 @@ static int __init do_symlink(void) > return 0; > } > > +static int __init do_mountpoint(void) > +{ > + int ret; > + char *p, *ep; > + const char *opts[3]; > + const char *opstart; > + unsigned long n; > + > + state = SkipIt; > + next_state = Reset; > + > + memset(opts, 0, sizeof(opts)); > + > + /* Default filesystem type */ > + opts[0] = IS_ENABLED(CONFIG_TMPFS) ? "tmpfs" : "ramfs"; > + > + p = collected; > + ep = p + body_len; > + n = 0; > + opstart = NULL; > + while (p < ep && n < 3) { > + char c = *p; > + if (c <= ' ') { > + if (opstart) { > + *p = '\0'; > + opts[n++] = opstart; > + opstart = NULL; > + } > + } else { > + if (!opstart) > + opstart = p; > + } > + p++; > + } > + > + if (!opts[1]) > + opts[1] = opts[0]; > + > + ret = init_mount(opts[0], name_buf, opts[1], 0, opts[2]); > + if (!ret) { > + init_chown(name_buf, uid, gid, 0); > + init_chmod(name_buf, mode); /* S_IFMT is ignored by > chmod() */ > + dir_add(name_buf, name_len, mtime); > + } else { > + pr_err("initramfs mount %s %s %s failed, error %d\n", > + opts[0], name_buf, opts[1], ret); > + } > + return 0; > +} > + > static __initdata int (*actions[])(void) = { > [Start] = do_start, > [Collect] = do_collect, > @@ -459,6 +549,7 @@ static __initdata int (*actions[])(void) = { > [GotName] = do_name, > [CopyFile] = do_copy, > [GotSymlink] = do_symlink, > + [GotMountpoint] = do_mountpoint, > [Reset] = do_reset, > }; > > @@ -515,8 +606,8 @@ char * __init unpack_to_rootfs(char *buf, unsigned > long len) > const char *compress_name; > struct { > char header[CPIO_HDRLEN]; > - char symlink[PATH_MAX + N_ALIGN(PATH_MAX) + 1]; > - char name[N_ALIGN(PATH_MAX)]; > + char symlink[SYMLINK_BUF_SIZE]; > + char name[NAME_BUF_SIZE]; > } *bufs = kmalloc(sizeof(*bufs), GFP_KERNEL); > > if (!bufs)
