From 17d97d4c90f8ca7420ce1717bf790f5e028ec057 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 11 Apr 2022 01:42:59 +0900 Subject: [PATCH 1/5] udev: create disk/by-diskseq symlink only when the device has diskseq Follow-up for 0d08db7f89ee665a9dcb6dd66c1f9e203192e8ec. --- rules.d/60-persistent-storage.rules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules.d/60-persistent-storage.rules b/rules.d/60-persistent-storage.rules index 23f43e4f97..4eb911b37c 100644 --- a/rules.d/60-persistent-storage.rules +++ b/rules.d/60-persistent-storage.rules @@ -124,6 +124,6 @@ ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_NAME}=="?*", SYMLINK+="disk/ # by-diskseq link (if an app is told to open a path like this, they may parse # the diskseq number from the path, then issue BLKGETDISKSEQ to verify they really got # the right device, to access specific disks in a race-free fashion) -ENV{DISKSEQ}=="?*", ENV{DEVTYPE}!="partition", SYMLINK+="disk/by-diskseq/$env{DISKSEQ}" +ENV{DISKSEQ}=="?*", ENV{DEVTYPE}!="partition", ENV{DISKSEQ}=="?*", SYMLINK+="disk/by-diskseq/$env{DISKSEQ}" LABEL="persistent_storage_end" From 03b894fc09473068f706ccf063c89ec2c3a78a4c Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 13 Apr 2022 23:01:33 +0900 Subject: [PATCH 2/5] sd-device: skip diskseq verification when ID_IGNORE_DISKSEQ property is set Some drivers do not announce the diskseq change. E.g. for md devices, the kernel increments the diskseq *after* emitting a 'change' uevent when backing block devices are added to a md device, and udevd does not receive no uevent which contains the new diskseq. --- src/libsystemd/sd-device/sd-device.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index d31526fc22..7a346257df 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -2281,7 +2281,7 @@ _public_ int sd_device_trigger_with_uuid( _public_ int sd_device_open(sd_device *device, int flags) { _cleanup_close_ int fd = -1, fd2 = -1; - const char *devname, *subsystem = NULL; + const char *devname, *subsystem = NULL, *val = NULL; uint64_t q, diskseq = 0; struct stat st; dev_t devnum; @@ -2306,10 +2306,6 @@ _public_ int sd_device_open(sd_device *device, int flags) { if (r < 0 && r != -ENOENT) return r; - r = sd_device_get_diskseq(device, &diskseq); - if (r < 0 && r != -ENOENT) - return r; - fd = open(devname, FLAGS_SET(flags, O_PATH) ? flags : O_CLOEXEC|O_NOFOLLOW|O_PATH); if (fd < 0) return -errno; @@ -2327,6 +2323,16 @@ _public_ int sd_device_open(sd_device *device, int flags) { if (FLAGS_SET(flags, O_PATH)) return TAKE_FD(fd); + r = sd_device_get_property_value(device, "ID_IGNORE_DISKSEQ", &val); + if (r < 0 && r != -ENOENT) + return r; + + if (!val || parse_boolean(val) <= 0) { + r = sd_device_get_diskseq(device, &diskseq); + if (r < 0 && r != -ENOENT) + return r; + } + fd2 = open(FORMAT_PROC_FD_PATH(fd), flags); if (fd2 < 0) return -errno; From 0224c31ea397011ab4b9f43a90fc9553272f36d5 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 13 Apr 2022 23:04:47 +0900 Subject: [PATCH 3/5] udev: do not create disk/by-diskseq symlink when ID_IGNORE_DISKSEQ property is set --- rules.d/60-persistent-storage.rules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules.d/60-persistent-storage.rules b/rules.d/60-persistent-storage.rules index 4eb911b37c..de08428207 100644 --- a/rules.d/60-persistent-storage.rules +++ b/rules.d/60-persistent-storage.rules @@ -124,6 +124,6 @@ ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_NAME}=="?*", SYMLINK+="disk/ # by-diskseq link (if an app is told to open a path like this, they may parse # the diskseq number from the path, then issue BLKGETDISKSEQ to verify they really got # the right device, to access specific disks in a race-free fashion) -ENV{DISKSEQ}=="?*", ENV{DEVTYPE}!="partition", ENV{DISKSEQ}=="?*", SYMLINK+="disk/by-diskseq/$env{DISKSEQ}" +ENV{DISKSEQ}=="?*", ENV{DEVTYPE}!="partition", ENV{DISKSEQ}=="?*", ENV{ID_IGNORE_DISKSEQ}!="1", SYMLINK+="disk/by-diskseq/$env{DISKSEQ}" LABEL="persistent_storage_end" From 9a78ee002f14cf1feeb2d4a13ad9936a2f755e02 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 13 Apr 2022 23:09:14 +0900 Subject: [PATCH 4/5] udev: set ID_IGNORE_DISKSEQ for md devices --- rules.d/50-udev-default.rules.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rules.d/50-udev-default.rules.in b/rules.d/50-udev-default.rules.in index 9cdaadb4cd..0394530479 100644 --- a/rules.d/50-udev-default.rules.in +++ b/rules.d/50-udev-default.rules.in @@ -4,6 +4,10 @@ ACTION=="remove", ENV{REMOVE_CMD}!="", RUN+="$env{REMOVE_CMD}" ACTION=="remove", GOTO="default_end" +# The md driver increments diskseq *after* emitting 'change' uevent. +# Drop the line below if it is fixed on the kernel side. +SUBSYSTEM=="block", KERNEL=="md*", ENV{ID_IGNORE_DISKSEQ}="1" + SUBSYSTEM=="virtio-ports", KERNEL=="vport*", ATTR{name}=="?*", SYMLINK+="virtio-ports/$attr{name}" # select "system RTC" or just use the first one From 3c9af05caeb0dcc7fc60b5b5a2d43e991425c993 Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Thu, 7 Apr 2022 18:03:17 +0200 Subject: [PATCH 5/5] test: add MD-related tests to TEST-64 --- test/TEST-64-UDEV-STORAGE/test.sh | 30 ++++++++++++++++++++++++++++ test/test-functions | 23 +++++++++++++++++++++ test/units/testsuite-64.sh | 33 +++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/test/TEST-64-UDEV-STORAGE/test.sh b/test/TEST-64-UDEV-STORAGE/test.sh index 04632952d0..0e684e01a0 100755 --- a/test/TEST-64-UDEV-STORAGE/test.sh +++ b/test/TEST-64-UDEV-STORAGE/test.sh @@ -42,6 +42,9 @@ _host_has_feature() {( lvm) command -v lvm || return $? ;; + mdadm) + command -v mdadm || return $? + ;; multipath) command -v multipath && command -v multipathd || return $? ;; @@ -64,6 +67,7 @@ test_append_files() {( [btrfs]=install_btrfs [iscsi]=install_iscsi [lvm]=install_lvm + [mdadm]=install_mdadm [multipath]=install_multipath ) @@ -444,6 +448,32 @@ EOF rm -f "${testdisk:?}" } +testcase_mdadm_basic() { + if ! _host_has_feature "mdadm"; then + echo "Missing mdadm tools/modules, skipping the test..." + return 77 + fi + + local qemu_opts=("-device ahci,id=ahci0") + local diskpath i size + + for i in {0..4}; do + diskpath="${TESTDIR:?}/mdadmbasic${i}.img" + + dd if=/dev/zero of="$diskpath" bs=1M count=64 + qemu_opts+=( + "-device ide-hd,bus=ahci0.$i,drive=drive$i,model=foobar,serial=deadbeefmdadm$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:?}" || return $? + + rm -f "${TESTDIR:?}"/mdadmbasic*.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/test-functions b/test/test-functions index 47eae9f0cb..b5a618c741 100644 --- a/test/test-functions +++ b/test/test-functions @@ -1055,6 +1055,29 @@ install_iscsi() { fi } +install_mdadm() { + local unit + local mdadm_units=( + system/mdadm-grow-continue@.service + system/mdadm-last-resort@.service + system/mdadm-last-resort@.timer + system/mdmon@.service + system/mdmonitor-oneshot.service + system/mdmonitor-oneshot.timer + system/mdmonitor.service + system-shutdown/mdadm.shutdown + ) + + image_install mdadm mdmon + inst_rules 01-md-raid-creating.rules 63-md-raid-arrays.rules 64-md-raid-assembly.rules 69-md-clustered-confirm-device.rules + # Fedora/CentOS/RHEL ships this rule file + [[ -f /lib/udev/rules.d/65-md-incremental.rules ]] && inst_rules 65-md-incremental.rules + + for unit in "${mdadm_units[@]}"; do + image_install "${ROOTLIBDIR:?}/$unit" + done +} + install_compiled_systemd() { dinfo "Install compiled systemd" diff --git a/test/units/testsuite-64.sh b/test/units/testsuite-64.sh index 5f50131dd5..43c46db2f9 100755 --- a/test/units/testsuite-64.sh +++ b/test/units/testsuite-64.sh @@ -534,6 +534,39 @@ testcase_long_sysfs_path() { rm -fr "${logfile:?}" "${mpoint:?}" } +testcase_mdadm_basic() { + local raid_name uuid + local expected_symlinks=() + local devices=( + /dev/disk/by-id/ata-foobar_deadbeefmdadm{0..4} + ) + + ls -l "${devices[@]}" + + echo "Mirror raid" + raid_name="mdmirror" + uuid="aaaaaaaa:bbbbbbbb:cccccccc:00000001" + expected_symlinks=( + "/dev/md/$raid_name" + "/dev/disk/by-id/md-name-H:mdmirror" + "/dev/disk/by-id/md-uuid-$uuid" + "/dev/disk/by-label/mdadm_mirror" # ext4 partition + ) + # Create a simple RAID 1 with an ext4 filesystem + echo y | mdadm --create "${expected_symlinks[0]}" --name "$raid_name" --uuid "$uuid" /dev/disk/by-id/ata-foobar_deadbeefmdadm{0..1} -v -f --level=1 --raid-devices=2 + udevadm wait --settle --timeout=30 "${expected_symlinks[0]}" + mkfs.ext4 -L mdadm_mirror "/dev/md/$raid_name" + udevadm wait --settle --timeout=30 "${expected_symlinks[@]}" + # Disassemble the array + mdadm -v --stop "${expected_symlinks[0]}" + udevadm settle + helper_check_device_symlinks + # Reassemble it and check if all requires symlinks exist + mdadm --assemble "${expected_symlinks[0]}" --name "$raid_name" -v + udevadm wait --settle --timeout=30 "${expected_symlinks[@]}" + helper_check_device_symlinks +} + : >/failed udevadm settle