[Buildroot] [PATCH 2/7] system: add overlayfs option for ro /var

Norbert Lange nolange79 at gmail.com
Sun Jan 15 12:52:47 UTC 2023


This commit adds an alternative that has the following characteristics:

-   Dont depend on anything being available, except the
    API File Systems [1].

    As /var is meant to be available before normal and even some early
    services are running.

-   Be a clean drop-in, that can be trivially added / removed.

-   Depend on overlayfs being available in the kernel.

-   Units are supposed to be reusable for custom solutions.

Further, a few subdirectories are introduced, which hopefully can serve
as template for similar uses.

Buildroot owns /run/.br, bind mounts end up in /run/.br/bnd,
overlay directories in /run/.br/ovl.

The sequence is rather important, and the systemd mount units serve as
reliable "sequence point" (cant be replicated otherwise).

What we need to do is mount /var in its usable state, and block
units depending on this before we are finished.
This includes:

-   Other mounts targeting a subdirectory in /var.

-   Units using 'RequiresMountsFor' targeting /var or subdirectories.

    Most notable `basic.target` which most units depend upon by default.

-   Units that are (transitively) odered after one of the above.

As comparison, the /var factory introduces issues here, as
systemd-tmpfiles-setup.service will require all mounts to be finished
before, as well als journald running.
(That means /var will already be used while and before initialization).

The necessary steps are:

1.  Bindmount /var to /run/.br/bnd/var

    This is done by using the template br-bindmount-run at .service.

2.  Mount an tmpfs and prepare the overlay at /run/.br/ovl/var

    This is done by using the template br-overlay-prepare at .service,
    the mounting command is separated so that users can further
    customize the behaviour.

    The choice of using a service seems more flexible, as the
    mount units lack several options of the mount command.
    As a gut feeling the fileystems mounted under /run should
    not be accessible or propagate their mounts,
    hence --make-private.
    (Or you might not use a mount at all).

3.  Finally mount the overlay with a normal mount unit

    Dependencies on the template-instances of 1. and 2. will ensure
    correct odering before.
    By nature off being a systemd mount unit the remaining units
    will be automatically order after this unit if necessary.

As example, consider using /dev/sdc1 as upper layer for var,
this can be archived by swapping out just the line executing
the mount itself:

[Service]
ExecStart=
ExecStart=/bin/mount --make-private -n /dev/sdc1 ${OVERLAY_DIR}

[1] - https://www.freedesktop.org/wiki/Software/systemd/APIFileSystems/

Cc: Yann E. MORIN <yann.morin.1998 at free.fr>
Cc: Romain Naour <romain.naour at smile.fr>
Cc: Jérémy Rosen <jeremy.rosen at smile.fr>
Signed-off-by: Norbert Lange <nolange79 at gmail.com>
---
 .../overlayfs/br-bindmount-run at .service       | 26 +++++++++++++++++++
 .../overlayfs/br-overlay-prepare at .service     | 26 +++++++++++++++++++
 .../overlayfs/overlay.mount.in                | 16 ++++++++++++
 .../skeleton-init-systemd.mk                  | 17 ++++++++++++
 system/Config.in                              | 13 ++++++++++
 5 files changed, 98 insertions(+)
 create mode 100644 package/skeleton-init-systemd/overlayfs/br-bindmount-run at .service
 create mode 100644 package/skeleton-init-systemd/overlayfs/br-overlay-prepare at .service
 create mode 100644 package/skeleton-init-systemd/overlayfs/overlay.mount.in

diff --git a/package/skeleton-init-systemd/overlayfs/br-bindmount-run at .service b/package/skeleton-init-systemd/overlayfs/br-bindmount-run at .service
new file mode 100644
index 0000000000..ce944efd92
--- /dev/null
+++ b/package/skeleton-init-systemd/overlayfs/br-bindmount-run at .service
@@ -0,0 +1,26 @@
+[Unit]
+Description=Bind-mount rootfs directory (/%I) to /run
+Documentation=man:file-hierarchy(7)
+ConditionPathIsSymbolicLink=!/%I
+DefaultDependencies=no
+Conflicts=umount.target
+Before=umount.target
+
+# Needs to run after rootfs is properly mounted
+# and before regular mounts might interfere.
+After=systemd-remount-fs.service
+Before=local-fs-pre.target
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+# dont fail if common dirs already exist
+ExecStartPre=/bin/mkdir -m755 -p /run/.br
+ExecStartPre=/bin/mkdir -m700 -p /run/.br/bnd
+
+ExecStartPre=/bin/mkdir -m700 -p /run/.br/bnd/%I
+ExecStart=/bin/mount --make-private -n --bind -o ro /%I /run/.br/bnd/%I
+
+# lazy unmount, dont block shutdown under any circumstances
+ExecStop=/bin/umount -n -l /run/.br/bnd/%I
+ExecStopPost=-/bin/rmdir /run/.br/bnd/%I
diff --git a/package/skeleton-init-systemd/overlayfs/br-overlay-prepare at .service b/package/skeleton-init-systemd/overlayfs/br-overlay-prepare at .service
new file mode 100644
index 0000000000..86b32900dd
--- /dev/null
+++ b/package/skeleton-init-systemd/overlayfs/br-overlay-prepare at .service
@@ -0,0 +1,26 @@
+[Unit]
+Description=Mount and prepare tmpfs for overlay (/%I)
+Documentation=man:file-hierarchy(7)
+ConditionPathIsSymbolicLink=!/%I
+DefaultDependencies=no
+Conflicts=umount.target
+Before=local-fs.target umount.target
+# prepare for systemd mount units aswell
+RequiresMountsFor=/run/.br/ovl/%I
+
+[Service]
+Environment="OVERLAY_DIR=/run/.br/ovl/%I"
+Type=oneshot
+RemainAfterExit=yes
+# dont fail if common dirs already exist
+ExecStartPre=/bin/mkdir -m755 -p /run/.br
+ExecStartPre=/bin/mkdir -m700 -p /run/.br/ovl
+
+ExecStartPre=/bin/mkdir -m700 -p ${OVERLAY_DIR}
+# Create an override and edit this line for customization
+ExecStart=/bin/mount --make-private -n -t tmpfs tmpfs_br_ovl ${OVERLAY_DIR}
+ExecStartPost=/bin/mkdir -p ${OVERLAY_DIR}/up ${OVERLAY_DIR}/wd
+
+# lazy unmount, dont block shutdown under any circumstances
+ExecStop=/bin/umount -n -l ${OVERLAY_DIR}
+ExecStopPost=/bin/rmdir ${OVERLAY_DIR}
diff --git a/package/skeleton-init-systemd/overlayfs/overlay.mount.in b/package/skeleton-init-systemd/overlayfs/overlay.mount.in
new file mode 100644
index 0000000000..84f4d9ee47
--- /dev/null
+++ b/package/skeleton-init-systemd/overlayfs/overlay.mount.in
@@ -0,0 +1,16 @@
+[Unit]
+Description=Variable storage (/@PATH@)
+Documentation=man:file-hierarchy(7)
+ConditionPathIsSymbolicLink=!/@PATH@
+
+After=br-bindmount-run@@PATH at .service
+Requires=br-bindmount-run@@PATH at .service
+
+After=br-overlay-prepare@@PATH at .service
+BindsTo=br-overlay-prepare@@PATH at .service
+
+[Mount]
+Type=overlay
+What=br_ovl_ at PATH@
+Where=/@PATH@
+Options=redirect_dir=on,index=on,xino=on,lowerdir=/run/.br/bnd/@PATH@,upperdir=/run/.br/ovl/@PATH@/up,workdir=/run/.br/ovl/@PATH@/wd
diff --git a/package/skeleton-init-systemd/skeleton-init-systemd.mk b/package/skeleton-init-systemd/skeleton-init-systemd.mk
index fb15552f99..ad529cddf6 100644
--- a/package/skeleton-init-systemd/skeleton-init-systemd.mk
+++ b/package/skeleton-init-systemd/skeleton-init-systemd.mk
@@ -57,6 +57,23 @@ define SKELETON_INIT_SYSTEMD_PRE_ROOTFS_VAR
 endef
 SKELETON_INIT_SYSTEMD_ROOTFS_PRE_CMD_HOOKS += SKELETON_INIT_SYSTEMD_PRE_ROOTFS_VAR
 endif  # BR2_INIT_SYSTEMD_VAR_FACTORY
+
+ifeq ($(BR2_INIT_SYSTEMD_VAR_OVERLAYFS),y)
+define SKELETON_INIT_SYSTEMD_LINUX_CONFIG_FIXUPS
+	$(call KCONFIG_ENABLE_OPT,CONFIG_OVERLAY_FS)
+endef
+define SKELETON_INIT_SYSTEMD_POST_INSTALL_VAR_OVERLAYFS
+	sed 's, at PATH@,var,g' $(SKELETON_INIT_SYSTEMD_PKGDIR)/overlayfs/overlay.mount.in >$(@D)/var.mount
+	$(INSTALL) -D -m 0644 $(@D)/var.mount $(TARGET_DIR)/usr/lib/systemd/system/var.mount
+	$(INSTALL) -D -m 0644 $(SKELETON_INIT_SYSTEMD_PKGDIR)/overlayfs/br-bindmount-run at .service \
+		$(TARGET_DIR)/usr/lib/systemd/system/br-bindmount-run at .service
+	$(INSTALL) -D -m 0644 $(SKELETON_INIT_SYSTEMD_PKGDIR)/overlayfs/br-overlay-prepare at .service \
+		$(TARGET_DIR)/usr/lib/systemd/system/br-overlay-prepare at .service
+	# /var mount gets pulled in automatically by basic.target
+endef
+SKELETON_INIT_SYSTEMD_POST_INSTALL_TARGET_HOOKS += SKELETON_INIT_SYSTEMD_POST_INSTALL_VAR_OVERLAYFS
+endif  # BR2_INIT_SYSTEMD_VAR_OVERLAYFS
+
 endif  # BR2_TARGET_GENERIC_REMOUNT_ROOTFS_RW
 
 ifeq ($(BR2_INIT_SYSTEMD_POPULATE_TMPFILES),y)
diff --git a/system/Config.in b/system/Config.in
index 87df031545..cdf383d0d4 100644
--- a/system/Config.in
+++ b/system/Config.in
@@ -187,6 +187,19 @@ config BR2_INIT_SYSTEMD_VAR_FACTORY
 	  var.mount unit, that overrides the What and Type, and possibly
 	  the Options and After, fields.
 
+config BR2_INIT_SYSTEMD_VAR_OVERLAYFS
+	bool "mount an overlayfs backed by a tmpfs"
+	help
+	  Mount an overlayfs on /var, with the upper as a tmpfs.
+
+	  You can customize the backing storage with an override, for
+	  ecample create this file and add the content following:
+	  /lib/systemd/system/br-overlay-prepare at var.service.d/mount.conf
+
+	  [Service]
+	  ExecStart=
+	  ExecStart=/bin/mount --make-private -n /dev/sdc1 ${OVERLAY_DIR}
+
 config BR2_INIT_SYSTEMD_VAR_NONE
 	bool "do nothing"
 	help
-- 
2.39.0




More information about the buildroot mailing list