]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
test: btrfs-related udev tests
authorFrantisek Sumsal <frantisek@sumsal.cz>
Fri, 17 Sep 2021 17:28:38 +0000 (19:28 +0200)
committerFrantisek Sumsal <frantisek@sumsal.cz>
Sun, 19 Sep 2021 11:46:49 +0000 (13:46 +0200)
test/TEST-64-UDEV-STORAGE/test.sh
test/units/testsuite-64.sh

index 4c4b39dd3fdb0771396a2c6fd0f3c1fe5594b8fe..c4119cf9ecd0e446c76ce45f0fe39cb72bc04f09 100755 (executable)
@@ -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
index 693cd87adeacc8effdcbb6577349ef3ecb8d0564..4380fa0fcfa0b8219ccc0f282057fc3f3195e0d9 100755 (executable)
@@ -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]}" <<EOF
+label: gpt
+
+name="diskpart1", size=85M
+name="diskpart2", size=85M
+name="diskpart3", size=85M
+name="diskpart4", size=85M
+EOF
+    udevadm settle
+    mkfs.btrfs -d single -m raid1 -L "$label" -U "$uuid" /dev/disk/by-partlabel/diskpart{1..4}
+    udevadm settle
+    btrfs filesystem show
+    test -e "/dev/disk/by-uuid/$uuid"
+    test -e "/dev/disk/by-label/$label"
+    helper_check_device_symlinks
+    wipefs -a -f "${devices[0]}"
+
+    echo "Multiple devices: using disks, data: raid10, metadata: raid10, mixed mode"
+    uuid="deadbeef-dead-dead-beef-000000000002"
+    label="btrfs_mdisk"
+    mkfs.btrfs -M -d raid10 -m raid10 -L "$label" -U "$uuid" "${devices[@]}"
+    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 LUKS encrypted disks, data: raid1, metadata: raid1, mixed mode"
+    uuid="deadbeef-dead-dead-beef-000000000003"
+    label="btrfs_mencdisk"
+    mpoint="/btrfs_enc$RANDOM"
+    mkdir "$mpoint"
+    # Create a key-file
+    dd if=/dev/urandom of=/etc/btrfs_keyfile bs=64 count=1 iflag=fullblock
+    chmod 0600 /etc/btrfs_keyfile
+    # Encrypt each device and add it to /etc/crypttab, so it can be mounted
+    # automagically later
+    : >/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