From b1471e559e8dc4ea78c896ed365f5b043c2d6ce0 Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Fri, 17 Sep 2021 19:28:38 +0200 Subject: [PATCH] test: btrfs-related udev tests --- test/TEST-64-UDEV-STORAGE/test.sh | 50 +++++++++++-- test/units/testsuite-64.sh | 120 ++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 6 deletions(-) diff --git a/test/TEST-64-UDEV-STORAGE/test.sh b/test/TEST-64-UDEV-STORAGE/test.sh index 4c4b39dd3fd..c4119cf9ecd 100755 --- a/test/TEST-64-UDEV-STORAGE/test.sh +++ b/test/TEST-64-UDEV-STORAGE/test.sh @@ -5,9 +5,7 @@ # * iSCSI # * LVM over iSCSI (?) # * SW raid (mdadm) -# * LUKS -> MD (mdadm) -> LVM -# * BTRFS -# * MD BTRFS +# * MD (mdadm) -> DM-CRYPT -> LVM set -e TEST_DESCRIPTION="systemd-udev storage tests" @@ -37,7 +35,7 @@ _host_has_feature() {( command -v lvm ;; btrfs) - modprobe -nv btrfs && command -v mkfs.btrfs + modprobe -nv btrfs && command -v mkfs.btrfs && command -v btrfs ;; *) echo >&2 "ERROR: Unknown feature '$1'" @@ -51,15 +49,19 @@ test_append_files() {( local feature # An associative array of requested (but optional) features and their # respective "handlers" from test/test-functions + # + # Note: we install cryptsetup unconditionally, hence it's not explicitly + # checked for here local -A features=( - [multipath]=install_multipath + [btrfs]=install_btrfs [lvm]=install_lvm + [multipath]=install_multipath ) instmods "=block" "=md" "=nvme" "=scsi" install_dmevent generate_module_dependencies - image_install lsblk wc + image_install lsblk wc wipefs # Install the optional features if the host has the respective tooling for feature in "${!features[@]}"; do @@ -74,6 +76,13 @@ test_append_files() {( done )} +_image_cleanup() { + mount_initdir + # Clean up certain "problematic" files which may be left over by failing tests + : >"${initdir:?}/etc/fstab" + : >"${initdir:?}/etc/crypttab" +} + test_run_one() { local test_id="${1:?}" @@ -100,6 +109,7 @@ test_run() { # Execute each currently defined function starting with "testcase_" for testcase in "${TESTCASES[@]}"; do + _image_cleanup echo "------ $testcase: BEGIN ------" { "$testcase" "$test_id"; ec=$?; } || : case $ec in @@ -311,6 +321,34 @@ testcase_lvm_basic() { rm -f "${TESTDIR:?}"/lvmbasic*.img } +testcase_btrfs_basic() { + if ! _host_has_feature "btrfs"; then + echo "Missing btrfs tools/modules, skipping the test..." + return 77 + fi + + local qemu_opts=("-device ahci,id=ahci0") + local diskpath i size + + for i in {0..3}; do + diskpath="${TESTDIR:?}/btrfsbasic${i}.img" + # Make the first disk larger for multi-partition tests + [[ $i -eq 0 ]] && size=350 || size=128 + + dd if=/dev/zero of="$diskpath" bs=1M count="$size" + qemu_opts+=( + "-device ide-hd,bus=ahci0.$i,drive=drive$i,model=foobar,serial=deadbeefbtrfs$i" + "-drive format=raw,cache=unsafe,file=$diskpath,if=none,id=drive$i" + ) + done + + KERNEL_APPEND="systemd.setenv=TEST_FUNCTION_NAME=${FUNCNAME[0]} ${USER_KERNEL_APPEND:-}" + QEMU_OPTIONS="${qemu_opts[*]} ${USER_QEMU_OPTIONS:-}" + test_run_one "${1:?}" + + rm -f "${TESTDIR:?}"/btrfsbasic*.img +} + # Allow overriding which tests should be run from the "outside", useful for manual # testing (make -C test/... TESTCASES="testcase1 testcase2") if [[ -v "TESTCASES" && -n "$TESTCASES" ]]; then diff --git a/test/units/testsuite-64.sh b/test/units/testsuite-64.sh index 693cd87adea..4380fa0fcfa 100755 --- a/test/units/testsuite-64.sh +++ b/test/units/testsuite-64.sh @@ -277,6 +277,126 @@ testcase_lvm_basic() { done } +testcase_btrfs_basic() { + local dev_stub i label mpoint uuid + local devices=( + /dev/disk/by-id/ata-foobar_deadbeefbtrfs{0..3} + ) + + ls -l "${devices[@]}" + + echo "Single device: default settings" + uuid="deadbeef-dead-dead-beef-000000000000" + label="btrfs_root" + mkfs.btrfs -L "$label" -U "$uuid" "${devices[0]}" + udevadm settle + btrfs filesystem show + test -e "/dev/disk/by-uuid/$uuid" + test -e "/dev/disk/by-label/$label" + helper_check_device_symlinks + + echo "Multiple devices: using partitions, data: single, metadata: raid1" + uuid="deadbeef-dead-dead-beef-000000000001" + label="btrfs_mpart" + sfdisk --wipe=always "${devices[0]}" </etc/crypttab + for ((i = 0; i < ${#devices[@]}; i++)); do + # Intentionally use weaker cipher-related settings, since we don't care + # about security here as it's a throwaway LUKS partition + cryptsetup luksFormat -q \ + --use-urandom --pbkdf pbkdf2 --pbkdf-force-iterations 1000 \ + --uuid "deadbeef-dead-dead-beef-11111111111$i" --label "encdisk$i" "${devices[$i]}" /etc/btrfs_keyfile + udevadm settle + test -e "/dev/disk/by-uuid/deadbeef-dead-dead-beef-11111111111$i" + test -e "/dev/disk/by-label/encdisk$i" + # Add the device into /etc/crypttab, reload systemd, and then activate + # the device so we can create a filesystem on it later + echo "encbtrfs$i UUID=deadbeef-dead-dead-beef-11111111111$i /etc/btrfs_keyfile luks,noearly" >>/etc/crypttab + systemctl daemon-reload + systemctl start "systemd-cryptsetup@encbtrfs$i" + done + helper_check_device_symlinks + # Check if we have all necessary DM devices + ls -l /dev/mapper/encbtrfs{0..3} + # Create a multi-device btrfs filesystem on the LUKS devices + mkfs.btrfs -M -d raid1 -m raid1 -L "$label" -U "$uuid" /dev/mapper/encbtrfs{0..3} + udevadm settle + btrfs filesystem show + test -e "/dev/disk/by-uuid/$uuid" + test -e "/dev/disk/by-label/$label" + helper_check_device_symlinks + # Mount it and write some data to it we can compare later + mount -t btrfs /dev/mapper/encbtrfs0 "$mpoint" + echo "hello there" >"$mpoint/test" + # "Deconstruct" the btrfs device and check if we're in a sane state (symlink-wise) + umount "$mpoint" + systemctl stop systemd-cryptsetup@encbtrfs{0..3} + test ! -e "/dev/disk/by-uuid/$uuid" + helper_check_device_symlinks + # Add the mount point to /etc/fstab and check if the device can be put together + # automagically. The source device is the DM name of the first LUKS device + # (from /etc/crypttab). We have to specify all LUKS devices manually, as + # registering the necessary devices is usually initrd's job (via btrfs device scan) + dev_stub="/dev/mapper/encbtrfs" + echo "/dev/mapper/encbtrfs0 $mpoint btrfs device=${dev_stub}0,device=${dev_stub}1,device=${dev_stub}2,device=${dev_stub}3 0 2" >>/etc/fstab + # Tell systemd about the new mount + systemctl daemon-reload + # Restart cryptsetup.target to trigger autounlock of partitions in /etc/crypttab + systemctl restart cryptsetup.target + # Start the corresponding mount unit and check if the btrfs device was reconstructed + # correctly + systemctl start "${mpoint##*/}.mount" + btrfs filesystem show + test -e "/dev/disk/by-uuid/$uuid" + test -e "/dev/disk/by-label/$label" + helper_check_device_symlinks + grep "hello there" "$mpoint/test" + # Cleanup + systemctl stop "${mpoint##*/}.mount" + systemctl stop systemd-cryptsetup@encbtrfs{0..3} + sed -i "/${mpoint##*/}/d" /etc/fstab + : >/etc/crypttab + rm -fr "$mpoint" + systemctl daemon-reload + udevadm settle +} + : >/failed udevadm settle