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

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)