1#
2# CDDL HEADER START
3#
4# The contents of this file are subject to the terms of the
5# Common Development and Distribution License (the "License").
6# You may not use this file except in compliance with the License.
7#
8# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9# or https://opensource.org/licenses/CDDL-1.0.
10# See the License for the specific language governing permissions
11# and limitations under the License.
12#
13# When distributing Covered Code, include this CDDL HEADER in each
14# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15# If applicable, add the following below this CDDL HEADER, with the
16# fields enclosed by brackets "[]" replaced with your own identifying
17# information: Portions Copyright [yyyy] [name of copyright owner]
18#
19# CDDL HEADER END
20#
21
22#
23# Copyright 2017, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
24#
25
26. $STF_SUITE/include/libtest.shlib
27. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
28. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
29
30#
31# Wait for udev to settle, completely.
32# This is quite discomforting, but there's a race condition here
33# (Amazon 2015.09 x86_64 Release (TEST) is good at triggering this)  where the
34# kernel tries to remove zvol device nodes while they're open by [blkid],
35# [zvol_id] or other udev related processes.
36# Calling 'udevadm settle' is not enough: wait for those processes "manually".
37#
38function udev_wait
39{
40	udevadm trigger --action=change
41	udevadm settle
42	for i in {1..3}; do
43		blkid="$(pgrep blkid | wc -l)"
44		zvol_id="$(pgrep zvol_id | wc -l)"
45		[[ "0" == "$zvol_id" && "0" == "$blkid" ]] && return
46		udevadm settle
47	done
48	log_fail "Wait timeout reached for udev_wait"
49}
50
51#
52# Clean up udev status
53# This is also a problem on "Amazon 2015.09 x86_64 Release (TEST)" where udev,
54# sometimes, does not clean up /dev/zvol symlinks correctly for removed ZVOLs.
55# Prune those links manually, then tell udev to forget them.
56#
57function udev_cleanup
58{
59	log_note "Pruning broken ZVOL symlinks ..."
60
61	udevadm settle
62	# find all dangling links and delete them
63	find -L "${ZVOL_DEVDIR}" -type l -print -delete
64	# purge those links from udev database
65	udevadm info --cleanup-db
66}
67
68#
69# Verify $device exists and is a block device
70#
71function blockdev_exists # device
72{
73	typeset device="$1"
74
75	# we wait here instead of doing it in a wrapper around 'zfs set snapdev'
76	# because there are other commands (zfs snap, zfs inherit, zfs destroy)
77	# that can affect device nodes
78	for i in {1..3}; do
79		is_linux && udev_wait
80		block_device_wait "$device"
81		is_disk_device "$device" && return 0
82	done
83	log_fail "$device does not exist as a block device"
84}
85
86#
87# Verify $device does not exist
88#
89function blockdev_missing # device
90{
91	typeset device="$1"
92
93	# we wait here instead of doing it in a wrapper around 'zfs set snapdev'
94	# because there are other commands (zfs snap, zfs inherit, zfs destroy)
95	# that can affect device nodes
96	for i in {1..3}; do
97		is_linux && udev_wait
98		block_device_wait
99		is_disk_device "$device" || return 0
100	done
101	log_fail "$device exists when not expected"
102}
103
104#
105# Verify $property on $dataset is inherited by $parent and is set to $value
106#
107function verify_inherited # property value dataset parent
108{
109	typeset property="$1"
110	typeset value="$2"
111	typeset dataset="$3"
112	typeset parent="$4"
113
114	typeset val=$(get_prop "$property" "$dataset")
115	typeset src=$(get_source "$property" "$dataset")
116	if [[ "$val" != "$value" || "$src" != "inherited from $parent" ]]; then
117		log_fail "Dataset $dataset did not inherit $property properly:"\
118		    "expected=$value, value=$val, source=$src."
119	fi
120}
121
122#
123# Create a small partition on $device, then verify if we can access it
124#
125function verify_partition # device
126{
127	typeset device="$1"
128
129	if ! is_disk_device "$device"; then
130		log_fail "$device is not a block device"
131	fi
132	# create a small dummy partition
133	set_partition 0 "" 1m $device
134	# verify we can access the partition on the device
135	devname="$(readlink -f "$device")"
136	if is_linux || is_freebsd; then
137		is_disk_device "${devname}p1"
138	else
139		is_disk_device "${devname}s0"
140	fi
141}
142