]>
Commit | Line | Data |
---|---|---|
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 | ||
5 | set -eux | |
6 | set -o pipefail | |
7 | ||
d430e451 | 8 | # Check if all symlinks under /dev/disk/ are valid |
df72bd45 | 9 | # shellcheck disable=SC2120 |
de11005c FS |
10 | helper_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 |
43 | helper_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 |
83 | check_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 | ||
131 | check_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 | ||
156 | helper_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 |
171 | testcase_megasas2_basic() { |
172 | lsblk -S | |
173 | [[ "$(lsblk --scsi --noheadings | wc -l)" -ge 128 ]] | |
174 | } | |
175 | ||
176 | testcase_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 |
227 | testcase_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 | 241 | testcase_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 | |
255 | label: gpt | |
256 | ||
257 | $(for ((j = 1; j <= num_part; j++)); do echo 'name="Hello world", size=2M'; done) | |
258 | EOF | |
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 |
265 | testcase_multipath_basic_failover() { |
266 | local dmpath i path wwid | |
267 | ||
268 | # Configure multipath | |
269 | cat >/etc/multipath.conf <<\EOF | |
270 | defaults { | |
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 | ||
277 | blacklist_exceptions { | |
278 | property "(SCSI_IDENT_|ID_WWN)" | |
279 | } | |
280 | ||
281 | blacklist { | |
282 | } | |
283 | EOF | |
b6183109 SL |
284 | |
285 | sfdisk /dev/sda <<EOF | |
286 | label: gpt | |
287 | ||
288 | name="first_partition", size=5M | |
289 | uuid="deadbeef-dead-dead-beef-000000000000", name="failover_part", size=5M | |
290 | EOF | |
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 | 374 | testcase_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) |
410 | EOF | |
411 | ||
412 | rule=/run/udev/rules.d/50-test.rules | |
413 | mkdir -p "${rule%/*}" | |
414 | cat >"$rule" <<EOF | |
415 | SUBSYSTEM=="block", KERNEL=="${devices[4]##*/}*|${devices[5]##*/}*", OPTIONS="link_priority=10" | |
35497c7c FS |
416 | EOF |
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 | 472 | testcase_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 | 505 | EOF |
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 | ||
536 | testcase_simultaneous_events() { | |
537 | testcase_simultaneous_events_1 | |
538 | testcase_simultaneous_events_2 | |
539 | } | |
540 | ||
0203b2e4 | 541 | testcase_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 |
714 | testcase_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 |
735 | label: gpt |
736 | ||
737 | name="diskpart1", size=85M | |
738 | name="diskpart2", size=85M | |
739 | name="diskpart3", size=85M | |
740 | name="diskpart4", size=85M | |
741 | EOF | |
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 |
841 | testcase_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 | |
952 | testcase_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 | |
976 | label: gpt | |
977 | ||
978 | name="test_swap", size=32M | |
979 | uuid="deadbeef-dead-dead-beef-000000000000", name="test_part", size=5M | |
980 | EOF | |
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 | 1022 | testcase_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 | |
1117 | label: gpt | |
1118 | ||
1119 | uuid="deadbeef-dead-dead-beef-111111111111", name="mdpart1", size=8M | |
1120 | uuid="deadbeef-dead-dead-beef-222222222222", name="mdpart2", size=32M | |
1121 | uuid="deadbeef-dead-dead-beef-333333333333", name="mdpart3", size=16M | |
1122 | EOF | |
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 | ||
1142 | testcase_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 | 1198 | udevadm settle |
8a088877 | 1199 | udevadm control --log-level debug |
f2204ac2 FS |
1200 | lsblk -a |
1201 | ||
d430e451 FS |
1202 | echo "Check if all symlinks under /dev/disk/ are valid (pre-test)" |
1203 | helper_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 | |
1207 | if ! command -v "${TEST_FUNCTION_NAME:?}"; then | |
1208 | echo >&2 "Missing verification handler for test case '$TEST_FUNCTION_NAME'" | |
1209 | exit 1 | |
1210 | fi | |
1211 | ||
1212 | echo "TEST_FUNCTION_NAME=$TEST_FUNCTION_NAME" | |
1213 | "$TEST_FUNCTION_NAME" | |
f415cdb3 | 1214 | udevadm settle |
f2204ac2 | 1215 | |
d430e451 FS |
1216 | echo "Check if all symlinks under /dev/disk/ are valid (post-test)" |
1217 | helper_check_device_symlinks | |
1218 | ||
8a088877 YW |
1219 | udevadm control --log-level info |
1220 | ||
f2204ac2 FS |
1221 | systemctl status systemd-udevd |
1222 | ||
1223 | touch /testok |