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