Linux client: dm snapshots (option 4) on dracut-based distros & working dracut module

Yes, this was created with the help of claude.

Image backups of the root filesystem cannot be set up by the installer on
Fedora/RHEL/CentOS/Rocky/Alma/openSUSE. Here is what is missing and a working fix.

Would be nice to see a detection for distros which are using dracut in future updates.

Script and full documentation are in the attached urbackup-dracut-setup.zip
(urbackup-dracut-setup.sh plus README.md).

1. The installer bails out on dracut systems

Choosing 4) Linux device mapper based snapshots and confirming the root device
conversion gives:

Did not find initramfs-tools. Installation failed.
Configured snapshot mechanism via /usr/local/etc/urbackup/snapshot.cfg

The client then reports Image backup: not supported, even with ext4 root.

Cause: in install_client_linux.sh the initramfs integration is guarded by
if [ -e /usr/share/initramfs-tools/hooks ], which only exists on Debian/Ubuntu.
There is no dracut branch.

Fix: a dracut module (91urbackupsnap) that does what
scripts_local-top_urbackup-setup-snapshot does on Debian - create a 1:1 linear
mapping over the root device in a pre-mount hook and point sysroot.mount at
it. Same device name (root-98d1f8b1f435), so the shipped dm_create_snapshot /
dm_remove_snapshot scripts work unmodified.

The attached script installs the module, detects the root UUID automatically and
bakes it into the initramfs, so nothing needs editing per machine:

sudo ./urbackup-dracut-setup.sh            # module + a TEST initramfs only
sudo ./urbackup-dracut-setup.sh --apply    # make it permanent for all kernels
sudo ./urbackup-dracut-setup.sh --verify   # check everything, print fixes
sudo ./urbackup-dracut-setup.sh --cleanup  # clear leftovers of an aborted backup
sudo ./urbackup-dracut-setup.sh --uninstall

The default builds a test image only, so you can try it via a one-shot GRUB edit
(e, change the initrd line, Ctrl+X) without touching the normal boot path.
Every failure path in the hook falls through to a normal boot, and
setup-snapshot=0 on the kernel command line disables it entirely.

--verify also checks the two issues below and prints the exact commands to fix
them.

2. Binaries linked against the Debian soname

urbackupclient_dmsnaptool: error while loading shared libraries:
libdevmapper.so.1.02.1: cannot open shared object file

Fedora ships libdevmapper.so.1.02:

ln -s /lib64/libdevmapper.so.1.02 /lib64/libdevmapper.so.1.02.1 && ldconfig

3. Dependencies installed only via apt

apt-get install thin-provisioning-tools partclone has no RPM counterpart in the
installer:

dnf install device-mapper-persistent-data partclone

Server-side setting

Leave Volumes to backup at C. A mount point like / gives
Could not read MBR; C before root is a dm device gives
Backing up System Reserved (SYSVOL) partition failed. Once the module is active,
C works and includes the ESP automatically. Run a full backup first - an
incremental with no full to base on fails with the same SYSVOL error.

Pitfalls, if this is ever implemented upstream

  1. udevadm settle in a pre-mount hook deadlocks - the hook runs inside the
    event chain it would wait on. Symptom:
    Job dracut-pre-mount.service/start running (2min 52s / no limit).
  2. timeout is not in a default initramfs - wrapped calls silently return
    empty and the hook aborts with no error.
  3. blkid -U <uuid> is unreliable there (no blkid.tab); use
    /dev/disk/by-uuid/<uuid>.
  4. A drop-in in /etc/systemd/system/sysroot.mount.d/ is ignored -
    sysroot.mount comes from dracut-rootfs-generator, before any hook.
    /run/systemd/system/sysroot.mount.d/ at hook time works;
    /run/systemd/generator does not survive daemon-reload.
  5. Write the mount override only after the mapping exists - doing it
    unconditionally hangs the boot forever waiting on a .device unit.
  6. Depend on dracut module dm, not just base, or systemd never sees the
    mapping’s .device unit.
  7. Validate in check(), never install() - a failure in install() aborts the
    whole initramfs build and can leave an unbootable kernel after a kernel update.

Not a bug: what stays after a backup

The -clone, -clone-era, -era-metadata, -era-metadata-access and -origin
devices plus a ~5 MB /.era-meta_* file persist between backups. That is the
dm-era CBT layer and it is meant to stay; -cow-storage and the 5 GB
/.overlay_* are released correctly. Took me a while to realise this was
intended.

An aborted backup does leave a partial era stack that blocks later attempts
(create ioctl on ...-clone-era failed: Device or resource busy). Use the shipped
script first:

/usr/local/share/urbackup/dm_remove_snapshot "<snapid>" "/mnt/urbackup_snaps/<snapid>" "" "" "/"

then remove leftover devices, and only once none remain,
chattr -i + rm the files - deleting them while a snapshot is active can
corrupt the filesystem (cf. the older overlay-files-filling-up-disk thread).

Status

Fedora 44, kernel 7.1.5, ext4 root on NVMe, no LVM, client 2.5.31: full →
incremental → full all succeed repeatedly. Forced fsck after days on the
mapping: clean. SELinux ruled out (same in permissive), no stuck udev cookies.

Possible upstream fix

In the snapn = 4 branch: detect dracut alongside initramfs-tools, ship the
module and run dracut --force --regenerate-all, use dnf/yum for the two
packages, and either link against libdevmapper.so.1.02 or ship both sonames.
Happy to turn this into a PR if useful.

urbackup-dracut-setup.zip (10.1 KB)

Follow-up: file manager entries, no sleep inhibition on Linux, and leftovers after a shutdown

Three things that came up while running this on two machines. All of them are
handled by the updated urbackup-dracut-setup.sh, but 2 and 3 apply to any Linux
client, with or without the dracut module.


1. The snapshot devices show up in the desktop file manager

On a desktop install, the first image backup adds a pile of entries to the file
manager’s device list. On KDE I got five, all reading 929,5 GiB Internal Drive:

Device What it is
dm-0 the root mapping, mounted at /
dm-1, dm-4, dm-7 -clone-era, -clone, -origin - the CBT layer
sda3 the real root partition, no longer mounted directly

They all carry the same ext4 UUID, so udisks2 offers five mountable volumes.
-era-metadata and -era-metadata-access have no filesystem and stay hidden.

This is not just cosmetic: clicking one of them mounts the live root filesystem
a second time through a different block device.

Fix is a udev rule. udisks2 turns UDISKS_IGNORE into its HintIgnore property,
which both Solid (KDE) and GVfs (GNOME) honour. Display only - fstab, mount,
udisksctl and the boot path are unaffected.

/etc/udev/rules.d/99-urbackup-hide-dm.rules:

SUBSYSTEM=="block", ENV{DM_NAME}=="root-98d1f8b1f435-*", ENV{UDISKS_IGNORE}="1"
SUBSYSTEM=="block", ENV{DEVTYPE}=="partition", ENV{ID_FS_UUID}=="<root-uuid>", ENV{UDISKS_IGNORE}="1"
udevadm control --reload
udevadm trigger --subsystem-match=block --action=change
udevadm settle
udevadm info --query=property --name=/dev/sda3 | grep UDISKS_IGNORE

Two traps that cost me a while:

  1. DEVTYPE is a udev property, not a match key. DEVTYPE=="partition" makes
    udev drop the entire line with Invalid key 'DEVTYPE' (visible in
    journalctl -u systemd-udevd) and the rule silently does nothing. It has to
    be ENV{DEVTYPE}.
  2. udevadm trigger returns before the events are processed, so checking the
    property right after it can look like a failure when it is not. Use
    udevadm settle in between.

Scope: rule 1 can only ever match device-mapper devices, since DM_NAME does not
exist on anything else. Rule 2 matches by filesystem UUID, so a clone of the same
disk attached to the machine would be hidden too - worth knowing if you restore
an image to a new disk and then plug the old one in.

I left the root mapping itself visible. I checked what a stock system looks like
by booting once with setup-snapshot=0 and the rule moved out of the way: the
root partition is listed there, as a single entry with a usage bar. So keeping
the mapping visible reproduces the original behaviour - same single entry, now
labelled dm-0 instead of sda3. Add this if you want it gone entirely, though
that shows less than a stock install does:

SUBSYSTEM=="block", ENV{DM_NAME}=="root-98d1f8b1f435", ENV{UDISKS_IGNORE}="1"

2. The Linux client does not inhibit sleep during a backup

This one surprised me. systemd-inhibit --list on Fedora 44, once idle and once
during a running full image backup:

WHO            UID  USER   PID  COMM            WHAT
ModemManager   0    root   1349 ModemManager    sleep
NetworkManager 0    root   1323 NetworkManager  sleep
UPower         0    root   1193 upowerd         sleep
PowerDevil     1000 tobias 2758 org_kde_powerde handle-power-key:...:handle-lid-switch
bitwarden-app  1000 tobias 4062 xdg-dbus-proxy  sleep
compositor     1000 tobias 2412 kwin_wayland    sleep

6 inhibitors listed.

Identical in both cases. No UrBackup entry. So on any machine with an idle
timeout shorter than a backup, the backup gets cut off. My desktop sleeps after
15 minutes; a full image over WiFi on the laptop takes about 30.

The feature request for this
(forum thread 3394)
has been open since 2017 and was still being reported this January. Everything
discussed there is Windows-side - Linux does not appear to be covered at all.

Workaround is a small polling service that holds the inhibitor on the client’s
behalf. The design point worth stealing: rather than spawning a background
systemd-inhibit and killing it later - which leaks an orphaned child if the
watcher dies - let the wait loop run inside systemd-inhibit. systemd then
releases the lock exactly when the loop exits, under all circumstances:

while true; do
    if backup_running; then
        systemd-inhibit --what=sleep:idle --who=UrBackup \
                        --why="Backup in progress" --mode=block \
                        "$0" --hold
    fi
    sleep 20
done

backup_running uses two independent signals, OR-ed:

  1. urbackupclientctl status reports a non-empty running_processes array
  2. a root-98d1f8b1f435-*-cow-storage dm device exists - the per-backup snapshot
    target, present for the whole duration of a backup

The second is the fallback for a failed ctl call or a changed output format in
a future client. There is also a hard cap (8h) that releases the lock even if
detection ever gets stuck on a leftover, so it can never block sleep
indefinitely.

handle-lid-switch is intentionally not inhibited by default. It would
finish the backup on a closed laptop, but a closed laptop in a bag can overheat.


3. A shutdown mid-backup leaves the overlay file behind

The dm devices of an interrupted backup do not survive a reboot - those clean
themselves up. The files on the root filesystem do not:

  • /.overlay_<uuid>_<token> (5 GB, immutable) and its
    /.overlay_<uuid>_<token>-wsnap companion (100 MB) - per-backup, both must
    be gone once a backup finished, so finding one at boot proves the backup was
    interrupted
  • /.era-meta_* (~5 MB, immutable) - the CBT layer, supposed to persist

A oneshot unit at boot that deletes only the first one handles this. The
important part is what it must not do: deleting /.era-meta_* on every boot
resets changed block tracking and quietly turns every incremental image backup
into a full one. So this is deliberately narrower than a general cleanup routine,
which deletes both and should stay a manual action.

Two more things it has to get right, or it is worse than nothing:

  • Refuse to touch any file while a root-98d1f8b1f435-* device is still
    active.
    Deleting the overlay under a live snapshot can corrupt the
    filesystem - which is exactly why UrBackup marks these files immutable.
  • Always exit 0. A cleanup unit that can fail a boot is a bad trade.

It does not help with a backup that aborts without a reboot - that still leaves
the partial era stack and create ioctl ... Device or resource busy on the next
attempt, and still needs the shipped dm_remove_snapshot first.

Tested by rebooting in the middle of a running image backup on Fedora 44. Both
overlay files were removed at the next boot, the dracut module rebuilt the root
mapping as usual, and the next incremental image backup rebuilt the entire CBT
stack from the surviving /.era-meta_* without an error - so the era metadata
tolerates being interrupted this way, at least in this case.

Attached v3 which handels all this stuff.

urbackup-dracut-setup_v3.zip (20.1 KB)