- "11"
- "13"
- "20"
+ - "21"
- "26"
- "30"
- "50"
- "11"
- "13"
- "20"
+ - "21"
- "26"
- "30"
- "50"
- "11"
- "13"
- "20"
+ - "21"
- "26"
- "30"
- "40"
- "10"
- "11"
- "20"
+ - "21"
- "26"
- "30"
- "31"
- "12"
- "13"
- "20"
+ - "21"
- "26"
- "30"
- "50"
be mounted read-only through a higher level transient overlay directory, has
been implemented through the multiple lower layers feature of OverlayFS.
+**rd.overlay=**__{LABEL=<label>|UUID=<uuid>|PARTUUID=<uuid>|PARTLABEL=<label>|/dev/<device>}__::
+Specifies the storage device for persistent overlay (for both live images and
+regular OverlayFS). When a block device is specified, it will be mounted and
+used for persistent overlay storage. For live images with LABEL= specification,
+if the labeled partition does not exist, it will be automatically created using
+available free space on the device.
++
+Supported device specifications:
++
+--
+* _LABEL=<label>_ - Use the device with the specified filesystem label.
+* _UUID=<uuid>_ - Use the device with the specified UUID.
+* _PARTUUID=<uuid>_ - Use the device with the specified partition UUID.
+* _PARTLABEL=<label>_ - Use the device with the specified partition label.
+* _/dev/<device>_ - Use the specified device path directly.
+--
++
+[listing]
+.Examples
+----
+rd.overlay=LABEL=persist
+rd.overlay=UUID=12345678-1234-1234-1234-123456789abc
+rd.overlay=/dev/sdb1
+----
+
Booting live images
~~~~~~~~~~~~~~~~~~~
Requires the dracut 'dmsquash-live' module.
install() {
inst_hook pre-mount 01 "$moddir/prepare-overlayfs.sh"
- inst_hook mount 01 "$moddir/mount-overlayfs.sh" # overlay on top of block device
- inst_hook pre-pivot 10 "$moddir/mount-overlayfs.sh" # overlay on top of network device (e.g. nfs)
+ inst_hook mount 01 "$moddir/mount-overlayfs.sh" # overlay on top of block device
+ inst_hook pre-pivot 00 "$moddir/prepare-overlayfs.sh" # prepare for network root (e.g. nfs)
+ inst_hook pre-pivot 10 "$moddir/mount-overlayfs.sh" # overlay on top of network device
}
getargbool 0 rd.overlayfs -d rd.live.overlay.overlayfs && overlayfs="yes"
getargbool 0 rd.overlay.readonly -d rd.live.overlayfs.readonly && readonly_overlay="--readonly" || readonly_overlay=""
+overlay=$(getarg rd.overlay -d rd.live.overlay)
-[ -n "$overlayfs" ] || return 0
+[ -n "$overlayfs" ] || [ -n "$overlay" ] || return 0
+
+# Only proceed if prepare-overlayfs.sh has run and set up rootfsbase.
+# This handles the case where root isn't available yet (e.g., network root like NFS).
+# The script will be called again at pre-pivot when the root is mounted.
+[ -e /run/rootfsbase ] || return 0
if [ -n "$readonly_overlay" ] && [ -h /run/overlayfs-r ]; then
ovlfs=lowerdir=/run/overlayfs-r:/run/rootfsbase
getargbool 0 rd.overlayfs -d rd.live.overlay.overlayfs && overlayfs="yes"
getargbool 0 rd.overlay.reset -d rd.live.overlay.reset && reset_overlay="yes"
+overlay=$(getarg rd.overlay -d rd.live.overlay)
-[ -n "$overlayfs" ] || return 0
+[ -n "$overlayfs" ] || [ -n "$overlay" ] || return 0
+
+overlay_mode="tmpfs"
+overlay_device=""
+
+case "$overlay" in
+ LABEL=* | UUID=* | PARTLABEL=* | PARTUUID=* | /dev/*)
+ overlay_mode="device"
+ overlay_device=$(label_uuid_to_dev "$overlay")
+ if [ ! -b "$overlay_device" ]; then
+ warn "Failed to resolve device from '$overlay', falling back to tmpfs"
+ overlay_mode="tmpfs"
+ fi
+ ;;
+ *)
+ # For dmsquash-live compatibility, any other format uses tmpfs
+ overlay_mode="tmpfs"
+ ;;
+esac
+
+# Skip if root not mounted and rootfsbase not set up by another module (e.g. dmsquash-live)
+if ! ismounted "$NEWROOT" && ! [ -e /run/rootfsbase ]; then
+ return 0
+fi
if ! [ -e /run/rootfsbase ]; then
mkdir -m 0755 -p /run/rootfsbase
mount --bind "$NEWROOT" /run/rootfsbase
fi
-mkdir -m 0755 -p /run/overlayfs
-mkdir -m 0755 -p /run/ovlwork
+if [ "$overlay_mode" = "device" ] && [ -n "$overlay_device" ]; then
+ info "Attempting to use persistent overlay on $overlay_device"
+
+ wait_for_dev -n "$overlay_device"
+
+ mkdir -m 0755 -p /run/overlayfs-backing
+
+ if mount "$overlay_device" /run/overlayfs-backing; then
+ info "Successfully mounted persistent overlay on $overlay_device"
+
+ mkdir -m 0755 -p /run/overlayfs-backing/overlay
+ mkdir -m 0755 -p /run/overlayfs-backing/ovlwork
+
+ ln -sf /run/overlayfs-backing/overlay /run/overlayfs
+ ln -sf /run/overlayfs-backing/ovlwork /run/ovlwork
+ else
+ warn "Failed to mount $overlay_device, falling back to tmpfs"
+ overlay_mode="tmpfs"
+ fi
+fi
+
+if [ "$overlay_mode" = "tmpfs" ]; then
+ info "Using tmpfs overlay (changes will not persist across reboots)"
+
+ [ -d /run/overlayfs ] || {
+ mkdir -m 0755 -p /run/initramfs/overlay/overlayfs
+ mkdir -m 0755 -p /run/initramfs/overlay/ovlwork
+ ln -sf /run/initramfs/overlay/overlayfs /run/overlayfs
+ ln -sf /run/initramfs/overlay/ovlwork /run/ovlwork
+ }
+fi
+
if [ -n "$reset_overlay" ] && [ -h /run/overlayfs ]; then
ovlfsdir=$(readlink /run/overlayfs)
info "Resetting the OverlayFS overlay directory."
--- /dev/null
+include ../Makefile.testdir
--- /dev/null
+#!/bin/sh
+
+if ! grep -q " overlay " /proc/mounts; then
+ echo "overlay filesystem not found in /proc/mounts" >> /run/failed
+fi
+
+if ! echo > /test-overlay-write; then
+ echo "overlay is not writable" >> /run/failed
+fi
+
+if grep -qE 'rd\.overlay=(LABEL|UUID|PARTUUID|PARTLABEL|/dev/)' /proc/cmdline; then
+ if grep -q "rd.overlay=LABEL=NONEXISTENT" /proc/cmdline; then
+ if grep -q "/run/overlayfs-backing" /proc/mounts; then
+ echo "non-existent device should have fallen back to tmpfs but backing is mounted" >> /run/failed
+ fi
+ else
+ if ! grep -q "/run/overlayfs-backing" /proc/mounts; then
+ echo "persistent overlay device not mounted at /run/overlayfs-backing" >> /run/failed
+ fi
+ fi
+else
+ # tmpfs mode - verify persistent backing is NOT mounted
+ if grep -q "/run/overlayfs-backing" /proc/mounts; then
+ echo "tmpfs mode but persistent backing is mounted at /run/overlayfs-backing" >> /run/failed
+ fi
+fi
+
+# Dump /proc/mounts at the end if there were any failures for easier debugging
+if [ -s /run/failed ]; then
+ {
+ echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> /proc/mounts >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
+ cat /proc/mounts
+ echo "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< /proc/mounts <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
+ } >> /run/failed
+fi
--- /dev/null
+#!/usr/bin/env bash
+set -eu
+# shellcheck disable=SC2034
+TEST_DESCRIPTION="Test overlayfs module with persistent device overlay"
+
+client_run() {
+ local test_name="$1"
+ shift
+ local client_opts="$*"
+
+ client_test_start "$test_name"
+
+ declare -a disk_args=()
+ qemu_add_drive disk_args "$TESTDIR"/root.img root
+ qemu_add_drive disk_args "$TESTDIR"/overlay.img overlay
+
+ "$testdir"/run-qemu -nic none \
+ "${disk_args[@]}" \
+ -append "$TEST_KERNEL_CMDLINE root=LABEL=dracut $client_opts" \
+ -initrd "$TESTDIR"/initramfs.testing
+ check_qemu_log
+
+ client_test_end
+}
+
+test_run() {
+ local overlay_uuid
+ overlay_uuid=$(blkid -s UUID -o value "$TESTDIR"/overlay.img)
+
+ client_run "tmpfs overlay" "rd.overlayfs=1"
+ client_run "persistent device overlay (LABEL)" "rd.overlay=LABEL=OVERLAY"
+ client_run "persistent device overlay (UUID)" "rd.overlay=UUID=$overlay_uuid"
+ client_run "persistent device overlay (device path)" \
+ "rd.overlay=/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_overlay"
+ client_run "fallback to tmpfs (non-existent LABEL)" "rd.overlay=LABEL=NONEXISTENT"
+}
+
+test_setup() {
+ call_dracut --tmpdir "$TESTDIR" \
+ --add-confdir test-root \
+ -i ./assertion.sh /assertion.sh \
+ -f "$TESTDIR"/initramfs.root
+
+ build_ext4_image "$TESTDIR"/dracut.*/initramfs/ "$TESTDIR"/root.img dracut
+
+ rm -f "$TESTDIR"/overlay.img
+ truncate -s 32M "$TESTDIR"/overlay.img
+ mkfs.ext4 -q -L OVERLAY "$TESTDIR"/overlay.img
+
+ test_dracut --add overlayfs
+}
+
+# shellcheck disable=SC1090
+. "$testdir"/test-functions