Dracut Initramfs Module
Shanios ships a custom dracut module (99shanios) that adds three hooks to the initramfs. These hooks implement the two features that require early-boot access before the root filesystem is available to userspace: boot failure detection and /etc OverlayFS mounting.
Module Location
/usr/lib/dracut/modules.d/99shanios/
├── module-setup.sh ← declares hooks and binaries
├── shanios-boot-failure-hook.sh ← pre-mount (priority 90)
├── shanios-overlay-etc.sh ← pre-pivot (priority 50)
└── shanios-boot-success-clear.sh ← pre-pivot (priority 90)
The module is always included in Shanios initramfs builds (check() returns 0 unconditionally, and depends() declares no extra module dependencies beyond dracut's always-present base). It is rebuilt automatically by gen-efi configure <slot> on every deploy.
module-setup.sh's install() also pulls in what the three hooks need at early boot, since the initramfs is otherwise minimal:
- Binaries:
blkid mount umount mountpoint mkdir rmdir rm printf sed(viainst_multiple) - Kernel module:
overlay(viainstmods overlay), somount -t overlayworks before the real root's modules are reachable
Hook: shanios-boot-failure-hook.sh (pre-mount 90)
Runs: After LUKS unlock and device discovery, before the root Btrfs subvolume is mounted.
Purpose: Write a boot_hard_failure marker so that if root mount fails, the failure is recorded persistently and shani-update can detect it on the next boot.
Why dracut and not a systemd service: dracut has no "on mount failure" hook. The only reliable pattern is write-before-mount, clear-on-success. If root never mounts, the marker persists. If root mounts successfully, the shanios-boot-success-clear.sh hook at pre-pivot removes it.
What it does:
- Locates the Btrfs device by filesystem label (
shani_root) - Mounts
@dataread-write to a temporary mountpoint (/run/shanios-data-tmp) - Reads the attempted slot from
rootflags=subvol=@<slot>in the kernel cmdline viagetarg rootflags, validating it isblueorgreen(falls back to the sentinelunknownotherwise —shani-updatehandles that value gracefully) - Writes the slot name to
/data/boot_hard_failure, always overwriting any stale marker so it reflects the current attempt - Unmounts
@dataimmediately
Failure handling: If the @data subvolume cannot be mounted (e.g. disk not found), the hook exits silently with a warning in the boot log rather than halting the boot.
Hook: shanios-overlay-etc.sh (pre-pivot 50)
Runs: After root is successfully mounted, before pivot_root hands control to systemd.
Purpose: Mount the /etc OverlayFS so systemd PID 1 reads the correct (user-modified) /etc from its very first unit file access.
Why in dracut and not fstab: If the overlay is applied via fstab after pivot_root, systemd has already cached paths from the read-only root's /etc. The overlay must be in place before the switch to the new root.
What it does:
- Locates the Btrfs device by filesystem label
- Mounts
@dataread-write at/run/shanios-data-tmp - Creates
/data/overlay/etc/upperandworkdirectories if missing - Mounts OverlayFS onto
${NEWROOT}/etcwith optionsindex=off,metacopy=off - Does not unmount
@data— the overlay upper/work directories are on this mount; unmounting would break the overlay
The @data mount at /run/shanios-data-tmp is carried into the new root by switch_root (which moves all /run mounts automatically). It is visible in the booted system at /run/shanios-data-tmp until the fstab @data mount at /data takes over.
Mount options:
| Option | Reason |
|---|---|
index=off | Avoids inode index checks that break across subvolume mounts |
metacopy=off | Disables metadata-only copy-up; keeps behaviour simple and compatible with older kernels |
Hook: shanios-boot-success-clear.sh (pre-pivot 90)
Runs: After root is successfully mounted and after the overlay hook (priority 50), before pivot_root.
Purpose: Clear the boot_hard_failure marker written by the pre-mount hook, confirming that root mount succeeded.
What it does:
- Uses the already-mounted
@datafrom the overlay hook (or re-mounts it if the overlay hook failed) - Removes
/data/boot_hard_failureif present - Does not unmount
@data— same reason as the overlay hook
Ordering: Running at priority 90 (after the overlay hook at 50) ensures the overlay is already live when success is declared.
Interaction with Boot Health Services
The dracut hooks work together with userspace systemd services to provide complete boot failure detection:
Boot attempt
│
├─ [pre-mount 90] shanios-boot-failure-hook.sh
│ └─ writes /data/boot_hard_failure
│
├─ Root mount attempted
│ ├─ FAIL → pre-pivot never runs → boot_hard_failure persists → reboot
│ └─ SUCCESS ↓
│
├─ [pre-pivot 50] shanios-overlay-etc.sh
│ └─ mounts /etc overlay
│
├─ [pre-pivot 90] shanios-boot-success-clear.sh
│ └─ removes /data/boot_hard_failure
│
└─ pivot_root → systemd PID 1
│
├─ mark-boot-in-progress.service (local-fs.target)
│ └─ clears boot-ok/boot_failure.acked/boot_in_progress, then writes boot_in_progress
│
├─ mark-boot-success.service (at multi-user.target)
│ └─ writes /data/boot-ok, clears boot_in_progress, and clears boot_failure
│ if the booted slot matches the slot recorded there (stale recovery)
│
├─ bless-boot.service (after mark-boot-success)
│ └─ bootctl set-good (stops boot counter)
│
└─ check-boot-failure.timer (OnBootSec=15m)
└─ if boot_in_progress && ! boot-ok → writes /data/boot_failure
Rebuilding the Module
The module is rebuilt automatically by every shani-deploy run and every gen-efi configure call. To rebuild manually:
# Rebuild initramfs (and re-sign UKI) for the currently booted slot
sudo gen-efi configure blue
# Or rebuild just the initramfs without re-signing
sudo dracut --force --kver "$(uname -r)"
Note: A rawdracut --forcewithout--uefiproduces a separate initrd file, not a UKI. Always usegen-efi configureto ensure the result is signed and installed correctly.
Verifying the Module is Installed
# Check module files are present
ls /usr/lib/dracut/modules.d/99shanios/
# Check the module is included in the running initramfs
# (decompress the UKI and inspect its cpio archive)
sudo /usr/lib/systemd/systemd-stub /boot/efi/EFI/shanios/shanios-blue.efi --dump 2>/dev/null \
| cpio -t 2>/dev/null | grep shanios
# Or use shani-health
shani-health --boot # shows "Dracut mod: OK 99shanios module installed (N hooks)"
See Also
- Boot Process — how the full boot chain works
- Overlay Filesystem — how the
/etcoverlay works at runtime - gen-efi Reference — building and signing UKIs