diff options
Diffstat (limited to '')
-rw-r--r-- | modules.d/80lvmmerge/README.md | 61 | ||||
-rwxr-xr-x | modules.d/80lvmmerge/lvmmerge.sh | 95 | ||||
-rwxr-xr-x | modules.d/80lvmmerge/module-setup.sh | 25 |
3 files changed, 181 insertions, 0 deletions
diff --git a/modules.d/80lvmmerge/README.md b/modules.d/80lvmmerge/README.md new file mode 100644 index 0000000..5e3e05f --- /dev/null +++ b/modules.d/80lvmmerge/README.md @@ -0,0 +1,61 @@ +# lvmmerge - dracut module + +## Preparation +- ensure that the lvm thin pool is big enough +- backup any (most likely /boot and /boot/efi) device with: +``` +# mkdir /restoredev +# dev=<device>; umount $dev; dd if="$dev" of=/restoredev/$(systemd-escape -p "$dev"); mount $dev +``` +- backup the MBR +``` +# dev=<device>; dd if="$dev" of=/restoredev/$(systemd-escape -p "$dev") bs=446 count=1 +# ls -l /dev/disk/by-path/virtio-pci-0000\:00\:07.0 +lrwxrwxrwx. 1 root root 9 Jul 24 04:27 /dev/disk/by-path/virtio-pci-0000:00:07.0 -> ../../vda +``` +- backup some partitions +``` +# dev=/dev/disk/by-path/virtio-pci-0000:00:07.0 +# dd if="$dev" of=/restoredev/$(systemd-escape -p "$dev") bs=446 count=1 +# umount /boot/efi +# dev=/dev/disk/by-partuuid/687177a8-86b3-4e37-a328-91d20db9563c +# dd if="$dev" of=/restoredev/$(systemd-escape -p "$dev") +# umount /boot +# dev=/dev/disk/by-partuuid/4fdf99e9-4f28-4207-a26f-c76546824eaf +# dd if="$dev" of=/restoredev/$(systemd-escape -p "$dev") +``` +Final /restoredev +``` +# ls -al /restoredev/ +total 1253380 +drwx------. 2 root root 250 Jul 24 04:38 . +dr-xr-xr-x. 18 root root 242 Jul 24 04:32 .. +-rw-------. 1 root root 209715200 Jul 24 04:34 dev-disk-by\x2dpartuuid-4fdf99e9\x2d4f28\x2d4207\x2da26f\x2dc76546824eaf +-rw-------. 1 root root 1073741824 Jul 24 04:34 dev-disk-by\x2dpartuuid-687177a8\x2d86b3\x2d4e37\x2da328\x2d91d20db9563c +-rw-------. 1 root root 446 Jul 24 04:38 dev-disk-by\x2dpath-virtio\x2dpci\x2d0000:00:07.0 +``` +- make a thin snapshot +``` +# lvm lvcreate -pr -s rhel/root --name reset +``` + +- mark the snapshot with a tag +``` +# lvm lvchange --addtag reset rhel/reset +``` + +- remove /restoredev +``` +# rm -fr /restoredev +``` + +## Operation + +If a boot entry with ```rd.lvm.mergetags=<tag>``` is selected and there are LVs with ```<tag>``` +dracut will +- make a copy of the snapshot +- merge it back to the original +- rename the copy back to the name of the snapshot +- if /restordev appears in the root, then it will restore the images + found in that directory. This can be used to restore /boot and /boot/efi and the + MBR of the boot device diff --git a/modules.d/80lvmmerge/lvmmerge.sh b/modules.d/80lvmmerge/lvmmerge.sh new file mode 100755 index 0000000..b8dbfa8 --- /dev/null +++ b/modules.d/80lvmmerge/lvmmerge.sh @@ -0,0 +1,95 @@ +#!/bin/bash + +type getarg > /dev/null 2>&1 || . /lib/dracut-lib.sh + +do_merge() { + sed -i -e 's/\(^[[:space:]]*\)locking_type[[:space:]]*=[[:space:]]*[[:digit:]]/\1locking_type = 1/' \ + /etc/lvm/lvm.conf + + systemctl --no-block stop sysroot.mount + swapoff -a + umount -R /sysroot + + for tag in $(getargs rd.lvm.mergetags); do + lvm vgs --noheadings -o vg_name \ + | while read -r vg || [[ -n $vg ]]; do + unset LVS + declare -a LVS + lvs=$(lvm lvs --noheadings -o lv_name "$vg") + for lv in $lvs; do + lvm lvchange -an "$vg/$lv" + + tags=$(trim "$(lvm lvs --noheadings -o lv_tags "$vg/$lv")") + strstr ",${tags}," ",${tag}," || continue + + if ! lvm lvs --noheadings -o lv_name "${vg}/${lv}_dracutsnap" &> /dev/null; then + info "Creating backup ${lv}_dracutsnap of ${vg}/${lv}" + lvm lvcreate -pr -s "${vg}/${lv}" --name "${lv}_dracutsnap" + fi + lvm lvchange --addtag "$tag" "${vg}/${lv}_dracutsnap" + + info "Merging back ${vg}/${lv} to the original LV" + lvm lvconvert --merge "${vg}/${lv}" + + LVS+=("$lv") + done + + systemctl --no-block stop sysroot.mount + udevadm settle + + for ((i = 0; i < 100; i++)); do + lvm vgchange -an "$vg" && break + sleep 0.5 + done + + udevadm settle + lvm vgchange -ay "$vg" + udevadm settle + for lv in "${LVS[@]}"; do + info "Renaming ${lv}_dracutsnap backup to ${vg}/${lv}" + lvm lvrename "$vg" "${lv}_dracutsnap" "${lv}" + done + udevadm settle + done + done + + systemctl --no-block reset-failed systemd-fsck-root + systemctl --no-block start systemd-fsck-root + systemctl --no-block reset-failed sysroot.mount + systemctl --no-block start sysroot.mount + + for ((i = 0; i < 100; i++)); do + [[ -d /sysroot/dev ]] && break + sleep 0.5 + systemctl --no-block start sysroot.mount + done + + if [[ -d /sysroot/restoredev ]]; then + ( + if cd /sysroot/restoredev; then + # restore devices and partitions + for i in *; do + target=$(systemd-escape -pu "$i") + if ! [[ -b $target ]]; then + warn "Not restoring $target, as the device does not exist" + continue + fi + + # Just in case + umount "$target" &> /dev/null + + info "Restoring $target" + dd if="$i" of="$target" |& vinfo + done + fi + ) + mount -o remount,rw /sysroot + rm -fr /sysroot/restoredev + fi + info "Rebooting" + reboot +} + +if getarg rd.lvm.mergetags; then + do_merge +fi diff --git a/modules.d/80lvmmerge/module-setup.sh b/modules.d/80lvmmerge/module-setup.sh new file mode 100755 index 0000000..c3be931 --- /dev/null +++ b/modules.d/80lvmmerge/module-setup.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# called by dracut +check() { + # No point trying to support lvm if the binaries are missing + require_binaries lvm dd swapoff || return 1 + + return 255 +} + +# called by dracut +depends() { + echo lvm dracut-systemd systemd bash + return 0 +} + +installkernel() { + hostonly="" instmods dm-snapshot +} + +# called by dracut +install() { + inst_multiple dd swapoff + inst_hook cleanup 01 "$moddir/lvmmerge.sh" +} |