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