xref: /freebsd/tests/sys/geom/class/multipath/misc.sh (revision deed14f4518b6146be591a7a8112bafea3cf65c9)
167f72211SAlan Somers#!/bin/sh
267f72211SAlan Somers# Copyright (c) 2019 Axcient
367f72211SAlan Somers#
467f72211SAlan Somers# Redistribution and use in source and binary forms, with or without
567f72211SAlan Somers# modification, are permitted provided that the following conditions
667f72211SAlan Somers# are met:
767f72211SAlan Somers# 1. Redistributions of source code must retain the above copyright
867f72211SAlan Somers#    notice, this list of conditions and the following disclaimer.
967f72211SAlan Somers# 2. Redistributions in binary form must reproduce the above copyright
1067f72211SAlan Somers#    notice, this list of conditions and the following disclaimer in the
1167f72211SAlan Somers#    documentation and/or other materials provided with the distribution.
1267f72211SAlan Somers#
1367f72211SAlan Somers# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1467f72211SAlan Somers# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1567f72211SAlan Somers# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1667f72211SAlan Somers# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1767f72211SAlan Somers# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1867f72211SAlan Somers# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1967f72211SAlan Somers# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2067f72211SAlan Somers# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2167f72211SAlan Somers# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2267f72211SAlan Somers# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2367f72211SAlan Somers# SUCH DAMAGE.
2467f72211SAlan Somers#
2567f72211SAlan Somers# $FreeBSD$
2667f72211SAlan Somers
2767f72211SAlan Somers. $(atf_get_srcdir)/conf.sh
2867f72211SAlan Somers
2967f72211SAlan Somersatf_test_case add cleanup
3067f72211SAlan Somersadd_head()
3167f72211SAlan Somers{
3267f72211SAlan Somers	atf_set "descr" "Add a new path"
3367f72211SAlan Somers	atf_set "require.user" "root"
3467f72211SAlan Somers}
3567f72211SAlan Somersadd_body()
3667f72211SAlan Somers{
3767f72211SAlan Somers	load_gmultipath
3867f72211SAlan Somers	load_dtrace
3967f72211SAlan Somers
4067f72211SAlan Somers	md0=$(alloc_md)
4167f72211SAlan Somers	md1=$(alloc_md)
4267f72211SAlan Somers	md2=$(alloc_md)
4367f72211SAlan Somers	name=$(mkname)
4467f72211SAlan Somers	atf_check -s exit:0 gmultipath create "$name" ${md0} ${md1}
4567f72211SAlan Somers	check_multipath_state ${md0} "OPTIMAL" "ACTIVE" "PASSIVE"
4667f72211SAlan Somers
4767f72211SAlan Somers	# Add a new path
4867f72211SAlan Somers	atf_check -s exit:0 gmultipath add "$name" ${md2}
4967f72211SAlan Somers	check_multipath_state ${md0} "OPTIMAL" "ACTIVE" "PASSIVE" "PASSIVE"
5067f72211SAlan Somers}
5167f72211SAlan Somersadd_cleanup()
5267f72211SAlan Somers{
5367f72211SAlan Somers	common_cleanup
5467f72211SAlan Somers}
5567f72211SAlan Somers
5667f72211SAlan Somersatf_test_case create_A cleanup
5767f72211SAlan Somerscreate_A_head()
5867f72211SAlan Somers{
5967f72211SAlan Somers	atf_set "descr" "Create an Active/Active multipath device"
6067f72211SAlan Somers	atf_set "require.user" "root"
6167f72211SAlan Somers}
6267f72211SAlan Somerscreate_A_body()
6367f72211SAlan Somers{
6467f72211SAlan Somers	load_gmultipath
6567f72211SAlan Somers	load_dtrace
6667f72211SAlan Somers
6767f72211SAlan Somers	md0=$(alloc_md)
6867f72211SAlan Somers	md1=$(alloc_md)
6967f72211SAlan Somers	name=$(mkname)
7067f72211SAlan Somers	atf_check -s exit:0 gmultipath create -A "$name" ${md0} ${md1}
7167f72211SAlan Somers	check_multipath_state "${md1} ${md0}" "OPTIMAL" "ACTIVE" "ACTIVE"
7267f72211SAlan Somers}
7367f72211SAlan Somerscreate_A_cleanup()
7467f72211SAlan Somers{
7567f72211SAlan Somers	common_cleanup
7667f72211SAlan Somers}
7767f72211SAlan Somers
7867f72211SAlan Somersatf_test_case create_R cleanup
7967f72211SAlan Somerscreate_R_head()
8067f72211SAlan Somers{
8167f72211SAlan Somers	atf_set "descr" "Create an Active/Read multipath device"
8267f72211SAlan Somers	atf_set "require.user" "root"
8367f72211SAlan Somers}
8467f72211SAlan Somerscreate_R_body()
8567f72211SAlan Somers{
8667f72211SAlan Somers	load_gmultipath
8767f72211SAlan Somers	load_dtrace
8867f72211SAlan Somers
8967f72211SAlan Somers	md0=$(alloc_md)
9067f72211SAlan Somers	md1=$(alloc_md)
9167f72211SAlan Somers	name=$(mkname)
9267f72211SAlan Somers	atf_check -s exit:0 gmultipath create -R "$name" ${md0} ${md1}
9367f72211SAlan Somers	check_multipath_state ${md0} "OPTIMAL" "ACTIVE" "READ"
9467f72211SAlan Somers}
9567f72211SAlan Somerscreate_R_cleanup()
9667f72211SAlan Somers{
9767f72211SAlan Somers	common_cleanup
9867f72211SAlan Somers}
9967f72211SAlan Somers
10067f72211SAlan Somersatf_test_case depart_and_arrive cleanup
10167f72211SAlan Somersdepart_and_arrive_head()
10267f72211SAlan Somers{
10367f72211SAlan Somers	atf_set "descr" "gmultipath should remove devices that disappear, and automatically reattach labeled providers that reappear"
10467f72211SAlan Somers	atf_set "require.user" "root"
10567f72211SAlan Somers}
10667f72211SAlan Somersdepart_and_arrive_body()
10767f72211SAlan Somers{
10867f72211SAlan Somers	load_gnop
10967f72211SAlan Somers	load_gmultipath
11067f72211SAlan Somers	md0=$(alloc_md)
11167f72211SAlan Somers	md1=$(alloc_md)
11267f72211SAlan Somers	name=$(mkname)
11367f72211SAlan Somers	# We need a non-zero offset to gmultipath won't see the label when it
11467f72211SAlan Somers	# tastes the md device.  We only want the label to be visible on the
11567f72211SAlan Somers	# gnop device.
11667f72211SAlan Somers	offset=131072
11767f72211SAlan Somers	atf_check gnop create -o $offset /dev/${md0}
11867f72211SAlan Somers	atf_check gnop create -o $offset /dev/${md1}
11967f72211SAlan Somers	atf_check -s exit:0 gmultipath label "$name" ${md0}.nop
12067f72211SAlan Somers	# gmultipath is too smart to let us create a gmultipath device by label
12167f72211SAlan Somers	# when the two providers aren't actually related.  So we create a
12267f72211SAlan Somers	# device by label with one provider, and then manually add the second.
12367f72211SAlan Somers	atf_check -s exit:0 gmultipath add "$name" ${md1}.nop
12467f72211SAlan Somers	NDEVS=`gmultipath list "$name" | grep -c 'md[0-9]*\.nop'`
12567f72211SAlan Somers	atf_check_equal 2 $NDEVS
12667f72211SAlan Somers
12767f72211SAlan Somers	# Now fail the labeled provider
12867f72211SAlan Somers	atf_check -s exit:0 gnop destroy -f ${md0}.nop
12967f72211SAlan Somers	# It should be automatically removed from the multipath device
13067f72211SAlan Somers	NDEVS=`gmultipath list "$name" | grep -c 'md[0-9]*\.nop'`
13167f72211SAlan Somers	atf_check_equal 1 $NDEVS
13267f72211SAlan Somers
13367f72211SAlan Somers	# Now return the labeled provider
13467f72211SAlan Somers	atf_check gnop create -o $offset /dev/${md0}
13567f72211SAlan Somers	# It should be automatically restored to the multipath device.  We
13667f72211SAlan Somers	# don't really care which path is active.
13767f72211SAlan Somers	NDEVS=`gmultipath list "$name" | grep -c 'md[0-9]*\.nop'`
13867f72211SAlan Somers	atf_check_equal 2 $NDEVS
13967f72211SAlan Somers	STATE=`gmultipath list "$name" | awk '/^State:/ {print $2}'`
14067f72211SAlan Somers	atf_check_equal "OPTIMAL" $STATE
14167f72211SAlan Somers}
14267f72211SAlan Somersdepart_and_arrive_cleanup()
14367f72211SAlan Somers{
14467f72211SAlan Somers	common_cleanup
14567f72211SAlan Somers}
14667f72211SAlan Somers
14767f72211SAlan Somers
14867f72211SAlan Somersatf_test_case fail cleanup
14967f72211SAlan Somersfail_head()
15067f72211SAlan Somers{
15167f72211SAlan Somers	atf_set "descr" "Manually fail a path"
15267f72211SAlan Somers	atf_set "require.user" "root"
15367f72211SAlan Somers}
15467f72211SAlan Somersfail_body()
15567f72211SAlan Somers{
15667f72211SAlan Somers	load_gmultipath
15767f72211SAlan Somers	md0=$(alloc_md)
15867f72211SAlan Somers	md1=$(alloc_md)
15967f72211SAlan Somers	name=$(mkname)
16067f72211SAlan Somers	atf_check -s exit:0 gmultipath create "$name" ${md0} ${md1}
16167f72211SAlan Somers	check_multipath_state ${md0} "OPTIMAL" "ACTIVE" "PASSIVE"
16267f72211SAlan Somers	# Manually fail the active path
16367f72211SAlan Somers	atf_check -s exit:0 gmultipath fail "$name" ${md0}
16467f72211SAlan Somers	check_multipath_state ${md1} "DEGRADED" "FAIL" "ACTIVE"
16567f72211SAlan Somers}
16667f72211SAlan Somersfail_cleanup()
16767f72211SAlan Somers{
16867f72211SAlan Somers	common_cleanup
16967f72211SAlan Somers}
17067f72211SAlan Somers
17167f72211SAlan Somersatf_test_case fail_on_error cleanup
17267f72211SAlan Somersfail_on_error_head()
17367f72211SAlan Somers{
17467f72211SAlan Somers	atf_set "descr" "An error in the provider will cause gmultipath to mark it as FAIL"
17567f72211SAlan Somers	atf_set "require.user" "root"
17667f72211SAlan Somers}
17767f72211SAlan Somersfail_on_error_body()
17867f72211SAlan Somers{
17967f72211SAlan Somers	load_gnop
18067f72211SAlan Somers	load_gmultipath
18167f72211SAlan Somers	md0=$(alloc_md)
18267f72211SAlan Somers	md1=$(alloc_md)
18367f72211SAlan Somers	name=$(mkname)
18467f72211SAlan Somers	atf_check gnop create /dev/${md0}
18567f72211SAlan Somers	atf_check gnop create /dev/${md1}
18667f72211SAlan Somers	atf_check -s exit:0 gmultipath create "$name" ${md0}.nop ${md1}.nop
18767f72211SAlan Somers	# The first I/O to the first path should fail, causing gmultipath to
18867f72211SAlan Somers	# fail over to the second path.
189*deed14f4SAlan Somers	atf_check gnop configure -r 100 -w 100 ${md0}.nop
19067f72211SAlan Somers	atf_check -s exit:0 -o ignore -e ignore dd if=/dev/zero of=/dev/multipath/"$name" bs=4096 count=1
19167f72211SAlan Somers	check_multipath_state ${md1}.nop "DEGRADED" "FAIL" "ACTIVE"
19267f72211SAlan Somers}
19367f72211SAlan Somersfail_on_error_cleanup()
19467f72211SAlan Somers{
19567f72211SAlan Somers	common_cleanup
19667f72211SAlan Somers}
19767f72211SAlan Somers
19867f72211SAlan Somersatf_test_case physpath cleanup
19967f72211SAlan Somersphyspath_head()
20067f72211SAlan Somers{
20167f72211SAlan Somers	atf_set "descr" "gmultipath should pass through the underlying providers' physical path"
20267f72211SAlan Somers	atf_set "require.user" "root"
20367f72211SAlan Somers}
20467f72211SAlan Somersphyspath_body()
20567f72211SAlan Somers{
20667f72211SAlan Somers	load_gnop
20767f72211SAlan Somers	load_gmultipath
20867f72211SAlan Somers	md0=$(alloc_md)
20967f72211SAlan Somers	md1=$(alloc_md)
21067f72211SAlan Somers	name=$(mkname)
21167f72211SAlan Somers	physpath="some/physical/path"
21267f72211SAlan Somers	# Create two providers with the same physical paths, mimicing how
21367f72211SAlan Somers	# multipathed SAS drives appear.  This is the normal way to use
21467f72211SAlan Somers	# gmultipath.  If the underlying providers' physical paths differ,
21567f72211SAlan Somers	# then you're probably using gmultipath wrong.
21667f72211SAlan Somers	atf_check gnop create -z $physpath /dev/${md0}
21767f72211SAlan Somers	atf_check gnop create -z $physpath /dev/${md1}
21867f72211SAlan Somers	atf_check -s exit:0 gmultipath create "$name" ${md0}.nop ${md1}.nop
21967f72211SAlan Somers	gmultipath_physpath=$(diskinfo -p multipath/"$name")
22067f72211SAlan Somers	atf_check_equal "$physpath" "$gmultipath_physpath"
22167f72211SAlan Somers}
22267f72211SAlan Somersphyspath_cleanup()
22367f72211SAlan Somers{
22467f72211SAlan Somers	common_cleanup
22567f72211SAlan Somers}
22667f72211SAlan Somers
22767f72211SAlan Somersatf_test_case prefer cleanup
22867f72211SAlan Somersprefer_head()
22967f72211SAlan Somers{
23067f72211SAlan Somers	atf_set "descr" "Manually select the preferred path"
23167f72211SAlan Somers	atf_set "require.user" "root"
23267f72211SAlan Somers}
23367f72211SAlan Somersprefer_body()
23467f72211SAlan Somers{
23567f72211SAlan Somers	load_gmultipath
23667f72211SAlan Somers	load_dtrace
23767f72211SAlan Somers
23867f72211SAlan Somers	md0=$(alloc_md)
23967f72211SAlan Somers	md1=$(alloc_md)
24067f72211SAlan Somers	md2=$(alloc_md)
24167f72211SAlan Somers	name=$(mkname)
24267f72211SAlan Somers	atf_check -s exit:0 gmultipath create "$name" ${md0} ${md1} ${md2}
24367f72211SAlan Somers	check_multipath_state ${md0} "OPTIMAL" "ACTIVE" "PASSIVE" "PASSIVE"
24467f72211SAlan Somers
24567f72211SAlan Somers	# Explicitly prefer the final path
24667f72211SAlan Somers	atf_check -s exit:0 gmultipath prefer "$name" ${md2}
24767f72211SAlan Somers	check_multipath_state ${md2} "OPTIMAL" "PASSIVE" "PASSIVE" "ACTIVE"
24867f72211SAlan Somers}
24967f72211SAlan Somersprefer_cleanup()
25067f72211SAlan Somers{
25167f72211SAlan Somers	common_cleanup
25267f72211SAlan Somers}
25367f72211SAlan Somers
25467f72211SAlan Somersatf_test_case restore cleanup
25567f72211SAlan Somersrestore_head()
25667f72211SAlan Somers{
25767f72211SAlan Somers	atf_set "descr" "Manually restore a failed path"
25867f72211SAlan Somers	atf_set "require.user" "root"
25967f72211SAlan Somers}
26067f72211SAlan Somersrestore_body()
26167f72211SAlan Somers{
26267f72211SAlan Somers	load_gmultipath
26367f72211SAlan Somers	load_dtrace
26467f72211SAlan Somers
26567f72211SAlan Somers	md0=$(alloc_md)
26667f72211SAlan Somers	md1=$(alloc_md)
26767f72211SAlan Somers	name=$(mkname)
26867f72211SAlan Somers	atf_check -s exit:0 gmultipath create "$name" ${md0} ${md1}
26967f72211SAlan Somers
27067f72211SAlan Somers	# Explicitly fail the first path
27167f72211SAlan Somers	atf_check -s exit:0 gmultipath fail "$name" ${md0}
27267f72211SAlan Somers	check_multipath_state ${md1} "DEGRADED" "FAIL" "ACTIVE"
27367f72211SAlan Somers
27467f72211SAlan Somers	# Explicitly restore it
27567f72211SAlan Somers	atf_check -s exit:0 gmultipath restore "$name" ${md0}
27667f72211SAlan Somers	check_multipath_state ${md1} "OPTIMAL" "PASSIVE" "ACTIVE"
27767f72211SAlan Somers}
27867f72211SAlan Somersrestore_cleanup()
27967f72211SAlan Somers{
28067f72211SAlan Somers	common_cleanup
28167f72211SAlan Somers}
28267f72211SAlan Somers
28367f72211SAlan Somersatf_test_case restore_on_error cleanup
28467f72211SAlan Somersrestore_on_error_head()
28567f72211SAlan Somers{
28667f72211SAlan Somers	atf_set "descr" "A failed path should be restored if an I/O error is encountered on all other active paths"
28767f72211SAlan Somers	atf_set "require.user" "root"
28867f72211SAlan Somers}
28967f72211SAlan Somersrestore_on_error_body()
29067f72211SAlan Somers{
29167f72211SAlan Somers	load_gnop
29267f72211SAlan Somers	load_gmultipath
29367f72211SAlan Somers	load_dtrace
29467f72211SAlan Somers
29567f72211SAlan Somers	md0=$(alloc_md)
29667f72211SAlan Somers	md1=$(alloc_md)
29767f72211SAlan Somers	name=$(mkname)
29867f72211SAlan Somers	atf_check gnop create /dev/${md0}
29967f72211SAlan Somers	atf_check gnop create /dev/${md1}
30067f72211SAlan Somers	atf_check -s exit:0 gmultipath create "$name" ${md0}.nop ${md1}.nop
30167f72211SAlan Somers	# Explicitly fail the first path
30267f72211SAlan Somers	atf_check -s exit:0 gmultipath fail "$name" ${md0}.nop
30367f72211SAlan Somers
30467f72211SAlan Somers	# Setup the second path to fail on the next I/O
30567f72211SAlan Somers	atf_check gnop configure -r 100 -w 100  ${md1}.nop
30667f72211SAlan Somers	atf_check -s exit:0 -o ignore -e ignore \
30767f72211SAlan Somers	    dd if=/dev/zero of=/dev/multipath/"$name" bs=4096 count=1
30867f72211SAlan Somers
30967f72211SAlan Somers	# Now the first path should be active, and the second should be failed
31067f72211SAlan Somers	check_multipath_state ${md0}.nop "DEGRADED" "ACTIVE" "FAIL"
31167f72211SAlan Somers}
31267f72211SAlan Somersrestore_on_error_cleanup()
31367f72211SAlan Somers{
31467f72211SAlan Somers	common_cleanup
31567f72211SAlan Somers}
31667f72211SAlan Somers
31767f72211SAlan Somersatf_test_case rotate cleanup
31867f72211SAlan Somersrotate_head()
31967f72211SAlan Somers{
32067f72211SAlan Somers	atf_set "descr" "Manually rotate the active path"
32167f72211SAlan Somers	atf_set "require.user" "root"
32267f72211SAlan Somers}
32367f72211SAlan Somersrotate_body()
32467f72211SAlan Somers{
32567f72211SAlan Somers	load_gmultipath
32667f72211SAlan Somers	load_dtrace
32767f72211SAlan Somers
32867f72211SAlan Somers	md0=$(alloc_md)
32967f72211SAlan Somers	md1=$(alloc_md)
33067f72211SAlan Somers	md2=$(alloc_md)
33167f72211SAlan Somers	name=$(mkname)
33267f72211SAlan Somers	atf_check -s exit:0 gmultipath create "$name" ${md0} ${md1} ${md2}
33367f72211SAlan Somers	check_multipath_state ${md0} "OPTIMAL" "ACTIVE" "PASSIVE" "PASSIVE"
33467f72211SAlan Somers
33567f72211SAlan Somers	# Explicitly rotate the paths
33667f72211SAlan Somers	atf_check -s exit:0 gmultipath rotate "$name"
33767f72211SAlan Somers	check_multipath_state ${md2} "OPTIMAL" "PASSIVE" "PASSIVE" "ACTIVE"
33867f72211SAlan Somers	# Again
33967f72211SAlan Somers	atf_check -s exit:0 gmultipath rotate "$name"
34067f72211SAlan Somers	check_multipath_state ${md1} "OPTIMAL" "PASSIVE" "ACTIVE" "PASSIVE"
34167f72211SAlan Somers	# Final rotation should restore original configuration
34267f72211SAlan Somers	atf_check -s exit:0 gmultipath rotate "$name"
34367f72211SAlan Somers	check_multipath_state ${md0} "OPTIMAL" "ACTIVE" "PASSIVE" "PASSIVE"
34467f72211SAlan Somers}
34567f72211SAlan Somersrotate_cleanup()
34667f72211SAlan Somers{
34767f72211SAlan Somers	common_cleanup
34867f72211SAlan Somers}
34967f72211SAlan Somers
35067f72211SAlan Somersatf_init_test_cases()
35167f72211SAlan Somers{
35267f72211SAlan Somers	atf_add_test_case add
35367f72211SAlan Somers	atf_add_test_case create_A
35467f72211SAlan Somers	atf_add_test_case create_R
35567f72211SAlan Somers	atf_add_test_case depart_and_arrive
35667f72211SAlan Somers	atf_add_test_case fail
35767f72211SAlan Somers	atf_add_test_case fail_on_error
35867f72211SAlan Somers	atf_add_test_case physpath
35967f72211SAlan Somers	atf_add_test_case prefer
36067f72211SAlan Somers	atf_add_test_case restore
36167f72211SAlan Somers	atf_add_test_case restore_on_error
36267f72211SAlan Somers	atf_add_test_case rotate
36367f72211SAlan Somers}
364