]> git.ipfire.org Git - thirdparty/dracut.git/commitdiff
add lvmmerge dracut module
authorHarald Hoyer <harald@redhat.com>
Mon, 24 Jul 2017 13:45:23 +0000 (15:45 +0200)
committerHarald Hoyer <harald@redhat.com>
Mon, 24 Jul 2017 13:48:54 +0000 (15:48 +0200)
modules.d/80lvmmerge/64-lvm.rules [new file with mode: 0644]
modules.d/80lvmmerge/README.md [new file with mode: 0755]
modules.d/80lvmmerge/lvmmerge.sh [new file with mode: 0755]
modules.d/80lvmmerge/module-setup.sh [new file with mode: 0755]
modules.d/90lvm/module-setup.sh

diff --git a/modules.d/80lvmmerge/64-lvm.rules b/modules.d/80lvmmerge/64-lvm.rules
new file mode 100644 (file)
index 0000000..3ce0c1f
--- /dev/null
@@ -0,0 +1,21 @@
+# hacky rules to try to activate lvm when we get new block devs...
+#
+# Copyright 2008, Red Hat, Inc.
+# Jeremy Katz <katzj@redhat.com>
+
+
+SUBSYSTEM!="block", GOTO="lvm_end"
+ACTION!="add|change", GOTO="lvm_end"
+# Also don't process disks that are slated to be a multipath device
+ENV{DM_MULTIPATH_DEVICE_PATH}=="?*", GOTO="lvm_end"
+KERNEL=="dm-[0-9]*", ACTION=="add", GOTO="lvm_end"
+ENV{ID_FS_TYPE}!="LVM?_member", GOTO="lvm_end"
+
+PROGRAM=="/bin/sh -c 'for i in $sys/$devpath/holders/dm-[0-9]*; do [ -e $$i ] && exit 0; done; exit 1;' ", \
+    GOTO="lvm_end"
+
+RUN+="/sbin/initqueue --settled --onetime --unique /sbin/lvm_scan"
+RUN+="/sbin/initqueue --timeout --name 51-lvm_scan --onetime --unique /sbin/lvm_scan --partial"
+RUN+="/bin/sh -c '>/tmp/.lvm_scan-%k;'"
+
+LABEL="lvm_end"
diff --git a/modules.d/80lvmmerge/README.md b/modules.d/80lvmmerge/README.md
new file mode 100755 (executable)
index 0000000..48e0dd8
--- /dev/null
@@ -0,0 +1,63 @@
+# 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 lv's 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 *.devimage
+  found in that directory. This can be used to restore /boot and /boot/efi.
+  Additionally any *.mbrimage files will be restored. This can be used 
+  found in that directory. This can be used to restore /boot and /boot/efi
diff --git a/modules.d/80lvmmerge/lvmmerge.sh b/modules.d/80lvmmerge/lvmmerge.sh
new file mode 100755 (executable)
index 0000000..a2fd567
--- /dev/null
@@ -0,0 +1,143 @@
+#!/bin/bash
+
+#
+# How to prepare:
+# - 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
+# # 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")
+# # 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
+#
+# If a boot entry with rd.lvm.mergetags=<tag> is selected and there lv's 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 *.devimage
+#   found in that directory. This can be used to restore /boot and /boot/efi.
+#   Additionally any *.mbrimage files will be restored. This can be used 
+#   found in that directory. This can be used to restore /boot and /boot/efi
+#
+
+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 (executable)
index 0000000..dddb6ec
--- /dev/null
@@ -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
+    return 0
+}
+
+installkernel() {
+    hostonly="" instmods dm-snapshot
+}
+
+# called by dracut
+install() {
+    inst_multiple dd swapoff
+    inst_hook cleanup 01 "$moddir/lvmmerge.sh"
+}
index c4db779a82e5425e9607162c3657ae387deee71d..6ca4ee44882984917beb9b0332391e698c8293bf 100755 (executable)
@@ -43,7 +43,7 @@ cmdline() {
 }
 
 installkernel() {
-    instmods dm-snapshot
+    hostonly='' instmods dm-snapshot
 }
 
 # called by dracut