Skip to content

Instantly share code, notes, and snippets.

@fathonix
Last active July 8, 2026 14:50
Show Gist options
  • Select an option

  • Save fathonix/bfdaf496f643b33b022cfee392ccbba6 to your computer and use it in GitHub Desktop.

Select an option

Save fathonix/bfdaf496f643b33b022cfee392ccbba6 to your computer and use it in GitHub Desktop.
persistent-overlayroot - overlayfs as rootfs with persistent backing storage
#!/bin/sh
# persistent-overlayroot - overlayfs as rootfs with persistent backing storage.
# Licensed under MIT. (c) 2026 Aldo Adirajasa Fathoni
# Install to /etc/initramfs-tools/hooks/fuse-overlayfs then chmod 755
# Make sure the fuse package has been installed
set -e
case "$1" in
prereqs) echo "fuse"; exit 0;;
esac
. /usr/share/initramfs-tools/hook-functions
copy_exec /usr/bin/fuse-overlayfs /usr/bin
exit 0
#!/bin/sh
# persistent-overlayroot - overlayfs as rootfs with persistent backing storage.
# Licensed under MIT. (c) 2026 Aldo Adirajasa Fathoni
# Install this to /etc/initramfs-tools/scripts/init-bottom/, remember to chmod 755
# TODO:
# - Multi-level upper dirs
# - Port to other initramfs generators
case $1 in
prereqs) echo ""; exit 0;;
esac
. /scripts/functions
ovlrootmnt="$rootmnt"
ovlbasedir=/overlay
ovllowerdir="${ovlbasedir}/lower"
ovlupperdir="${ovlbasedir}/upper"
ovlworkdir="${ovlbasedir}/work"
ovldebug=0
ovlfuse=0
ovlskip=0
ovldesc=""
log() { "log_${1}_msg" "persistent-overlayroot: $2"; }
log_begin() { log begin "$*"; }
log_end() { log end "$*"; }
log_success() { log success "$*"; }
log_warn() { log warning "$*"; }
log_fail() { log failure "$*"; }
fail() { log_fail "$*"; panic "persistent-overlayroot failed! Dropping to a shell..."; }
exit_early() { log_end "$*"; exit 0; }
add_desc() { [ -z "$ovldesc" ] && ovldesc="$*" || ovldesc=", ${*}"; }
read_kernel_cmdline() {
local cmdline="" ovlarg=""
read cmdline < /proc/cmdline ||
fail "Failed to read kernel cmdline"
for ovlarg in $cmdline; do
case $ovlarg in
overlayroot=*)
ovldev="${ovlarg#overlayroot=}"
;;
overlayrootflags=*)
ovldevopts="${ovlarg#overlayrootflags=}"
;;
overlayrootfstype=*)
ovldevtype="${ovlarg#overlayrootfstype=}"
;;
debugoverlayroot)
ovldebug=1
;;
fuseoverlayroot)
ovlfuse=1
;;
skipoverlayroot)
ovlskip=1
;;
esac
done
[ -z "$ovldev" ] && exit_early "overlayroot= not set. Skipping..."
[ $ovlskip -eq 1 ] && exit_early "skipoverlayroot was set. Skipping..."
}
mount_overlay() {
local ovldir="" ovlfscmd="mount -t overlay overlay"
[ ! -z "$ovldevtype" ] && ovldevtype="-t ${ovldevtype}"
[ ! -z "$ovldevopts" ] && ovldevopts="-o ${ovldevopts}"
mkdir -p "$ovlbasedir"
mount $ovldevtype "$ovldev" "$ovlbasedir" $ovldevopts ||
fail "Error mounting overlayroot"
for ovldir in "$ovllowerdir" "$ovlupperdir" "$ovlworkdir"; do
mkdir -p "$ovldir" ||
fail "Error creating directory ${ovldir}"
done
if [ $ovlfuse -eq 1 ]; then
log_begin "fuseoverlayroot was set, using fuse-overlayfs instead of kernel overlay"
# Prevent systemd from killing fuse-overlayfs https://systemd.io/ROOT_STORAGE_DAEMONS/
ovlfscmd="start-stop-daemon -S -a @fuse-overlayfs -x fuse-overlayfs --"
add_desc "fuse-overlayfs"
fi
mount --move "$ovlrootmnt" "$ovllowerdir" ||
fail "Error moving root mount to ${ovllowerdir}"
$ovlfscmd "$ovlrootmnt" \
-o "lowerdir=${ovllowerdir},upperdir=${ovlupperdir},workdir=${ovlworkdir}" ||
fail "Error mounting overlayfs"
mkdir -p "${ovlrootmnt}${ovlbasedir}"
mount --move "$ovlbasedir" "${ovlrootmnt}${ovlbasedir}" ||
fail "Error moving overlayroot base mount into overlayroot mount"
}
post_mount_overlay() {
[ $ovldebug -eq 1 ] && fail "Debugging was enabled, initiating crash..."
[ ! -z "$ovldesc" ] && ovldesc=" with ${ovldesc}"
}
log_begin "Setting up overlayfs as rootfs"
read_kernel_cmdline
mount_overlay
post_mount_overlay
log_success "Configured overlayfs as rootfs with ${ovldev} on top of ${ROOT}${ovldesc}"
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment