Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/geom/class/multipath/misc.sh
39635 views
1
#!/bin/sh
2
# Copyright (c) 2019 Axcient
3
#
4
# Redistribution and use in source and binary forms, with or without
5
# modification, are permitted provided that the following conditions
6
# are met:
7
# 1. Redistributions of source code must retain the above copyright
8
# notice, this list of conditions and the following disclaimer.
9
# 2. Redistributions in binary form must reproduce the above copyright
10
# notice, this list of conditions and the following disclaimer in the
11
# documentation and/or other materials provided with the distribution.
12
#
13
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23
# SUCH DAMAGE.
24
#
25
26
. $(atf_get_srcdir)/conf.sh
27
28
atf_test_case add cleanup
29
add_head()
30
{
31
atf_set "descr" "Add a new path"
32
atf_set "require.user" "root"
33
}
34
add_body()
35
{
36
load_gmultipath
37
load_dtrace
38
39
md0=$(alloc_md)
40
md1=$(alloc_md)
41
md2=$(alloc_md)
42
name=$(mkname)
43
atf_check -s exit:0 gmultipath create "$name" ${md0} ${md1}
44
check_multipath_state ${md0} "OPTIMAL" "ACTIVE" "PASSIVE"
45
46
# Add a new path
47
atf_check -s exit:0 gmultipath add "$name" ${md2}
48
check_multipath_state ${md0} "OPTIMAL" "ACTIVE" "PASSIVE" "PASSIVE"
49
}
50
add_cleanup()
51
{
52
common_cleanup
53
}
54
55
atf_test_case create_A cleanup
56
create_A_head()
57
{
58
atf_set "descr" "Create an Active/Active multipath device"
59
atf_set "require.user" "root"
60
}
61
create_A_body()
62
{
63
load_gmultipath
64
load_dtrace
65
66
md0=$(alloc_md)
67
md1=$(alloc_md)
68
name=$(mkname)
69
atf_check -s exit:0 gmultipath create -A "$name" ${md0} ${md1}
70
check_multipath_state "${md1} ${md0}" "OPTIMAL" "ACTIVE" "ACTIVE"
71
}
72
create_A_cleanup()
73
{
74
common_cleanup
75
}
76
77
atf_test_case create_R cleanup
78
create_R_head()
79
{
80
atf_set "descr" "Create an Active/Read multipath device"
81
atf_set "require.user" "root"
82
}
83
create_R_body()
84
{
85
load_gmultipath
86
load_dtrace
87
88
md0=$(alloc_md)
89
md1=$(alloc_md)
90
name=$(mkname)
91
atf_check -s exit:0 gmultipath create -R "$name" ${md0} ${md1}
92
check_multipath_state ${md0} "OPTIMAL" "ACTIVE" "READ"
93
}
94
create_R_cleanup()
95
{
96
common_cleanup
97
}
98
99
atf_test_case depart_and_arrive cleanup
100
depart_and_arrive_head()
101
{
102
atf_set "descr" "gmultipath should remove devices that disappear, and automatically reattach labeled providers that reappear"
103
atf_set "require.user" "root"
104
}
105
depart_and_arrive_body()
106
{
107
load_gnop
108
load_gmultipath
109
md0=$(alloc_md)
110
md1=$(alloc_md)
111
name=$(mkname)
112
# We need a non-zero offset to gmultipath won't see the label when it
113
# tastes the md device. We only want the label to be visible on the
114
# gnop device.
115
offset=131072
116
atf_check gnop create -o $offset /dev/${md0}
117
atf_check gnop create -o $offset /dev/${md1}
118
atf_check -s exit:0 gmultipath label "$name" ${md0}.nop
119
# gmultipath is too smart to let us create a gmultipath device by label
120
# when the two providers aren't actually related. So we create a
121
# device by label with one provider, and then manually add the second.
122
atf_check -s exit:0 gmultipath add "$name" ${md1}.nop
123
NDEVS=`gmultipath list "$name" | grep -c 'md[0-9]*\.nop'`
124
atf_check_equal 2 $NDEVS
125
126
# Now fail the labeled provider
127
atf_check -s exit:0 gnop destroy -f ${md0}.nop
128
# It should be automatically removed from the multipath device
129
NDEVS=`gmultipath list "$name" | grep -c 'md[0-9]*\.nop'`
130
atf_check_equal 1 $NDEVS
131
132
# Now return the labeled provider
133
atf_check gnop create -o $offset /dev/${md0}
134
# It should be automatically restored to the multipath device. We
135
# don't really care which path is active.
136
NDEVS=`gmultipath list "$name" | grep -c 'md[0-9]*\.nop'`
137
atf_check_equal 2 $NDEVS
138
STATE=`gmultipath list "$name" | awk '/^State:/ {print $2}'`
139
atf_check_equal "OPTIMAL" $STATE
140
}
141
depart_and_arrive_cleanup()
142
{
143
common_cleanup
144
}
145
146
147
atf_test_case fail cleanup
148
fail_head()
149
{
150
atf_set "descr" "Manually fail a path"
151
atf_set "require.user" "root"
152
}
153
fail_body()
154
{
155
load_gmultipath
156
md0=$(alloc_md)
157
md1=$(alloc_md)
158
name=$(mkname)
159
atf_check -s exit:0 gmultipath create "$name" ${md0} ${md1}
160
check_multipath_state ${md0} "OPTIMAL" "ACTIVE" "PASSIVE"
161
# Manually fail the active path
162
atf_check -s exit:0 gmultipath fail "$name" ${md0}
163
check_multipath_state ${md1} "DEGRADED" "FAIL" "ACTIVE"
164
}
165
fail_cleanup()
166
{
167
common_cleanup
168
}
169
170
atf_test_case fail_on_error cleanup
171
fail_on_error_head()
172
{
173
atf_set "descr" "An error in the provider will cause gmultipath to mark it as FAIL"
174
atf_set "require.user" "root"
175
}
176
fail_on_error_body()
177
{
178
load_gnop
179
load_gmultipath
180
md0=$(alloc_md)
181
md1=$(alloc_md)
182
name=$(mkname)
183
atf_check gnop create /dev/${md0}
184
atf_check gnop create /dev/${md1}
185
atf_check -s exit:0 gmultipath create "$name" ${md0}.nop ${md1}.nop
186
# The first I/O to the first path should fail, causing gmultipath to
187
# fail over to the second path.
188
atf_check gnop configure -r 100 -w 100 ${md0}.nop
189
atf_check -s exit:0 -o ignore -e ignore dd if=/dev/zero of=/dev/multipath/"$name" bs=4096 count=1
190
check_multipath_state ${md1}.nop "DEGRADED" "FAIL" "ACTIVE"
191
}
192
fail_on_error_cleanup()
193
{
194
common_cleanup
195
}
196
197
atf_test_case physpath cleanup
198
physpath_head()
199
{
200
atf_set "descr" "gmultipath should append /mp to the underlying providers' physical path"
201
atf_set "require.user" "root"
202
}
203
physpath_body()
204
{
205
load_gnop
206
load_gmultipath
207
md0=$(alloc_md)
208
md1=$(alloc_md)
209
name=$(mkname)
210
physpath="some/physical/path"
211
# Create two providers with the same physical paths, mimicing how
212
# multipathed SAS drives appear. This is the normal way to use
213
# gmultipath. If the underlying providers' physical paths differ,
214
# then you're probably using gmultipath wrong.
215
atf_check gnop create -z $physpath /dev/${md0}
216
atf_check gnop create -z $physpath /dev/${md1}
217
atf_check -s exit:0 gmultipath create "$name" ${md0}.nop ${md1}.nop
218
gmultipath_physpath=$(diskinfo -p multipath/"$name")
219
atf_check_equal "$physpath/mp" "$gmultipath_physpath"
220
}
221
physpath_cleanup()
222
{
223
common_cleanup
224
}
225
226
atf_test_case prefer cleanup
227
prefer_head()
228
{
229
atf_set "descr" "Manually select the preferred path"
230
atf_set "require.user" "root"
231
}
232
prefer_body()
233
{
234
load_gmultipath
235
load_dtrace
236
237
md0=$(alloc_md)
238
md1=$(alloc_md)
239
md2=$(alloc_md)
240
name=$(mkname)
241
atf_check -s exit:0 gmultipath create "$name" ${md0} ${md1} ${md2}
242
check_multipath_state ${md0} "OPTIMAL" "ACTIVE" "PASSIVE" "PASSIVE"
243
244
# Explicitly prefer the final path
245
atf_check -s exit:0 gmultipath prefer "$name" ${md2}
246
check_multipath_state ${md2} "OPTIMAL" "PASSIVE" "PASSIVE" "ACTIVE"
247
}
248
prefer_cleanup()
249
{
250
common_cleanup
251
}
252
253
atf_test_case restore cleanup
254
restore_head()
255
{
256
atf_set "descr" "Manually restore a failed path"
257
atf_set "require.user" "root"
258
}
259
restore_body()
260
{
261
load_gmultipath
262
load_dtrace
263
264
md0=$(alloc_md)
265
md1=$(alloc_md)
266
name=$(mkname)
267
atf_check -s exit:0 gmultipath create "$name" ${md0} ${md1}
268
269
# Explicitly fail the first path
270
atf_check -s exit:0 gmultipath fail "$name" ${md0}
271
check_multipath_state ${md1} "DEGRADED" "FAIL" "ACTIVE"
272
273
# Explicitly restore it
274
atf_check -s exit:0 gmultipath restore "$name" ${md0}
275
check_multipath_state ${md1} "OPTIMAL" "PASSIVE" "ACTIVE"
276
}
277
restore_cleanup()
278
{
279
common_cleanup
280
}
281
282
atf_test_case restore_on_error cleanup
283
restore_on_error_head()
284
{
285
atf_set "descr" "A failed path should be restored if an I/O error is encountered on all other active paths"
286
atf_set "require.user" "root"
287
}
288
restore_on_error_body()
289
{
290
load_gnop
291
load_gmultipath
292
load_dtrace
293
294
md0=$(alloc_md)
295
md1=$(alloc_md)
296
name=$(mkname)
297
atf_check gnop create /dev/${md0}
298
atf_check gnop create /dev/${md1}
299
atf_check -s exit:0 gmultipath create "$name" ${md0}.nop ${md1}.nop
300
# Explicitly fail the first path
301
atf_check -s exit:0 gmultipath fail "$name" ${md0}.nop
302
303
# Setup the second path to fail on the next I/O
304
atf_check gnop configure -r 100 -w 100 ${md1}.nop
305
atf_check -s exit:0 -o ignore -e ignore \
306
dd if=/dev/zero of=/dev/multipath/"$name" bs=4096 count=1
307
308
# Now the first path should be active, and the second should be failed
309
check_multipath_state ${md0}.nop "DEGRADED" "ACTIVE" "FAIL"
310
}
311
restore_on_error_cleanup()
312
{
313
common_cleanup
314
}
315
316
atf_test_case rotate cleanup
317
rotate_head()
318
{
319
atf_set "descr" "Manually rotate the active path"
320
atf_set "require.user" "root"
321
}
322
rotate_body()
323
{
324
load_gmultipath
325
load_dtrace
326
327
md0=$(alloc_md)
328
md1=$(alloc_md)
329
md2=$(alloc_md)
330
name=$(mkname)
331
atf_check -s exit:0 gmultipath create "$name" ${md0} ${md1} ${md2}
332
check_multipath_state ${md0} "OPTIMAL" "ACTIVE" "PASSIVE" "PASSIVE"
333
334
# Explicitly rotate the paths
335
atf_check -s exit:0 gmultipath rotate "$name"
336
check_multipath_state ${md2} "OPTIMAL" "PASSIVE" "PASSIVE" "ACTIVE"
337
# Again
338
atf_check -s exit:0 gmultipath rotate "$name"
339
check_multipath_state ${md1} "OPTIMAL" "PASSIVE" "ACTIVE" "PASSIVE"
340
# Final rotation should restore original configuration
341
atf_check -s exit:0 gmultipath rotate "$name"
342
check_multipath_state ${md0} "OPTIMAL" "ACTIVE" "PASSIVE" "PASSIVE"
343
}
344
rotate_cleanup()
345
{
346
common_cleanup
347
}
348
349
atf_init_test_cases()
350
{
351
atf_add_test_case add
352
atf_add_test_case create_A
353
atf_add_test_case create_R
354
atf_add_test_case depart_and_arrive
355
atf_add_test_case fail
356
atf_add_test_case fail_on_error
357
atf_add_test_case physpath
358
atf_add_test_case prefer
359
atf_add_test_case restore
360
atf_add_test_case restore_on_error
361
atf_add_test_case rotate
362
}
363
364