Whamcloud - gitweb
LU-123 Port yaml and auster to b1_8
[fs/lustre-release.git] / lustre / tests / mmp.sh
1 #!/bin/bash
2 # vim:expandtab:shiftwidth=4:softtabstop=4:tabstop=4:
3 #
4 # Tests for multiple mount protection (MMP) feature.
5 #
6 # Run select tests by setting ONLY, or as arguments to the script.
7 # Skip specific tests by setting EXCEPT.
8 #
9 # e.g. ONLY="5 6" or ONLY="`seq 8 11`" or EXCEPT="7"
10 set -e
11
12 ONLY=${ONLY:-"$*"}
13
14 # bug number for skipped test:
15 ALWAYS_EXCEPT=${ALWAYS_EXCEPT:-"$MMP_EXCEPT"}
16 # UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT!
17
18 SRCDIR=$(cd $(dirname $0); echo $PWD)
19 export PATH=$PWD/$SRCDIR:$SRCDIR:$SRCDIR/../utils:$PATH:/sbin
20
21 LUSTRE=${LUSTRE:-$(cd $(dirname $0)/..; echo $PWD)}
22 . $LUSTRE/tests/test-framework.sh
23 init_test_env $@
24 . ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh}
25 init_logging
26
27 require_dsh_mds || exit 0
28 require_dsh_ost || exit 0
29
30 # unmount and cleanup the Lustre filesystem
31 MMP_RESTORE_MOUNT=false
32 if is_mounted $MOUNT || is_mounted $MOUNT2; then
33     cleanupall
34     MMP_RESTORE_MOUNT=true
35 fi
36
37 SAVED_FAIL_ON_ERROR=$FAIL_ON_ERROR
38 FAIL_ON_ERROR=false
39
40 build_test_filter
41
42 # Get the failover facet.
43 get_failover_facet() {
44     local facet=$1
45     local failover_facet=${facet}failover
46
47     local host=$(facet_host $facet)
48     local failover_host=$(facet_host $failover_facet)
49
50     [ -z "$failover_host" -o "$host" = "$failover_host" ] && \
51         failover_facet=$facet
52
53     echo $failover_facet
54 }
55
56 # Initiate the variables for Lustre servers and targets.
57 init_vars() {
58     MMP_MDS=mds
59     MMP_MDS_FAILOVER=$(get_failover_facet $MMP_MDS)
60
61     MMP_MDSDEV=$MDSDEV
62
63     MMP_OSS=${MMP_OSS:-ost1}
64     MMP_OSS_FAILOVER=$(get_failover_facet $MMP_OSS)
65
66     local oss_num=$(echo $MMP_OSS | tr -d "ost")
67     MMP_OSTDEV=$(ostdevname $oss_num)
68 }
69
70 # Stop the MDS and OSS services on the primary or failover servers.
71 stop_services() {
72     local flavor=$1
73     shift
74     local opts="$@"
75     local mds_facet
76     local oss_facet
77
78     if [ "$flavor" = "failover" ]; then
79         mds_facet=$MMP_MDS_FAILOVER
80         oss_facet=$MMP_OSS_FAILOVER
81     else
82         mds_facet=$MMP_MDS
83         oss_facet=$MMP_OSS
84     fi
85
86     stop $mds_facet $opts || return ${PIPESTATUS[0]}
87     stop $oss_facet $opts || return ${PIPESTATUS[0]}
88 }
89
90 # Enable the MMP feature.
91 enable_mmp() {
92     local facet=$1
93     local device=$2
94
95     do_facet $facet "$TUNE2FS -O mmp $device"
96     return ${PIPESTATUS[0]}
97 }
98
99 # Disable the MMP feature.
100 disable_mmp() {
101     local facet=$1
102     local device=$2
103
104     do_facet $facet "$TUNE2FS -O ^mmp $device"
105     return ${PIPESTATUS[0]}
106 }
107
108 # Reset the MMP block (if any) back to the clean state.
109 reset_mmp_block() {
110     local facet=$1
111     local device=$2
112
113     do_facet $facet "$TUNE2FS -f -E clear-mmp $device"
114     return ${PIPESTATUS[0]}
115 }
116
117 # Check whether the MMP feature is enabled or not.
118 mmp_is_enabled() {
119     local facet=$1
120     local device=$2
121
122     do_facet $facet "$DUMPE2FS -h $device | grep mmp"
123     return ${PIPESTATUS[0]}
124 }
125
126 # Get MMP update interval (in seconds) from the Lustre server target.
127 get_mmp_update_interval() {
128     local facet=$1
129     local device=$2
130     local interval
131
132     interval=$(do_facet $facet "$DEBUGFS -c -R dump_mmp $device 2>/dev/null \
133                 | grep 'MMP Update Interval' | cut -d' ' -f4")
134     [ -z "$interval" ] && interval=1
135
136     echo $interval
137 }
138
139 # Get MMP check interval (in seconds) from the Lustre server target.
140 get_mmp_check_interval() {
141     local facet=$1
142     local device=$2
143     local interval
144
145     interval=$(do_facet $facet "$DEBUGFS -c -R dump_mmp $device 2>/dev/null \
146                 | grep 'MMP Check Interval' | cut -d' ' -f4")
147     [ -z "$interval" ] && interval=5
148
149     echo $interval
150 }
151
152 # Enable the MMP feature on the Lustre server targets.
153 mmp_init() {
154     init_vars
155
156     # The MMP feature is automatically enabled by mkfs.lustre for
157     # new file system at format time if failover is being used.
158     # Otherwise, the Lustre administrator has to manually enable
159     # this feature when the file system is unmounted.
160
161     if [ -z "$mdsfailover_HOST" ]; then
162         log "Failover is not used on MDS, enabling MMP manually..."
163         enable_mmp $MMP_MDS $MMP_MDSDEV || \
164             error "failed to enable MMP on $MMP_MDSDEV on $MMP_MDS"
165     fi
166
167     local var=${MMP_OSS}failover_HOST
168
169     if [ -z "${!var}" ]; then
170         log "Failover is not used on OSS, enabling MMP manually..."
171         enable_mmp $MMP_OSS $MMP_OSTDEV || \
172             error "failed to enable MMP on $MMP_OSTDEV on $MMP_OSS"
173     fi
174
175     # check whether the MMP feature is enabled or not
176     mmp_is_enabled $MMP_MDS $MMP_MDSDEV || \
177         error "MMP was not enabled on $MMP_MDSDEV on $MMP_MDS"
178
179     mmp_is_enabled $MMP_OSS $MMP_OSTDEV || \
180         error "MMP was not enabled on $MMP_OSTDEV on $MMP_OSS"
181 }
182
183 # Disable the MMP feature on the Lustre server targets
184 # which did not use failover.
185 mmp_fini() {
186
187     if [ -z "$mdsfailover_HOST" ]; then
188         log "Failover is not used on MDS, disabling MMP manually..."
189         disable_mmp $MMP_MDS $MMP_MDSDEV || \
190             error "failed to disable MMP on $MMP_MDSDEV on $MMP_MDS"
191         mmp_is_enabled $MMP_MDS $MMP_MDSDEV && \
192             error "MMP was not disabled on $MMP_MDSDEV on $MMP_MDS"
193     fi
194
195     local var=${MMP_OSS}failover_HOST
196
197     if [ -z "${!var}" ]; then
198         log "Failover is not used on OSS, disabling MMP manually..."
199         disable_mmp $MMP_OSS $MMP_OSTDEV || \
200             error "failed to disable MMP on $MMP_OSTDEV on $MMP_OSS"
201         mmp_is_enabled $MMP_OSS $MMP_OSTDEV && \
202             error "MMP was not disabled on $MMP_OSTDEV on $MMP_OSS"
203     fi
204
205     return 0
206 }
207
208 # Mount the shared target on the failover server after some interval it's
209 # mounted on the primary server.
210 mount_after_interval_sub() {
211     local interval=$1
212     shift
213     local device=$1
214     shift
215     local facet=$1
216     shift
217     local opts="$@"
218     local failover_facet=$(get_failover_facet $facet)
219
220     local mount_pid
221     local first_mount_rc=0
222     local second_mount_rc=0
223
224     log "Mounting $device on $facet..."
225     start $facet $device $opts &
226     mount_pid=$!
227
228     if [ $interval -ne 0 ]; then
229         log "sleep $interval..."
230         sleep $interval
231     fi
232
233     log "Mounting $device on $failover_facet..."
234     start $failover_facet $device $opts
235     second_mount_rc=${PIPESTATUS[0]}
236
237     wait $mount_pid
238     first_mount_rc=${PIPESTATUS[0]}
239
240     if [ $second_mount_rc -eq 0 -a $first_mount_rc -eq 0 ]; then
241         error_noexit "one mount delayed by mmp interval $interval should fail"
242         stop $facet || return ${PIPESTATUS[0]}
243         [ "$failover_facet" != "$facet" ] && stop $failover_facet || \
244             return ${PIPESTATUS[0]}
245         return 1
246     elif [ $second_mount_rc -ne 0 -a $first_mount_rc -ne 0 ]; then
247         error_noexit "failed to mount on the failover pair $facet,$failover_facet"
248         return $first_mount_rc
249     fi
250
251     return 0
252 }
253
254 mount_after_interval() {
255     local mdt_interval=$1
256     local ost_interval=$2
257     local rc=0
258
259     mount_after_interval_sub $mdt_interval $MMP_MDSDEV $MMP_MDS \
260         $MDS_MOUNT_OPTS || return ${PIPESTATUS[0]}
261
262     echo
263     mount_after_interval_sub $ost_interval $MMP_OSTDEV $MMP_OSS $OST_MOUNT_OPTS
264     rc=${PIPESTATUS[0]}
265     if [ $rc -ne 0 ]; then
266         stop $MMP_MDS
267         return $rc
268     fi
269
270     return 0
271 }
272
273 # Mount the shared target on the failover server
274 # during unmounting it on the primary server.
275 mount_during_unmount() {
276     local device=$1
277     shift
278     local facet=$1
279     shift
280     local mnt_opts="$@"
281     local failover_facet=$(get_failover_facet $facet)
282
283     local unmount_pid
284     local unmount_rc=0
285     local mount_rc=0
286
287     log "Mounting $device on $facet..."
288     start $facet $device $mnt_opts || return ${PIPESTATUS[0]}
289
290     stop $facet &
291     unmount_pid=$!
292
293     start $failover_facet $device $mnt_opts
294     mount_rc=${PIPESTATUS[0]}
295
296     wait $unmount_pid
297     unmount_rc=${PIPESTATUS[0]}
298
299     if [ $mount_rc -eq 0 ]; then
300         error_noexit "mount during unmount of the first filesystem should fail"
301         stop $failover_facet || return ${PIPESTATUS[0]}
302         return 1
303     fi
304
305     if [ $unmount_rc -ne 0 ]; then
306         error_noexit "unmount the $device on $facet should succeed"
307         return $unmount_rc
308     fi
309
310     return 0
311 }
312
313 # Mount the shared target on the failover server
314 # after clean unmounting it on the primary server.
315 mount_after_unmount() {
316     local device=$1
317     shift
318     local facet=$1
319     shift
320     local mnt_opts="$@"
321     local failover_facet=$(get_failover_facet $facet)
322
323     log "Mounting $device on $facet..."
324     start $facet $device $mnt_opts || return ${PIPESTATUS[0]}
325
326     log "Unmounting $device on $facet..."
327     stop $facet || return ${PIPESTATUS[0]}
328
329     log "Mounting $device on $failover_facet..."
330     start $failover_facet $device $mnt_opts || return ${PIPESTATUS[0]}
331
332     return 0
333 }
334
335 # Mount the shared target on the failover server after rebooting
336 # the primary server.
337 mount_after_reboot() {
338     local device=$1
339     shift
340     local facet=$1
341     shift
342     local mnt_opts="$@"
343     local failover_facet=$(get_failover_facet $facet)
344     local rc=0
345
346     log "Mounting $device on $facet..."
347     start $facet $device $mnt_opts || return ${PIPESTATUS[0]}
348
349     if [ "$FAILURE_MODE" = "HARD" ]; then
350         shutdown_facet $facet
351         reboot_facet $facet
352         wait_for_facet $facet
353     else
354         replay_barrier_nodf $facet
355     fi
356
357     log "Mounting $device on $failover_facet..."
358     start $failover_facet $device $mnt_opts
359     rc=${PIPESTATUS[0]}
360     if [ $rc -ne 0 ]; then
361         error_noexit "mount $device on $failover_facet should succeed"
362         stop $facet || return ${PIPESTATUS[0]}
363         return $rc
364     fi
365
366     return 0
367 }
368
369 # Run e2fsck on the Lustre server target.
370 run_e2fsck() {
371     local facet=$1
372     shift
373     local device=$1
374     shift
375     local opts="$@"
376
377     log "Running e2fsck on the device $device on $facet..."
378     do_facet $facet "$E2FSCK $opts $device"
379     return ${PIPESTATUS[0]}
380 }
381
382 # Check whether there are failover pairs for MDS and OSS servers.
383 check_failover_pair() {
384     [ "$MMP_MDS" = "$MMP_MDS_FAILOVER" -o "$MMP_OSS" = "$MMP_OSS_FAILOVER" ] \
385         && { skip_env "failover pair is needed" && return 1; }
386     return 0
387 }
388
389 mmp_init
390
391 # Test 1 - two mounts at the same time.
392 test_1() {
393     check_failover_pair || return 0
394
395     mount_after_interval 0 0 || return ${PIPESTATUS[0]}
396     stop_services primary || return ${PIPESTATUS[0]}
397 }
398 run_test 1 "two mounts at the same time"
399
400 # Test 2 - one mount delayed by mmp update interval.
401 test_2() {
402     check_failover_pair || return 0
403
404     local mdt_interval=$(get_mmp_update_interval $MMP_MDS $MMP_MDSDEV)
405     local ost_interval=$(get_mmp_update_interval $MMP_OSS $MMP_OSTDEV)
406
407     mount_after_interval $mdt_interval $ost_interval || return ${PIPESTATUS[0]}
408     stop_services primary || return ${PIPESTATUS[0]}
409 }
410 run_test 2 "one mount delayed by mmp update interval"
411
412 # Test 3 - one mount delayed by 2x mmp check interval.
413 test_3() {
414     check_failover_pair || return 0
415
416     local mdt_interval=$(get_mmp_check_interval $MMP_MDS $MMP_MDSDEV)
417     local ost_interval=$(get_mmp_check_interval $MMP_OSS $MMP_OSTDEV)
418
419     mdt_interval=$((2 * $mdt_interval + 1))
420     ost_interval=$((2 * $ost_interval + 1))
421
422     mount_after_interval $mdt_interval $ost_interval || return ${PIPESTATUS[0]}
423     stop_services primary || return ${PIPESTATUS[0]}
424 }
425 run_test 3 "one mount delayed by 2x mmp check interval"
426
427 # Test 4 - one mount delayed by > 2x mmp check interval.
428 test_4() {
429     check_failover_pair || return 0
430
431     local mdt_interval=$(get_mmp_check_interval $MMP_MDS $MMP_MDSDEV)
432     local ost_interval=$(get_mmp_check_interval $MMP_OSS $MMP_OSTDEV)
433
434     mdt_interval=$((4 * $mdt_interval))
435     ost_interval=$((4 * $ost_interval))
436
437     mount_after_interval $mdt_interval $ost_interval || return ${PIPESTATUS[0]}
438     stop_services primary || return ${PIPESTATUS[0]}
439 }
440 run_test 4 "one mount delayed by > 2x mmp check interval"
441
442 # Test 5 - mount during unmount of the first filesystem.
443 test_5() {
444     local rc=0
445     check_failover_pair || return 0
446
447     mount_during_unmount $MMP_MDSDEV $MMP_MDS $MDS_MOUNT_OPTS || \
448         return ${PIPESTATUS[0]}
449
450     echo
451     start $MMP_MDS $MMP_MDSDEV $MDS_MOUNT_OPTS || return ${PIPESTATUS[0]}
452     mount_during_unmount $MMP_OSTDEV $MMP_OSS $OST_MOUNT_OPTS
453     rc=${PIPESTATUS[0]}
454     if [ $rc -ne 0 ]; then
455         stop $MMP_MDS || return ${PIPESTATUS[0]}
456         return $rc
457     fi
458
459     stop $MMP_MDS || return ${PIPESTATUS[0]}
460 }
461 run_test 5 "mount during unmount of the first filesystem"
462
463 # Test 6 - mount after clean unmount.
464 test_6() {
465     local rc=0
466     check_failover_pair || return 0
467
468     mount_after_unmount $MMP_MDSDEV $MMP_MDS $MDS_MOUNT_OPTS || \
469         return ${PIPESTATUS[0]}
470
471     echo
472     mount_after_unmount $MMP_OSTDEV $MMP_OSS $OST_MOUNT_OPTS
473     rc=${PIPESTATUS[0]}
474     if [ $rc -ne 0 ]; then
475         stop $MMP_MDS_FAILOVER || return ${PIPESTATUS[0]}
476         return $rc
477     fi
478
479     stop_services failover || return ${PIPESTATUS[0]}
480 }
481 run_test 6 "mount after clean unmount"
482
483 # Test 7 - mount after reboot.
484 test_7() {
485     local rc=0
486     check_failover_pair || return 0
487
488     mount_after_reboot $MMP_MDSDEV $MMP_MDS $MDS_MOUNT_OPTS || \
489         return ${PIPESTATUS[0]}
490
491     echo
492     mount_after_reboot $MMP_OSTDEV $MMP_OSS $OST_MOUNT_OPTS
493     rc=${PIPESTATUS[0]}
494     if [ $rc -ne 0 ]; then
495         stop $MMP_MDS || return ${PIPESTATUS[0]}
496         stop $MMP_MDS_FAILOVER || return ${PIPESTATUS[0]}
497         return $rc
498     fi
499
500     stop_services failover || return ${PIPESTATUS[0]}
501     stop_services primary || return ${PIPESTATUS[0]}
502 }
503 run_test 7 "mount after reboot"
504
505 # Test 8 - mount during e2fsck (should never succeed).
506 test_8() {
507     local e2fsck_pid
508
509     run_e2fsck $MMP_MDS $MMP_MDSDEV "-fy" &
510     e2fsck_pid=$!
511     sleep 1
512
513     log "Mounting $MMP_MDSDEV on $MMP_MDS_FAILOVER..."
514     if start $MMP_MDS_FAILOVER $MMP_MDSDEV $MDS_MOUNT_OPTS; then
515         error_noexit "mount $MMP_MDSDEV on $MMP_MDS_FAILOVER should fail"
516         stop $MMP_MDS_FAILOVER || return ${PIPESTATUS[0]}
517         return 1
518     fi
519
520     wait $e2fsck_pid
521
522     echo
523     run_e2fsck $MMP_OSS $MMP_OSTDEV "-fy" &
524     e2fsck_pid=$!
525     sleep 1
526
527     log "Mounting $MMP_OSTDEV on $MMP_OSS_FAILOVER..."
528     if start $MMP_OSS_FAILOVER $MMP_OSTDEV $OST_MOUNT_OPTS; then
529         error_noexit "mount $MMP_OSTDEV on $MMP_OSS_FAILOVER should fail"
530         stop $MMP_OSS_FAILOVER || return ${PIPESTATUS[0]}
531         return 2
532     fi
533
534     wait $e2fsck_pid
535     return 0
536 }
537 run_test 8 "mount during e2fsck"
538
539 # Test 9 - mount after aborted e2fsck (should never succeed).
540 test_9() {
541     local e2fsck_pid
542     local mdt_mmp_check_interval
543     local ost_mmp_check_interval
544
545     start $MMP_MDS $MMP_MDSDEV $MDS_MOUNT_OPTS || return ${PIPESTATUS[0]}
546     if ! start $MMP_OSS $MMP_OSTDEV $OST_MOUNT_OPTS; then
547         local rc=${PIPESTATUS[0]}
548         stop $MMP_MDS || return ${PIPESTATUS[0]}
549         return $rc
550     fi
551     stop_services primary || return ${PIPESTATUS[0]}
552
553     mdt_mmp_check_interval=$(get_mmp_check_interval $MMP_MDS $MMP_MDSDEV)
554     run_e2fsck $MMP_MDS_FAILOVER $MMP_MDSDEV "-fy" &
555     e2fsck_pid=$!
556     sleep $((2 * $mdt_mmp_check_interval))
557     kill -s ABRT $e2fsck_pid
558
559     log "Mounting $MMP_MDSDEV on $MMP_MDS..."
560     if start $MMP_MDS $MMP_MDSDEV $MDS_MOUNT_OPTS; then
561         error_noexit "mount $MMP_MDSDEV on $MMP_MDS should fail"
562         stop $MMP_MDS || return ${PIPESTATUS[0]}
563         return 1
564     fi
565
566     reset_mmp_block $MMP_MDS $MMP_MDSDEV || return ${PIPESTATUS[0]}
567
568     echo
569     ost_mmp_check_interval=$(get_mmp_check_interval $MMP_OSS $MMP_OSTDEV)
570     run_e2fsck $MMP_OSS_FAILOVER $MMP_OSTDEV "-fy" &
571     e2fsck_pid=$!
572     sleep $((2 * $ost_mmp_check_interval))
573     kill -s ABRT $e2fsck_pid
574
575     log "Mounting $MMP_OSTDEV on $MMP_OSS..."
576     if start $MMP_OSS $MMP_OSTDEV $OST_MOUNT_OPTS; then
577         error_noexit "mount $MMP_OSTDEV on $MMP_OSS should fail"
578         stop $MMP_OSS || return ${PIPESTATUS[0]}
579         return 2
580     fi
581
582     reset_mmp_block $MMP_OSS $MMP_OSTDEV || return ${PIPESTATUS[0]}
583     return 0
584 }
585 run_test 9 "mount after aborted e2fsck"
586
587 # Test 10 - e2fsck with mounted filesystem.
588 test_10() {
589     local rc=0
590
591     log "Mounting $MMP_MDSDEV on $MMP_MDS..."
592     start $MMP_MDS $MMP_MDSDEV $MDS_MOUNT_OPTS || return ${PIPESTATUS[0]}
593
594     run_e2fsck $MMP_MDS_FAILOVER $MMP_MDSDEV "-fn"
595     rc=${PIPESTATUS[0]}
596
597     # e2fsck is always called with -n, i.e.
598     # 0 (No errors) and 4 (File system errors left uncorrected) are the only acceptable
599     # e2fsck exit codes in case
600     if [ $rc -ne 0 ] && [ $rc -ne 4 ]; then
601         error_noexit "e2fsck $MMP_MDSDEV on $MMP_MDS_FAILOVER returned $rc"
602         stop $MMP_MDS || return ${PIPESTATUS[0]}
603         return $rc
604     fi
605
606     log "Mounting $MMP_OSTDEV on $MMP_OSS..."
607     start $MMP_OSS $MMP_OSTDEV $OST_MOUNT_OPTS
608     rc=${PIPESTATUS[0]}
609     if [ $rc -ne 0 ]; then
610         stop $MMP_MDS || return ${PIPESTATUS[0]}
611         return $rc
612     fi
613
614     run_e2fsck $MMP_OSS_FAILOVER $MMP_OSTDEV "-fn"
615     rc=${PIPESTATUS[0]}
616     if [ $rc -ne 0 ] && [ $rc -ne 4 ]; then
617         error_noexit "e2fsck $MMP_OSTDEV on $MMP_OSS_FAILOVER returned $rc"
618     fi
619
620     stop_services primary || return ${PIPESTATUS[0]}
621     return 0
622 }
623 run_test 10 "e2fsck with mounted filesystem"
624
625 mmp_fini
626 FAIL_ON_ERROR=$SAVED_FAIL_ON_ERROR
627
628 complete $(basename $0) $SECONDS
629 $MMP_RESTORE_MOUNT && setupall
630 exit_status