]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/units/testsuite-64.sh
test-64-udev-storage: partition disk inside testcase - testcase_multipath_basic_failover
[thirdparty/systemd.git] / test / units / testsuite-64.sh
CommitLineData
f2204ac2 1#!/usr/bin/env bash
7b3cec95 2# SPDX-License-Identifier: LGPL-2.1-or-later
f2204ac2
FS
3# vi: ts=4 sw=4 tw=0 et:
4
5set -eux
6set -o pipefail
7
d430e451 8# Check if all symlinks under /dev/disk/ are valid
df72bd45 9# shellcheck disable=SC2120
de11005c
FS
10helper_check_device_symlinks() {(
11 set +x
a0560b93 12
6df02597 13 local dev link path paths target
df72bd45 14
677acd21 15 [[ $# -gt 0 ]] && paths=("$@") || paths=("/dev/disk" "/dev/mapper")
d430e451 16
6df02597
FS
17 # Check if all given paths are valid
18 for path in "${paths[@]}"; do
19 if ! test -e "$path"; then
20 echo >&2 "Path '$path' doesn't exist"
21 return 1
22 fi
23 done
24
d430e451
FS
25 while read -r link; do
26 target="$(readlink -f "$link")"
27 # Both checks should do virtually the same thing, but check both to be
28 # on the safe side
29 if [[ ! -e "$link" || ! -e "$target" ]]; then
30 echo >&2 "ERROR: symlink '$link' points to '$target' which doesn't exist"
31 return 1
32 fi
33
34 # Check if the symlink points to the correct device in /dev
35 dev="/dev/$(udevadm info -q name "$link")"
36 if [[ "$target" != "$dev" ]]; then
37 echo >&2 "ERROR: symlink '$link' points to '$target' but '$dev' was expected"
38 return 1
39 fi
df72bd45 40 done < <(find "${paths[@]}" -type l)
de11005c 41)}
d430e451 42
ee275012
YW
43helper_check_udev_watch() {(
44 set +x
45
46 local link target id dev
47
48 while read -r link; do
49 target="$(readlink "$link")"
ee275012
YW
50 if [[ ! -L "/run/udev/watch/$target" ]]; then
51 echo >&2 "ERROR: symlink /run/udev/watch/$target does not exist"
52 return 1
53 fi
54 if [[ "$(readlink "/run/udev/watch/$target")" != "$(basename "$link")" ]]; then
55 echo >&2 "ERROR: symlink target of /run/udev/watch/$target is inconsistent with $link"
56 return 1
57 fi
58
59 if [[ "$target" =~ ^[0-9]+$ ]]; then
60 # $link is ID -> wd
61 id="$(basename "$link")"
62 else
63 # $link is wd -> ID
64 id="$target"
65 fi
66
67 if [[ "${id:0:1}" == "b" ]]; then
68 dev="/dev/block/${id:1}"
69 elif [[ "${id:0:1}" == "c" ]]; then
70 dev="/dev/char/${id:1}"
71 else
72 echo >&2 "ERROR: unexpected device ID '$id'"
73 return 1
74 fi
75
76 if [[ ! -e "$dev" ]]; then
77 echo >&2 "ERROR: device '$dev' corresponding to symlink '$link' does not exist"
78 return 1
79 fi
80 done < <(find /run/udev/watch -type l)
81)}
82
9c126b2c
YW
83check_device_unit() {(
84 set +x
85
86 local log_level link links path syspath unit
87
88 log_level="${1?}"
89 path="${2?}"
90 unit=$(systemd-escape --path --suffix=device "$path")
91
5479d0f8
YW
92 [[ "$log_level" == 1 ]] && echo "INFO: check_device_unit($unit)"
93
9c126b2c
YW
94 syspath=$(systemctl show --value --property SysFSPath "$unit" 2>/dev/null)
95 if [[ -z "$syspath" ]]; then
96 [[ "$log_level" == 1 ]] && echo >&2 "ERROR: $unit not found."
97 return 1
98 fi
99
100 if [[ ! -L "$path" ]]; then
101 if [[ ! -d "$syspath" ]]; then
102 [[ "$log_level" == 1 ]] && echo >&2 "ERROR: $unit exists for $syspath but it does not exist."
103 return 1
104 fi
105 return 0
106 fi
107
108 if [[ ! -b "$path" && ! -c "$path" ]]; then
109 [[ "$log_level" == 1 ]] && echo >&2 "ERROR: invalid file type $path"
110 return 1
111 fi
112
113 read -r -a links < <(udevadm info -q symlink "$syspath" 2>/dev/null)
114 for link in "${links[@]}"; do
115 if [[ "/dev/$link" == "$path" ]]; then # DEVLINKS= given by -q symlink are relative to /dev
116 return 0
117 fi
118 done
119
120 read -r -a links < <(udevadm info "$syspath" | sed -ne '/SYSTEMD_ALIAS=/ { s/^E: SYSTEMD_ALIAS=//; p }' 2>/dev/null)
121 for link in "${links[@]}"; do
122 if [[ "$link" == "$path" ]]; then # SYSTEMD_ALIAS= are absolute
123 return 0
124 fi
125 done
126
127 [[ "$log_level" == 1 ]] && echo >&2 "ERROR: $unit exists for $syspath but it does not have the corresponding DEVLINKS or SYSTEMD_ALIAS."
128 return 1
129)}
130
131check_device_units() {(
132 set +x
133
134 local log_level path paths
135
136 log_level="${1?}"
137 shift
138 paths=("$@")
139
140 for path in "${paths[@]}"; do
141 if ! check_device_unit "$log_level" "$path"; then
142 return 1
143 fi
144 done
145
146 while read -r unit _; do
147 path=$(systemd-escape --path --unescape "$unit")
148 if ! check_device_unit "$log_level" "$path"; then
149 return 1
150 fi
6018a27c 151 done < <(systemctl list-units --all --type=device --no-legend dev-* | awk '$1 !~ /dev-tty.+/ && $4 == "plugged" { print $1 }' | sed -e 's/\.device$//')
9c126b2c
YW
152
153 return 0
154)}
155
156helper_check_device_units() {(
157 set +x
158
159 local i
160
4481a308
ZJS
161 for i in {1..20}; do
162 (( i > 1 )) && sleep 0.5
9c126b2c
YW
163 if check_device_units 0 "$@"; then
164 return 0
165 fi
166 done
167
168 check_device_units 1 "$@"
169)}
170
f2204ac2
FS
171testcase_megasas2_basic() {
172 lsblk -S
173 [[ "$(lsblk --scsi --noheadings | wc -l)" -ge 128 ]]
174}
175
176testcase_nvme_basic() {
18a6cd4b
YW
177 local expected_symlinks=()
178 local i
179
180 for (( i = 0; i < 5; i++ )); do
181 expected_symlinks+=(
182 # both replace mode provides the same devlink
183 /dev/disk/by-id/nvme-QEMU_NVMe_Ctrl_deadbeef"$i"
184 # with nsid
185 /dev/disk/by-id/nvme-QEMU_NVMe_Ctrl_deadbeef"$i"_1
186 )
187 done
188 for (( i = 5; i < 10; i++ )); do
189 expected_symlinks+=(
190 # old replace mode
191 /dev/disk/by-id/nvme-QEMU_NVMe_Ctrl__deadbeef_"$i"
192 # newer replace mode
193 /dev/disk/by-id/nvme-QEMU_NVMe_Ctrl_____deadbeef__"$i"
194 # with nsid
195 /dev/disk/by-id/nvme-QEMU_NVMe_Ctrl_____deadbeef__"$i"_1
196 )
197 done
198 for (( i = 10; i < 15; i++ )); do
199 expected_symlinks+=(
200 # old replace mode does not provide devlink, as serial contains "/"
201 # newer replace mode
202 /dev/disk/by-id/nvme-QEMU_NVMe_Ctrl_____dead_beef_"$i"
203 # with nsid
204 /dev/disk/by-id/nvme-QEMU_NVMe_Ctrl_____dead_beef_"$i"_1
205 )
206 done
207 for (( i = 15; i < 20; i++ )); do
208 expected_symlinks+=(
209 # old replace mode does not provide devlink, as serial contains "/"
210 # newer replace mode
211 /dev/disk/by-id/nvme-QEMU_NVMe_Ctrl_dead_.._.._beef_"$i"
212 # with nsid
213 /dev/disk/by-id/nvme-QEMU_NVMe_Ctrl_dead_.._.._beef_"$i"_1
214 )
215 done
216
217 udevadm settle
218 ls /dev/disk/by-id
219 for i in "${expected_symlinks[@]}"; do
220 udevadm wait --settle --timeout=30 "$i"
221 done
222
f2204ac2 223 lsblk --noheadings | grep "^nvme"
18a6cd4b 224 [[ "$(lsblk --noheadings | grep -c "^nvme")" -ge 20 ]]
f2204ac2
FS
225}
226
6788418a
FS
227testcase_nvme_subsystem() {
228 local expected_symlinks=(
229 # Controller(s)
230 /dev/disk/by-id/nvme-QEMU_NVMe_Ctrl_deadbeef
c5ba7a2a
TB
231 /dev/disk/by-id/nvme-QEMU_NVMe_Ctrl_deadbeef_16
232 /dev/disk/by-id/nvme-QEMU_NVMe_Ctrl_deadbeef_17
6788418a
FS
233 # Shared namespaces
234 /dev/disk/by-path/pci-*-nvme-16
235 /dev/disk/by-path/pci-*-nvme-17
236 )
237
238 udevadm wait --settle --timeout=30 "${expected_symlinks[@]}"
239}
240
f2204ac2 241testcase_virtio_scsi_identically_named_partitions() {
211062e3
SL
242 local num_part num_disk i j
243 local alphabet='abcdefghijklmnopqrstuvwxyz'
0bfe2aa3 244
1f9caf28 245 if [[ -v ASAN_OPTIONS || "$(systemd-detect-virt -v)" == "qemu" ]]; then
211062e3
SL
246 num_part=4
247 num_disk=4
0bfe2aa3 248 else
211062e3
SL
249 num_part=8
250 num_disk=16
0bfe2aa3
YW
251 fi
252
211062e3
SL
253 for ((i = 0; i < num_disk; i++)); do
254 sfdisk "/dev/sd${alphabet:$i:1}" <<EOF
255label: gpt
256
257$(for ((j = 1; j <= num_part; j++)); do echo 'name="Hello world", size=2M'; done)
258EOF
259 done
260
f2204ac2 261 lsblk --noheadings -a -o NAME,PARTLABEL
211062e3 262 [[ "$(lsblk --noheadings -a -o NAME,PARTLABEL | grep -c "Hello world")" -eq "$((num_part * num_disk))" ]]
f2204ac2
FS
263}
264
d0cbad16
FS
265testcase_multipath_basic_failover() {
266 local dmpath i path wwid
267
268 # Configure multipath
269 cat >/etc/multipath.conf <<\EOF
270defaults {
271 # Use /dev/mapper/$WWN paths instead of /dev/mapper/mpathX
272 user_friendly_names no
273 find_multipaths yes
274 enable_foreign "^$"
275}
276
277blacklist_exceptions {
278 property "(SCSI_IDENT_|ID_WWN)"
279}
280
281blacklist {
282}
283EOF
b6183109
SL
284
285 sfdisk /dev/sda <<EOF
286label: gpt
287
288name="first_partition", size=5M
289uuid="deadbeef-dead-dead-beef-000000000000", name="failover_part", size=5M
290EOF
291 udevadm settle
292 mkfs.ext4 -U "deadbeef-dead-dead-beef-111111111111" -L "failover_vol" "/dev/sda2"
293
d0cbad16
FS
294 modprobe -v dm_multipath
295 systemctl start multipathd.service
296 systemctl status multipathd.service
297 multipath -ll
cd37793d 298 udevadm settle
d0cbad16
FS
299 ls -l /dev/disk/by-id/
300
1678bd2f 301 for i in {0..15}; do
d0cbad16
FS
302 wwid="deaddeadbeef$(printf "%.4d" "$i")"
303 path="/dev/disk/by-id/wwn-0x$wwid"
304 dmpath="$(readlink -f "$path")"
305
306 lsblk "$path"
307 multipath -C "$dmpath"
308 # We should have 4 active paths for each multipath device
309 [[ "$(multipath -l "$path" | grep -c running)" -eq 4 ]]
310 done
311
312 # Test failover (with the first multipath device that has a partitioned disk)
313 echo "${FUNCNAME[0]}: test failover"
314 local device expected link mpoint part
315 local -a devices
84e5b922 316 mkdir -p /mnt
d0cbad16
FS
317 mpoint="$(mktemp -d /mnt/mpathXXX)"
318 wwid="deaddeadbeef0000"
319 path="/dev/disk/by-id/wwn-0x$wwid"
320
321 # All following symlinks should exists and should be valid
322 local -a part_links=(
323 "/dev/disk/by-id/wwn-0x$wwid-part2"
324 "/dev/disk/by-partlabel/failover_part"
325 "/dev/disk/by-partuuid/deadbeef-dead-dead-beef-000000000000"
326 "/dev/disk/by-label/failover_vol"
327 "/dev/disk/by-uuid/deadbeef-dead-dead-beef-111111111111"
328 )
14f9c81f 329 udevadm wait --settle --timeout=30 "${part_links[@]}"
9c126b2c 330 helper_check_device_units "${part_links[@]}"
d0cbad16
FS
331
332 # Choose a random symlink to the failover data partition each time, for
333 # a better coverage
334 part="${part_links[$RANDOM % ${#part_links[@]}]}"
335
336 # Get all devices attached to a specific multipath device (in H:C:T:L format)
337 # and sort them in a random order, so we cut off different paths each time
338 mapfile -t devices < <(multipath -l "$path" | grep -Eo '[0-9]+:[0-9]+:[0-9]+:[0-9]+' | sort -R)
339 if [[ "${#devices[@]}" -ne 4 ]]; then
340 echo "Expected 4 devices attached to WWID=$wwid, got ${#devices[@]} instead"
341 return 1
342 fi
343 # Drop the last path from the array, since we want to leave at least one path active
344 unset "devices[3]"
345 # Mount the first multipath partition, write some data we can check later,
346 # and then disconnect the remaining paths one by one while checking if we
347 # can still read/write from the mount
348 mount -t ext4 "$part" "$mpoint"
349 expected=0
350 echo -n "$expected" >"$mpoint/test"
351 # Sanity check we actually wrote what we wanted
352 [[ "$(<"$mpoint/test")" == "$expected" ]]
353
354 for device in "${devices[@]}"; do
355 echo offline >"/sys/class/scsi_device/$device/device/state"
356 [[ "$(<"$mpoint/test")" == "$expected" ]]
357 expected="$((expected + 1))"
358 echo -n "$expected" >"$mpoint/test"
359
360 # Make sure all symlinks are still valid
14f9c81f 361 udevadm wait --settle --timeout=30 "${part_links[@]}"
9c126b2c 362 helper_check_device_units "${part_links[@]}"
d0cbad16
FS
363 done
364
365 multipath -l "$path"
366 # Three paths should be now marked as 'offline' and one as 'running'
367 [[ "$(multipath -l "$path" | grep -c offline)" -eq 3 ]]
368 [[ "$(multipath -l "$path" | grep -c running)" -eq 1 ]]
369
370 umount "$mpoint"
371 rm -fr "$mpoint"
372}
373
a2e41b81 374testcase_simultaneous_events_1() {
ad8c442a 375 local disk expected i iterations key link num_part part partscript rule target timeout
d64b44be 376 local -a devices symlinks
ad8c442a 377 local -A running
35497c7c 378
1f9caf28 379 if [[ -v ASAN_OPTIONS || "$(systemd-detect-virt -v)" == "qemu" ]]; then
d64b44be 380 num_part=2
a1bed4e4
YW
381 iterations=10
382 timeout=240
383 else
d64b44be 384 num_part=10
a1bed4e4
YW
385 iterations=100
386 timeout=30
387 fi
388
d64b44be
YW
389 for disk in {0..9}; do
390 link="/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_deadbeeftest${disk}"
391 target="$(readlink -f "$link")"
392 if [[ ! -b "$target" ]]; then
393 echo "ERROR: failed to find the test SCSI block device $link"
394 return 1
395 fi
396
397 devices+=("$target")
398 done
399
400 for ((part = 1; part <= num_part; part++)); do
401 symlinks+=(
402 "/dev/disk/by-partlabel/test${part}"
403 )
404 done
405
406 partscript="$(mktemp)"
407
35497c7c 408 cat >"$partscript" <<EOF
d64b44be
YW
409$(for ((part = 1; part <= num_part; part++)); do printf 'name="test%d", size=2M\n' "$part"; done)
410EOF
411
412 rule=/run/udev/rules.d/50-test.rules
413 mkdir -p "${rule%/*}"
414 cat >"$rule" <<EOF
415SUBSYSTEM=="block", KERNEL=="${devices[4]##*/}*|${devices[5]##*/}*", OPTIONS="link_priority=10"
35497c7c
FS
416EOF
417
d64b44be 418 udevadm control --reload
35497c7c 419
ba340e2a
JN
420 # initialize partition table
421 for disk in {0..9}; do
422 echo 'label: gpt' | udevadm lock --device="${devices[$disk]}" sfdisk -q "${devices[$disk]}"
423 done
424
ba669952 425 # Delete the partitions, immediately recreate them, wait for udev to settle
35497c7c
FS
426 # down, and then check if we have any dangling symlinks in /dev/disk/. Rinse
427 # and repeat.
428 #
429 # On unpatched udev versions the delete-recreate cycle may trigger a race
430 # leading to dead symlinks in /dev/disk/
1e429729 431 for ((i = 1; i <= iterations; i++)); do
d64b44be
YW
432 for disk in {0..9}; do
433 if ((disk % 2 == i % 2)); then
434 udevadm lock --device="${devices[$disk]}" sfdisk -q --delete "${devices[$disk]}" &
435 else
436 udevadm lock --device="${devices[$disk]}" sfdisk -q -X gpt "${devices[$disk]}" <"$partscript" &
437 fi
ad8c442a 438 running[$disk]=$!
d64b44be
YW
439 done
440
ad8c442a
YW
441 for key in "${!running[@]}"; do
442 wait "${running[$key]}"
443 unset "running[$key]"
d64b44be
YW
444 done
445
446 if ((i % 10 <= 1)); then
447 udevadm wait --settle --timeout="$timeout" "${devices[@]}" "${symlinks[@]}"
35497c7c 448 helper_check_device_symlinks
ee275012 449 helper_check_udev_watch
d64b44be
YW
450 for ((part = 1; part <= num_part; part++)); do
451 link="/dev/disk/by-partlabel/test${part}"
452 target="$(readlink -f "$link")"
453 if ((i % 2 == 0)); then
454 expected="${devices[5]}$part"
455 else
456 expected="${devices[4]}$part"
457 fi
458 if [[ "$target" != "$expected" ]]; then
459 echo >&2 "ERROR: symlink '/dev/disk/by-partlabel/test${part}' points to '$target' but '$expected' was expected"
460 return 1
461 fi
462 done
35497c7c
FS
463 fi
464 done
465
9c126b2c 466 helper_check_device_units
d64b44be
YW
467 rm -f "$rule" "$partscript"
468
469 udevadm control --reload
35497c7c
FS
470}
471
a2e41b81 472testcase_simultaneous_events_2() {
beebaeeb 473 local disk expected i iterations key link num_part part script_dir target timeout
a2e41b81
YW
474 local -a devices symlinks
475 local -A running
476
beebaeeb
YW
477 script_dir="$(mktemp --directory "/tmp/test-udev-storage.script.XXXXXXXXXX")"
478 # shellcheck disable=SC2064
479 trap "rm -rf '$script_dir'" RETURN
480
a2e41b81
YW
481 if [[ -v ASAN_OPTIONS || "$(systemd-detect-virt -v)" == "qemu" ]]; then
482 num_part=20
483 iterations=1
484 timeout=2400
485 else
486 num_part=100
487 iterations=3
488 timeout=300
489 fi
490
491 for disk in {0..9}; do
492 link="/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_deadbeeftest${disk}"
493 target="$(readlink -f "$link")"
494 if [[ ! -b "$target" ]]; then
495 echo "ERROR: failed to find the test SCSI block device $link"
496 return 1
497 fi
498
499 devices+=("$target")
500 done
501
beebaeeb
YW
502 for ((i = 1; i <= iterations; i++)); do
503 cat >"$script_dir/partscript-$i" <<EOF
504$(for ((part = 1; part <= num_part; part++)); do printf 'name="testlabel-%d", size=1M\n' "$i"; done)
a2e41b81 505EOF
beebaeeb 506 done
a2e41b81
YW
507
508 echo "## $iterations iterations start: $(date '+%H:%M:%S.%N')"
509 for ((i = 1; i <= iterations; i++)); do
510
511 for disk in {0..9}; do
512 udevadm lock --device="${devices[$disk]}" sfdisk -q --delete "${devices[$disk]}" &
513 running[$disk]=$!
514 done
515
516 for key in "${!running[@]}"; do
517 wait "${running[$key]}"
518 unset "running[$key]"
519 done
520
521 for disk in {0..9}; do
beebaeeb 522 udevadm lock --device="${devices[$disk]}" sfdisk -q -X gpt "${devices[$disk]}" <"$script_dir/partscript-$i" &
a2e41b81
YW
523 running[$disk]=$!
524 done
525
526 for key in "${!running[@]}"; do
527 wait "${running[$key]}"
528 unset "running[$key]"
529 done
530
beebaeeb 531 udevadm wait --settle --timeout="$timeout" "${devices[@]}" "/dev/disk/by-partlabel/testlabel-$i"
a2e41b81
YW
532 done
533 echo "## $iterations iterations end: $(date '+%H:%M:%S.%N')"
534}
535
536testcase_simultaneous_events() {
537 testcase_simultaneous_events_1
538 testcase_simultaneous_events_2
539}
540
0203b2e4 541testcase_lvm_basic() {
998fb5c5 542 local i iterations partitions part timeout
0203b2e4
FS
543 local vgroup="MyTestGroup$RANDOM"
544 local devices=(
545 /dev/disk/by-id/ata-foobar_deadbeeflvm{0..3}
546 )
547
1f9caf28 548 if [[ -v ASAN_OPTIONS || "$(systemd-detect-virt -v)" == "qemu" ]]; then
dd2b99ee
FS
549 timeout=180
550 else
551 timeout=30
552 fi
0203b2e4
FS
553 # Make sure all the necessary soon-to-be-LVM devices exist
554 ls -l "${devices[@]}"
555
556 # Add all test devices into a volume group, create two logical volumes,
557 # and check if necessary symlinks exist (and are valid)
558 lvm pvcreate -y "${devices[@]}"
559 lvm pvs
560 lvm vgcreate "$vgroup" -y "${devices[@]}"
561 lvm vgs
562 lvm vgchange -ay "$vgroup"
563 lvm lvcreate -y -L 4M "$vgroup" -n mypart1
6299b6e5 564 lvm lvcreate -y -L 32M "$vgroup" -n mypart2
0203b2e4 565 lvm lvs
1e429729 566 udevadm wait --settle --timeout="$timeout" "/dev/$vgroup/mypart1" "/dev/$vgroup/mypart2"
0203b2e4 567 mkfs.ext4 -L mylvpart1 "/dev/$vgroup/mypart1"
1e429729 568 udevadm wait --settle --timeout="$timeout" "/dev/disk/by-label/mylvpart1"
0203b2e4 569 helper_check_device_symlinks "/dev/disk" "/dev/$vgroup"
9c126b2c 570 helper_check_device_units
0203b2e4 571
d60e3482
YW
572 # Mount mypart1 through by-label devlink
573 mkdir -p /tmp/mypart1-mount-point
574 mount /dev/disk/by-label/mylvpart1 /tmp/mypart1-mount-point
1c5d54b2 575 timeout 30 bash -c "until systemctl -q is-active /tmp/mypart1-mount-point; do sleep .2; done"
d60e3482
YW
576 # Extend the partition and check if the device and mount units are still active.
577 # See https://bugzilla.redhat.com/show_bug.cgi?id=2158628
578 # Note, the test below may be unstable with LVM2 without the following patch:
579 # https://github.com/lvmteam/lvm2/pull/105
580 # But, to reproduce the issue, udevd must start to process the first 'change' uevent
581 # earlier than extending the volume has been finished, and in most case, the extension
582 # is hopefully fast.
583 lvm lvextend -y --size 8M "/dev/$vgroup/mypart1"
584 udevadm wait --settle --timeout="$timeout" "/dev/disk/by-label/mylvpart1"
1c5d54b2
ZJS
585 timeout 30 bash -c "until systemctl -q is-active '/dev/$vgroup/mypart1'; do sleep .2; done"
586 timeout 30 bash -c "until systemctl -q is-active /tmp/mypart1-mount-point; do sleep .2; done"
d60e3482
YW
587 # Umount the partition, otherwise the underlying device unit will stay in
588 # the inactive state and not be collected, and helper_check_device_units() will fail.
589 systemctl show /tmp/mypart1-mount-point
590 umount /tmp/mypart1-mount-point
591
ede0fe02
YW
592 # Rename partitions (see issue #24518)
593 lvm lvrename "/dev/$vgroup/mypart1" renamed1
594 lvm lvrename "/dev/$vgroup/mypart2" renamed2
595 udevadm wait --settle --timeout="$timeout" --removed "/dev/$vgroup/mypart1" "/dev/$vgroup/mypart2"
596 udevadm wait --settle --timeout="$timeout" "/dev/$vgroup/renamed1" "/dev/$vgroup/renamed2"
597 helper_check_device_symlinks "/dev/disk" "/dev/$vgroup"
598 helper_check_device_units
599
600 # Rename them back
601 lvm lvrename "/dev/$vgroup/renamed1" mypart1
602 lvm lvrename "/dev/$vgroup/renamed2" mypart2
603 udevadm wait --settle --timeout="$timeout" --removed "/dev/$vgroup/renamed1" "/dev/$vgroup/renamed2"
604 udevadm wait --settle --timeout="$timeout" "/dev/$vgroup/mypart1" "/dev/$vgroup/mypart2"
605 helper_check_device_symlinks "/dev/disk" "/dev/$vgroup"
606 helper_check_device_units
607
6299b6e5
FS
608 # Do not "unready" suspended encrypted devices w/o superblock info
609 # See:
610 # - https://github.com/systemd/systemd/pull/24177
611 # - https://bugzilla.redhat.com/show_bug.cgi?id=1985288
612 dd if=/dev/urandom of=/etc/lvm_keyfile bs=64 count=1 iflag=fullblock
613 chmod 0600 /etc/lvm_keyfile
614 # Intentionally use weaker cipher-related settings, since we don't care
615 # about security here as it's a throwaway LUKS partition
616 cryptsetup luksFormat -q --use-urandom --pbkdf pbkdf2 --pbkdf-force-iterations 1000 \
617 "/dev/$vgroup/mypart2" /etc/lvm_keyfile
618 # Mount the LUKS partition & create a filesystem on it
619 mkdir -p /tmp/lvmluksmnt
620 cryptsetup open --key-file=/etc/lvm_keyfile "/dev/$vgroup/mypart2" "lvmluksmap"
621 udevadm wait --settle --timeout="$timeout" "/dev/mapper/lvmluksmap"
622 mkfs.ext4 -L lvmluksfs "/dev/mapper/lvmluksmap"
623 udevadm wait --settle --timeout="$timeout" "/dev/disk/by-label/lvmluksfs"
624 # Make systemd "interested" in the mount by adding it to /etc/fstab
625 echo "/dev/disk/by-label/lvmluksfs /tmp/lvmluksmnt ext4 defaults 0 2" >>/etc/fstab
626 systemctl daemon-reload
627 mount "/tmp/lvmluksmnt"
628 mountpoint "/tmp/lvmluksmnt"
629 # Temporarily suspend the LUKS device and trigger udev - basically what `cryptsetup resize`
630 # does but in a more deterministic way suitable for a test/reproducer
631 for _ in {0..5}; do
632 dmsetup suspend "/dev/mapper/lvmluksmap"
633 udevadm trigger -v --settle "/dev/mapper/lvmluksmap"
634 dmsetup resume "/dev/mapper/lvmluksmap"
635 # The mount should survive this sequence of events
636 mountpoint "/tmp/lvmluksmnt"
637 done
638 # Cleanup
639 umount "/tmp/lvmluksmnt"
640 cryptsetup close "/dev/mapper/lvmluksmap"
641 sed -i "/lvmluksfs/d" "/etc/fstab"
642 systemctl daemon-reload
643
0203b2e4
FS
644 # Disable the VG and check symlinks...
645 lvm vgchange -an "$vgroup"
1e429729 646 udevadm wait --settle --timeout="$timeout" --removed "/dev/$vgroup" "/dev/disk/by-label/mylvpart1"
0203b2e4 647 helper_check_device_symlinks "/dev/disk"
9c126b2c 648 helper_check_device_units
0203b2e4
FS
649
650 # reenable the VG and check the symlinks again if all LVs are properly activated
651 lvm vgchange -ay "$vgroup"
1e429729 652 udevadm wait --settle --timeout="$timeout" "/dev/$vgroup/mypart1" "/dev/$vgroup/mypart2" "/dev/disk/by-label/mylvpart1"
0203b2e4 653 helper_check_device_symlinks "/dev/disk" "/dev/$vgroup"
9c126b2c 654 helper_check_device_units
0203b2e4
FS
655
656 # Same as above, but now with more "stress"
1f9caf28 657 if [[ -v ASAN_OPTIONS || "$(systemd-detect-virt -v)" == "qemu" ]]; then
dd2b99ee
FS
658 iterations=10
659 else
660 iterations=50
661 fi
662
1e429729 663 for ((i = 1; i <= iterations; i++)); do
0203b2e4
FS
664 lvm vgchange -an "$vgroup"
665 lvm vgchange -ay "$vgroup"
666
dbc04797 667 if ((i % 5 == 0)); then
1e429729 668 udevadm wait --settle --timeout="$timeout" "/dev/$vgroup/mypart1" "/dev/$vgroup/mypart2" "/dev/disk/by-label/mylvpart1"
0203b2e4 669 helper_check_device_symlinks "/dev/disk" "/dev/$vgroup"
9c126b2c 670 helper_check_device_units
0203b2e4
FS
671 fi
672 done
673
674 # Remove the first LV
675 lvm lvremove -y "$vgroup/mypart1"
1e429729 676 udevadm wait --settle --timeout="$timeout" --removed "/dev/$vgroup/mypart1"
14f9c81f 677 udevadm wait --timeout=0 "/dev/$vgroup/mypart2"
0203b2e4 678 helper_check_device_symlinks "/dev/disk" "/dev/$vgroup"
9c126b2c 679 helper_check_device_units
0203b2e4
FS
680
681 # Create & remove LVs in a loop, i.e. with more "stress"
1f9caf28 682 if [[ -v ASAN_OPTIONS ]]; then
998fb5c5 683 iterations=8
07faa499 684 partitions=16
998fb5c5 685 elif [[ "$(systemd-detect-virt -v)" == "qemu" ]]; then
dd2b99ee 686 iterations=8
998fb5c5 687 partitions=8
dd2b99ee
FS
688 else
689 iterations=16
998fb5c5 690 partitions=16
dd2b99ee
FS
691 fi
692
1e429729 693 for ((i = 1; i <= iterations; i++)); do
998fb5c5
FS
694 # 1) Create some logical volumes
695 for ((part = 0; part < partitions; part++)); do
0203b2e4
FS
696 lvm lvcreate -y -L 4M "$vgroup" -n "looppart$part"
697 done
698
699 # 2) Immediately remove them
998fb5c5 700 lvm lvremove -y $(seq -f "$vgroup/looppart%g" 0 "$((partitions - 1))")
0203b2e4 701
dbc04797 702 # 3) On every 4th iteration settle udev and check if all partitions are
0203b2e4 703 # indeed gone, and if all symlinks are still valid
dbc04797 704 if ((i % 4 == 0)); then
998fb5c5 705 for ((part = 0; part < partitions; part++)); do
1e429729 706 udevadm wait --settle --timeout="$timeout" --removed "/dev/$vgroup/looppart$part"
0203b2e4
FS
707 done
708 helper_check_device_symlinks "/dev/disk" "/dev/$vgroup"
9c126b2c 709 helper_check_device_units
0203b2e4
FS
710 fi
711 done
712}
713
b1471e55
FS
714testcase_btrfs_basic() {
715 local dev_stub i label mpoint uuid
716 local devices=(
717 /dev/disk/by-id/ata-foobar_deadbeefbtrfs{0..3}
718 )
719
720 ls -l "${devices[@]}"
721
722 echo "Single device: default settings"
723 uuid="deadbeef-dead-dead-beef-000000000000"
724 label="btrfs_root"
b3ba7d62 725 udevadm lock --device="${devices[0]}" mkfs.btrfs -f -L "$label" -U "$uuid" "${devices[0]}"
14f9c81f 726 udevadm wait --settle --timeout=30 "${devices[0]}" "/dev/disk/by-uuid/$uuid" "/dev/disk/by-label/$label"
b1471e55 727 btrfs filesystem show
b1471e55 728 helper_check_device_symlinks
9c126b2c 729 helper_check_device_units
b1471e55
FS
730
731 echo "Multiple devices: using partitions, data: single, metadata: raid1"
732 uuid="deadbeef-dead-dead-beef-000000000001"
733 label="btrfs_mpart"
bc6bd62c 734 udevadm lock --device="${devices[0]}" sfdisk --wipe=always "${devices[0]}" <<EOF
b1471e55
FS
735label: gpt
736
737name="diskpart1", size=85M
738name="diskpart2", size=85M
739name="diskpart3", size=85M
740name="diskpart4", size=85M
741EOF
14f9c81f 742 udevadm wait --settle --timeout=30 /dev/disk/by-partlabel/diskpart{1..4}
b3ba7d62 743 udevadm lock --device="${devices[0]}" mkfs.btrfs -f -d single -m raid1 -L "$label" -U "$uuid" /dev/disk/by-partlabel/diskpart{1..4}
14f9c81f 744 udevadm wait --settle --timeout=30 "/dev/disk/by-uuid/$uuid" "/dev/disk/by-label/$label"
b1471e55 745 btrfs filesystem show
b1471e55 746 helper_check_device_symlinks
9c126b2c 747 helper_check_device_units
b1471e55 748 wipefs -a -f "${devices[0]}"
14f9c81f 749 udevadm wait --settle --timeout=30 --removed /dev/disk/by-partlabel/diskpart{1..4}
b1471e55
FS
750
751 echo "Multiple devices: using disks, data: raid10, metadata: raid10, mixed mode"
752 uuid="deadbeef-dead-dead-beef-000000000002"
753 label="btrfs_mdisk"
14f9c81f
YW
754 udevadm lock \
755 --device=/dev/disk/by-id/ata-foobar_deadbeefbtrfs0 \
756 --device=/dev/disk/by-id/ata-foobar_deadbeefbtrfs1 \
757 --device=/dev/disk/by-id/ata-foobar_deadbeefbtrfs2 \
758 --device=/dev/disk/by-id/ata-foobar_deadbeefbtrfs3 \
b3ba7d62 759 mkfs.btrfs -f -M -d raid10 -m raid10 -L "$label" -U "$uuid" "${devices[@]}"
14f9c81f 760 udevadm wait --settle --timeout=30 "/dev/disk/by-uuid/$uuid" "/dev/disk/by-label/$label"
b1471e55 761 btrfs filesystem show
b1471e55 762 helper_check_device_symlinks
9c126b2c 763 helper_check_device_units
b1471e55
FS
764
765 echo "Multiple devices: using LUKS encrypted disks, data: raid1, metadata: raid1, mixed mode"
766 uuid="deadbeef-dead-dead-beef-000000000003"
767 label="btrfs_mencdisk"
768 mpoint="/btrfs_enc$RANDOM"
769 mkdir "$mpoint"
770 # Create a key-file
771 dd if=/dev/urandom of=/etc/btrfs_keyfile bs=64 count=1 iflag=fullblock
772 chmod 0600 /etc/btrfs_keyfile
773 # Encrypt each device and add it to /etc/crypttab, so it can be mounted
774 # automagically later
775 : >/etc/crypttab
776 for ((i = 0; i < ${#devices[@]}; i++)); do
777 # Intentionally use weaker cipher-related settings, since we don't care
778 # about security here as it's a throwaway LUKS partition
779 cryptsetup luksFormat -q \
780 --use-urandom --pbkdf pbkdf2 --pbkdf-force-iterations 1000 \
781 --uuid "deadbeef-dead-dead-beef-11111111111$i" --label "encdisk$i" "${devices[$i]}" /etc/btrfs_keyfile
14f9c81f 782 udevadm wait --settle --timeout=30 "/dev/disk/by-uuid/deadbeef-dead-dead-beef-11111111111$i" "/dev/disk/by-label/encdisk$i"
b1471e55
FS
783 # Add the device into /etc/crypttab, reload systemd, and then activate
784 # the device so we can create a filesystem on it later
7a2d6c2d 785 echo "encbtrfs$i UUID=deadbeef-dead-dead-beef-11111111111$i /etc/btrfs_keyfile luks" >>/etc/crypttab
b1471e55
FS
786 systemctl daemon-reload
787 systemctl start "systemd-cryptsetup@encbtrfs$i"
788 done
789 helper_check_device_symlinks
9c126b2c 790 helper_check_device_units
b1471e55
FS
791 # Check if we have all necessary DM devices
792 ls -l /dev/mapper/encbtrfs{0..3}
793 # Create a multi-device btrfs filesystem on the LUKS devices
14f9c81f
YW
794 udevadm lock \
795 --device=/dev/mapper/encbtrfs0 \
796 --device=/dev/mapper/encbtrfs1 \
797 --device=/dev/mapper/encbtrfs2 \
798 --device=/dev/mapper/encbtrfs3 \
b3ba7d62 799 mkfs.btrfs -f -M -d raid1 -m raid1 -L "$label" -U "$uuid" /dev/mapper/encbtrfs{0..3}
14f9c81f 800 udevadm wait --settle --timeout=30 "/dev/disk/by-uuid/$uuid" "/dev/disk/by-label/$label"
b1471e55 801 btrfs filesystem show
b1471e55 802 helper_check_device_symlinks
9c126b2c 803 helper_check_device_units
b1471e55
FS
804 # Mount it and write some data to it we can compare later
805 mount -t btrfs /dev/mapper/encbtrfs0 "$mpoint"
806 echo "hello there" >"$mpoint/test"
807 # "Deconstruct" the btrfs device and check if we're in a sane state (symlink-wise)
808 umount "$mpoint"
809 systemctl stop systemd-cryptsetup@encbtrfs{0..3}
14f9c81f 810 udevadm wait --settle --timeout=30 --removed "/dev/disk/by-uuid/$uuid"
b1471e55 811 helper_check_device_symlinks
9c126b2c 812 helper_check_device_units
b1471e55
FS
813 # Add the mount point to /etc/fstab and check if the device can be put together
814 # automagically. The source device is the DM name of the first LUKS device
815 # (from /etc/crypttab). We have to specify all LUKS devices manually, as
816 # registering the necessary devices is usually initrd's job (via btrfs device scan)
817 dev_stub="/dev/mapper/encbtrfs"
818 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
819 # Tell systemd about the new mount
820 systemctl daemon-reload
821 # Restart cryptsetup.target to trigger autounlock of partitions in /etc/crypttab
822 systemctl restart cryptsetup.target
823 # Start the corresponding mount unit and check if the btrfs device was reconstructed
824 # correctly
825 systemctl start "${mpoint##*/}.mount"
14f9c81f 826 udevadm wait --settle --timeout=30 "/dev/disk/by-uuid/$uuid" "/dev/disk/by-label/$label"
b1471e55 827 btrfs filesystem show
b1471e55 828 helper_check_device_symlinks
9c126b2c 829 helper_check_device_units
b1471e55
FS
830 grep "hello there" "$mpoint/test"
831 # Cleanup
832 systemctl stop "${mpoint##*/}.mount"
833 systemctl stop systemd-cryptsetup@encbtrfs{0..3}
834 sed -i "/${mpoint##*/}/d" /etc/fstab
835 : >/etc/crypttab
836 rm -fr "$mpoint"
837 systemctl daemon-reload
838 udevadm settle
839}
840
9cb41c33
FS
841testcase_iscsi_lvm() {
842 local dev i label link lun_id mpoint target_name uuid
843 local target_ip="127.0.0.1"
844 local target_port="3260"
845 local vgroup="iscsi_lvm$RANDOM"
846 local expected_symlinks=()
847 local devices=(
848 /dev/disk/by-id/ata-foobar_deadbeefiscsi{0..3}
849 )
850
851 ls -l "${devices[@]}"
852
853 # Start the target daemon
854 systemctl start tgtd
855 systemctl status tgtd
856
857 echo "iSCSI LUNs backed by devices"
858 # See RFC3721 and RFC7143
859 target_name="iqn.2021-09.com.example:iscsi.test"
860 # Initialize a new iSCSI target <$target_name> consisting of 4 LUNs, each
861 # backed by a device
862 tgtadm --lld iscsi --op new --mode target --tid=1 --targetname "$target_name"
863 for ((i = 0; i < ${#devices[@]}; i++)); do
864 # lun-0 is reserved by iSCSI
865 lun_id="$((i + 1))"
866 tgtadm --lld iscsi --op new --mode logicalunit --tid 1 --lun "$lun_id" -b "${devices[$i]}"
867 tgtadm --lld iscsi --op update --mode logicalunit --tid 1 --lun "$lun_id"
868 expected_symlinks+=(
869 "/dev/disk/by-path/ip-$target_ip:$target_port-iscsi-$target_name-lun-$lun_id"
870 )
871 done
872 tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL
873 # Configure the iSCSI initiator
874 iscsiadm --mode discoverydb --type sendtargets --portal "$target_ip" --discover
875 iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --login
e529abe2 876 udevadm wait --settle --timeout=30 "${expected_symlinks[@]}"
9cb41c33 877 helper_check_device_symlinks
9c126b2c 878 helper_check_device_units
9cb41c33
FS
879 # Cleanup
880 iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --logout
881 tgtadm --lld iscsi --op delete --mode target --tid=1
882
883 echo "iSCSI LUNs backed by files + LVM"
884 # Note: we use files here to "trick" LVM the disks are indeed on a different
885 # host, so it doesn't automagically detect another path to the backing
886 # device once we disconnect the iSCSI devices
887 target_name="iqn.2021-09.com.example:iscsi.lvm.test"
888 mpoint="$(mktemp -d /iscsi_storeXXX)"
889 expected_symlinks=()
890 # Use the first device as it's configured with larger capacity
891 mkfs.ext4 -L iscsi_store "${devices[0]}"
14f9c81f 892 udevadm wait --settle --timeout=30 "${devices[0]}"
9cb41c33
FS
893 mount "${devices[0]}" "$mpoint"
894 for i in {1..4}; do
895 dd if=/dev/zero of="$mpoint/lun$i.img" bs=1M count=32
896 done
897 # Initialize a new iSCSI target <$target_name> consisting of 4 LUNs, each
898 # backed by a file
899 tgtadm --lld iscsi --op new --mode target --tid=2 --targetname "$target_name"
900 # lun-0 is reserved by iSCSI
901 for i in {1..4}; do
902 tgtadm --lld iscsi --op new --mode logicalunit --tid 2 --lun "$i" -b "$mpoint/lun$i.img"
903 tgtadm --lld iscsi --op update --mode logicalunit --tid 2 --lun "$i"
904 expected_symlinks+=(
905 "/dev/disk/by-path/ip-$target_ip:$target_port-iscsi-$target_name-lun-$i"
906 )
907 done
908 tgtadm --lld iscsi --op bind --mode target --tid 2 -I ALL
909 # Configure the iSCSI initiator
910 iscsiadm --mode discoverydb --type sendtargets --portal "$target_ip" --discover
911 iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --login
e529abe2 912 udevadm wait --settle --timeout=30 "${expected_symlinks[@]}"
9cb41c33 913 helper_check_device_symlinks
9c126b2c 914 helper_check_device_units
9cb41c33
FS
915 # Add all iSCSI devices into a LVM volume group, create two logical volumes,
916 # and check if necessary symlinks exist (and are valid)
917 lvm pvcreate -y "${expected_symlinks[@]}"
918 lvm pvs
919 lvm vgcreate "$vgroup" -y "${expected_symlinks[@]}"
920 lvm vgs
921 lvm vgchange -ay "$vgroup"
922 lvm lvcreate -y -L 4M "$vgroup" -n mypart1
923 lvm lvcreate -y -L 8M "$vgroup" -n mypart2
924 lvm lvs
14f9c81f 925 udevadm wait --settle --timeout=30 "/dev/$vgroup/mypart1" "/dev/$vgroup/mypart2"
9cb41c33 926 mkfs.ext4 -L mylvpart1 "/dev/$vgroup/mypart1"
14f9c81f 927 udevadm wait --settle --timeout=30 "/dev/disk/by-label/mylvpart1"
9cb41c33 928 helper_check_device_symlinks "/dev/disk" "/dev/$vgroup"
9c126b2c 929 helper_check_device_units
9cb41c33
FS
930 # Disconnect the iSCSI devices and check all the symlinks
931 iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --logout
932 # "Reset" the DM state, since we yanked the backing storage from under the LVM,
933 # so the currently active VGs/LVs are invalid
934 dmsetup remove_all --deferred
9cb41c33 935 # The LVM and iSCSI related symlinks should be gone
e529abe2 936 udevadm wait --settle --timeout=30 --removed "/dev/$vgroup" "/dev/disk/by-label/mylvpart1" "${expected_symlinks[@]}"
9cb41c33 937 helper_check_device_symlinks "/dev/disk"
9c126b2c 938 helper_check_device_units
9cb41c33
FS
939 # Reconnect the iSCSI devices and check if everything get detected correctly
940 iscsiadm --mode discoverydb --type sendtargets --portal "$target_ip" --discover
941 iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --login
14f9c81f 942 udevadm wait --settle --timeout=30 "${expected_symlinks[@]}" "/dev/$vgroup/mypart1" "/dev/$vgroup/mypart2" "/dev/disk/by-label/mylvpart1"
9cb41c33 943 helper_check_device_symlinks "/dev/disk" "/dev/$vgroup"
9c126b2c 944 helper_check_device_units
9cb41c33
FS
945 # Cleanup
946 iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --logout
947 tgtadm --lld iscsi --op delete --mode target --tid=2
948 umount "$mpoint"
949 rm -rf "$mpoint"
950}
f415cdb3
FS
951
952testcase_long_sysfs_path() {
98f8c316 953 local cursor link logfile mpoint
f415cdb3
FS
954 local expected_symlinks=(
955 "/dev/disk/by-label/data_vol"
956 "/dev/disk/by-label/swap_vol"
957 "/dev/disk/by-partlabel/test_swap"
958 "/dev/disk/by-partlabel/test_part"
959 "/dev/disk/by-partuuid/deadbeef-dead-dead-beef-000000000000"
960 "/dev/disk/by-uuid/deadbeef-dead-dead-beef-111111111111"
961 "/dev/disk/by-uuid/deadbeef-dead-dead-beef-222222222222"
962 )
963
98f8c316
FS
964 # Create a cursor file to skip messages generated by udevd in initrd, as it
965 # might not be the same up-to-date version as we currently run (hence generating
966 # messages we check for later and making the test fail)
967 cursor="$(mktemp)"
968 journalctl --cursor-file="${cursor:?}" -n0 -q
969
f415cdb3
FS
970 # Make sure the test device is connected and show its "wonderful" path
971 stat /sys/block/vda
972 readlink -f /sys/block/vda/dev
973
8d82e390
SL
974 dev="/dev/vda"
975 sfdisk "${dev:?}" <<EOF
976label: gpt
977
978name="test_swap", size=32M
979uuid="deadbeef-dead-dead-beef-000000000000", name="test_part", size=5M
980EOF
981 udevadm settle
982 mkswap -U "deadbeef-dead-dead-beef-111111111111" -L "swap_vol" "${dev}1"
983 mkfs.ext4 -U "deadbeef-dead-dead-beef-222222222222" -L "data_vol" "${dev}2"
14f9c81f 984 udevadm wait --settle --timeout=30 "${expected_symlinks[@]}"
f415cdb3
FS
985
986 # Try to mount the data partition manually (using its label)
987 mpoint="$(mktemp -d /logsysfsXXX)"
988 mount LABEL=data_vol "$mpoint"
989 touch "$mpoint/test"
990 umount "$mpoint"
991 # Do the same, but with UUID and using fstab
992 echo "UUID=deadbeef-dead-dead-beef-222222222222 $mpoint ext4 defaults 0 0" >>/etc/fstab
993 systemctl daemon-reload
994 mount "$mpoint"
1c5d54b2 995 timeout 30 bash -c "until systemctl -q is-active '$mpoint'; do sleep .2; done"
f415cdb3
FS
996 test -e "$mpoint/test"
997 umount "$mpoint"
998
999 # Test out the swap partition
1000 swapon -v -L swap_vol
1001 swapoff -v -L swap_vol
1002
7b3a1af0
FS
1003 udevadm settle
1004
f415cdb3 1005 logfile="$(mktemp)"
98f8c316
FS
1006 # Check state of affairs after https://github.com/systemd/systemd/pull/22759
1007 # Note: can't use `--cursor-file` here, since we don't want to update the cursor
1008 # after using it
1009 [[ "$(journalctl --after-cursor="$(<"$cursor")" -q --no-pager -o short-monotonic -p info --grep "Device path.*vda.?' too long to fit into unit name" | wc -l)" -eq 0 ]]
1010 [[ "$(journalctl --after-cursor="$(<"$cursor")" -q --no-pager -o short-monotonic --grep "Unit name .*vda.?\.device\" too long, falling back to hashed unit name" | wc -l)" -gt 0 ]]
1011 # Check if the respective "hashed" units exist and are active (plugged)
1012 systemctl status --no-pager "$(readlink -f /sys/block/vda/vda1)"
1013 systemctl status --no-pager "$(readlink -f /sys/block/vda/vda2)"
f415cdb3 1014 # Make sure we don't unnecessarily spam the log
b26f4f00 1015 { journalctl -b -q --no-pager -o short-monotonic -p info --grep "/sys/devices/.+/vda[0-9]?" _PID=1 + UNIT=systemd-udevd.service || :;} | tee "$logfile"
f415cdb3
FS
1016 [[ "$(wc -l <"$logfile")" -lt 10 ]]
1017
1018 : >/etc/fstab
98f8c316 1019 rm -fr "${cursor:?}" "${logfile:?}" "${mpoint:?}"
f415cdb3
FS
1020}
1021
3c9af05c 1022testcase_mdadm_basic() {
18161cf0 1023 local i part_name raid_name raid_dev uuid
3c9af05c
FS
1024 local expected_symlinks=()
1025 local devices=(
1026 /dev/disk/by-id/ata-foobar_deadbeefmdadm{0..4}
1027 )
1028
1029 ls -l "${devices[@]}"
1030
1bb38875 1031 echo "Mirror raid (RAID 1)"
3c9af05c 1032 raid_name="mdmirror"
1bb38875
FS
1033 raid_dev="/dev/md/$raid_name"
1034 part_name="${raid_name}_part"
3c9af05c
FS
1035 uuid="aaaaaaaa:bbbbbbbb:cccccccc:00000001"
1036 expected_symlinks=(
1bb38875
FS
1037 "$raid_dev"
1038 "/dev/disk/by-id/md-name-H:$raid_name"
3c9af05c 1039 "/dev/disk/by-id/md-uuid-$uuid"
1bb38875 1040 "/dev/disk/by-label/$part_name" # ext4 partition
3c9af05c
FS
1041 )
1042 # Create a simple RAID 1 with an ext4 filesystem
1bb38875
FS
1043 echo y | mdadm --create "$raid_dev" --name "$raid_name" --uuid "$uuid" /dev/disk/by-id/ata-foobar_deadbeefmdadm{0..1} -v -f --level=1 --raid-devices=2
1044 udevadm wait --settle --timeout=30 "$raid_dev"
1045 mkfs.ext4 -L "$part_name" "$raid_dev"
3c9af05c 1046 udevadm wait --settle --timeout=30 "${expected_symlinks[@]}"
18161cf0
FS
1047 for i in {0..9}; do
1048 echo "Disassemble - reassemble loop, iteration #$i"
1049 mdadm -v --stop "$raid_dev"
1050 udevadm wait --settle --timeout=30 --removed "${expected_symlinks[@]}"
1051 mdadm --assemble "$raid_dev" --name "$raid_name" -v
1052 udevadm wait --settle --timeout=30 "${expected_symlinks[@]}"
1053 done
1bb38875 1054 helper_check_device_symlinks
9c126b2c 1055 helper_check_device_units
1bb38875
FS
1056 # Cleanup
1057 mdadm -v --stop "$raid_dev"
18161cf0 1058 udevadm wait --settle --timeout=30 --removed "${expected_symlinks[@]}"
1bb38875
FS
1059
1060 echo "Parity raid (RAID 5)"
1061 raid_name="mdparity"
1062 raid_dev="/dev/md/$raid_name"
1063 part_name="${raid_name}_part"
1064 uuid="aaaaaaaa:bbbbbbbb:cccccccc:00000101"
1065 expected_symlinks=(
1066 "$raid_dev"
1067 "/dev/disk/by-id/md-name-H:$raid_name"
1068 "/dev/disk/by-id/md-uuid-$uuid"
1069 "/dev/disk/by-label/$part_name" # ext4 partition
1070 )
1071 # Create a simple RAID 5 with an ext4 filesystem
1072 echo y | mdadm --create "$raid_dev" --name "$raid_name" --uuid "$uuid" /dev/disk/by-id/ata-foobar_deadbeefmdadm{0..2} -v -f --level=5 --raid-devices=3
1073 udevadm wait --settle --timeout=30 "$raid_dev"
1074 mkfs.ext4 -L "$part_name" "$raid_dev"
1075 udevadm wait --settle --timeout=30 "${expected_symlinks[@]}"
18161cf0
FS
1076 for i in {0..9}; do
1077 echo "Disassemble - reassemble loop, iteration #$i"
1078 mdadm -v --stop "$raid_dev"
1079 udevadm wait --settle --timeout=30 --removed "${expected_symlinks[@]}"
1080 mdadm --assemble "$raid_dev" --name "$raid_name" -v
1081 udevadm wait --settle --timeout=30 "${expected_symlinks[@]}"
1082 done
1bb38875 1083 helper_check_device_symlinks
9c126b2c 1084 helper_check_device_units
1bb38875
FS
1085 # Cleanup
1086 mdadm -v --stop "$raid_dev"
18161cf0 1087 udevadm wait --settle --timeout=30 --removed "${expected_symlinks[@]}"
9c126b2c 1088 helper_check_device_units
1bb38875 1089
18161cf0 1090 echo "Mirror + parity raid (RAID 10) + multiple partitions"
1bb38875
FS
1091 raid_name="mdmirpar"
1092 raid_dev="/dev/md/$raid_name"
1093 part_name="${raid_name}_part"
1094 uuid="aaaaaaaa:bbbbbbbb:cccccccc:00001010"
1095 expected_symlinks=(
1096 "$raid_dev"
1097 "/dev/disk/by-id/md-name-H:$raid_name"
1098 "/dev/disk/by-id/md-uuid-$uuid"
1099 "/dev/disk/by-label/$part_name" # ext4 partition
18161cf0
FS
1100 # Partitions
1101 "${raid_dev}1"
1102 "${raid_dev}2"
1103 "${raid_dev}3"
1104 "/dev/disk/by-id/md-name-H:$raid_name-part1"
1105 "/dev/disk/by-id/md-name-H:$raid_name-part2"
1106 "/dev/disk/by-id/md-name-H:$raid_name-part3"
1107 "/dev/disk/by-id/md-uuid-$uuid-part1"
1108 "/dev/disk/by-id/md-uuid-$uuid-part2"
1109 "/dev/disk/by-id/md-uuid-$uuid-part3"
1bb38875
FS
1110 )
1111 # Create a simple RAID 10 with an ext4 filesystem
1112 echo y | mdadm --create "$raid_dev" --name "$raid_name" --uuid "$uuid" /dev/disk/by-id/ata-foobar_deadbeefmdadm{0..3} -v -f --level=10 --raid-devices=4
1113 udevadm wait --settle --timeout=30 "$raid_dev"
18161cf0
FS
1114 # Partition the raid device
1115 # Here, 'udevadm lock' is meaningless, as udevd does not lock MD devices.
1116 sfdisk --wipe=always "$raid_dev" <<EOF
1117label: gpt
1118
1119uuid="deadbeef-dead-dead-beef-111111111111", name="mdpart1", size=8M
1120uuid="deadbeef-dead-dead-beef-222222222222", name="mdpart2", size=32M
1121uuid="deadbeef-dead-dead-beef-333333333333", name="mdpart3", size=16M
1122EOF
1123 udevadm wait --settle --timeout=30 "/dev/disk/by-id/md-uuid-$uuid-part2"
1124 mkfs.ext4 -L "$part_name" "/dev/disk/by-id/md-uuid-$uuid-part2"
d3ce9bed 1125 udevadm wait --settle --timeout=30 "${expected_symlinks[@]}"
18161cf0
FS
1126 for i in {0..9}; do
1127 echo "Disassemble - reassemble loop, iteration #$i"
1128 mdadm -v --stop "$raid_dev"
1129 udevadm wait --settle --timeout=30 --removed "${expected_symlinks[@]}"
1130 mdadm --assemble "$raid_dev" --name "$raid_name" -v
1131 udevadm wait --settle --timeout=30 "${expected_symlinks[@]}"
1132 done
d3ce9bed 1133 helper_check_device_symlinks
9c126b2c 1134 helper_check_device_units
18161cf0
FS
1135 # Cleanup
1136 mdadm -v --stop "$raid_dev"
1137 # Check if all expected symlinks were removed after the cleanup
1138 udevadm wait --settle --timeout=30 --removed "${expected_symlinks[@]}"
9c126b2c 1139 helper_check_device_units
d3ce9bed
FS
1140}
1141
1142testcase_mdadm_lvm() {
1143 local part_name raid_name raid_dev uuid vgroup
1144 local expected_symlinks=()
1145 local devices=(
1146 /dev/disk/by-id/ata-foobar_deadbeefmdadmlvm{0..4}
1147 )
1148
1149 ls -l "${devices[@]}"
1150
1151 raid_name="mdlvm"
1152 raid_dev="/dev/md/$raid_name"
1153 part_name="${raid_name}_part"
1154 vgroup="${raid_name}_vg"
1155 uuid="aaaaaaaa:bbbbbbbb:ffffffff:00001010"
1156 expected_symlinks=(
1157 "$raid_dev"
1158 "/dev/$vgroup/mypart1" # LVM partition
1159 "/dev/$vgroup/mypart2" # LVM partition
1160 "/dev/disk/by-id/md-name-H:$raid_name"
1161 "/dev/disk/by-id/md-uuid-$uuid"
1162 "/dev/disk/by-label/$part_name" # ext4 partition
1163 )
1164 # Create a RAID 10 with LVM + ext4
1165 echo y | mdadm --create "$raid_dev" --name "$raid_name" --uuid "$uuid" /dev/disk/by-id/ata-foobar_deadbeefmdadmlvm{0..3} -v -f --level=10 --raid-devices=4
1166 udevadm wait --settle --timeout=30 "$raid_dev"
1167 # Create an LVM on the MD
1168 lvm pvcreate -y "$raid_dev"
1169 lvm pvs
1170 lvm vgcreate "$vgroup" -y "$raid_dev"
1171 lvm vgs
1172 lvm vgchange -ay "$vgroup"
1173 lvm lvcreate -y -L 4M "$vgroup" -n mypart1
1174 lvm lvcreate -y -L 8M "$vgroup" -n mypart2
1175 lvm lvs
1176 udevadm wait --settle --timeout=30 "/dev/$vgroup/mypart1" "/dev/$vgroup/mypart2"
1177 mkfs.ext4 -L "$part_name" "/dev/$vgroup/mypart2"
1178 udevadm wait --settle --timeout=30 "${expected_symlinks[@]}"
1179 # Disassemble the array
1180 lvm vgchange -an "$vgroup"
1181 mdadm -v --stop "$raid_dev"
6d49e094 1182 udevadm wait --settle --timeout=30 --removed "${expected_symlinks[@]}"
d3ce9bed 1183 helper_check_device_symlinks
9c126b2c 1184 helper_check_device_units
d3ce9bed 1185 # Reassemble it and check if all required symlinks exist
1bb38875 1186 mdadm --assemble "$raid_dev" --name "$raid_name" -v
3c9af05c
FS
1187 udevadm wait --settle --timeout=30 "${expected_symlinks[@]}"
1188 helper_check_device_symlinks
9c126b2c 1189 helper_check_device_units
6d49e094
FS
1190 # Cleanup
1191 lvm vgchange -an "$vgroup"
1192 mdadm -v --stop "$raid_dev"
1193 # Check if all expected symlinks were removed after the cleanup
1194 udevadm wait --settle --timeout=30 --removed "${expected_symlinks[@]}"
9c126b2c 1195 helper_check_device_units
3c9af05c
FS
1196}
1197
f2204ac2 1198udevadm settle
8a088877 1199udevadm control --log-level debug
f2204ac2
FS
1200lsblk -a
1201
d430e451
FS
1202echo "Check if all symlinks under /dev/disk/ are valid (pre-test)"
1203helper_check_device_symlinks
1204
f2204ac2
FS
1205# TEST_FUNCTION_NAME is passed on the kernel command line via systemd.setenv=
1206# in the respective test.sh file
1207if ! command -v "${TEST_FUNCTION_NAME:?}"; then
1208 echo >&2 "Missing verification handler for test case '$TEST_FUNCTION_NAME'"
1209 exit 1
1210fi
1211
1212echo "TEST_FUNCTION_NAME=$TEST_FUNCTION_NAME"
1213"$TEST_FUNCTION_NAME"
f415cdb3 1214udevadm settle
f2204ac2 1215
d430e451
FS
1216echo "Check if all symlinks under /dev/disk/ are valid (post-test)"
1217helper_check_device_symlinks
1218
8a088877
YW
1219udevadm control --log-level info
1220
f2204ac2
FS
1221systemctl status systemd-udevd
1222
1223touch /testok