Whamcloud - gitweb
b=14148
[fs/lustre-release.git] / lustre / tests / test-framework.sh
1 #!/bin/bash
2 # vim:expandtab:shiftwidth=4:softtabstop=4:tabstop=4:
3
4 trap 'print_summary && echo "test-framework exiting on error"' ERR
5 set -e
6 #set -x
7
8
9 export REFORMAT=${REFORMAT:-""}
10 export VERBOSE=false
11 export GMNALNID=${GMNALNID:-/usr/sbin/gmlndnid}
12 export CATASTROPHE=${CATASTROPHE:-/proc/sys/lnet/catastrophe}
13 #export PDSH="pdsh -S -Rssh -w"
14
15 # eg, assert_env LUSTRE MDSNODES OSTNODES CLIENTS
16 assert_env() {
17     local failed=""
18     for name in $@; do
19         if [ -z "${!name}" ]; then
20             echo "$0: $name must be set"
21             failed=1
22         fi
23     done
24     [ $failed ] && exit 1 || true
25 }
26
27 usage() {
28     echo "usage: $0 [-r] [-f cfgfile]"
29     echo "       -r: reformat"
30
31     exit
32 }
33
34 print_summary () {
35     [ -n "$ONLY" ] && echo "WARNING: ONLY is set to ${ONLY}."
36     local form="%-13s %-17s %s\n"
37     echo "$(printf "$form" "status" "script" "skipped tests")"
38     echo "------------------------------------------------------------------------------------"
39     for O in $TESTSUITE_LIST; do
40         local skipped=""
41         local o=$(echo $O | tr "[:upper:]" "[:lower:]")
42         o=${o//_/-}
43         o=${o//tyn/tyN}
44         local log=${TMP}/${o}.log 
45         [ -f $log ] && skipped=$(cat $log | awk '{ printf " %s", $3 }' | sed 's/test_//g')
46         [ "${!O}" = "done" ] && \
47             echo "$(printf "$form" "Done" "$O" "$skipped")"
48     done
49
50     for O in $TESTSUITE_LIST; do
51         [ "${!O}" = "no" ] && \
52             echo "$(printf "$form" "Skipped" "$O" "")"
53     done
54
55     for O in $TESTSUITE_LIST; do
56         [ "${!O}" = "done" -o "${!O}" = "no" ] || \
57             echo "$(printf "$form" "UNFINISHED" "$O" "")"
58     done
59 }
60
61 init_test_env() {
62     export LUSTRE=`absolute_path $LUSTRE`
63     export TESTSUITE=`basename $0 .sh`
64     export LTESTDIR=${LTESTDIR:-$LUSTRE/../ltest}
65
66     [ -d /r ] && export ROOT=${ROOT:-/r}
67     export TMP=${TMP:-$ROOT/tmp}
68     export TESTSUITELOG=${TMP}/${TESTSUITE}.log
69
70     export PATH=:$PATH:$LUSTRE/utils:$LUSTRE/tests
71     export LCTL=${LCTL:-"$LUSTRE/utils/lctl"}
72     export LFS=${LFS:-"$LUSTRE/utils/lfs"}
73     [ ! -f "$LCTL" ] && export LCTL=$(which lctl) 
74     export LFS=${LFS:-"$LUSTRE/utils/lfs"}
75     [ ! -f "$LFS" ] && export LFS=$(which lfs) 
76     export MKFS=${MKFS:-"$LUSTRE/utils/mkfs.lustre"}
77     [ ! -f "$MKFS" ] && export MKFS=$(which mkfs.lustre) 
78     export TUNEFS=${TUNEFS:-"$LUSTRE/utils/tunefs.lustre"}
79     [ ! -f "$TUNEFS" ] && export TUNEFS=$(which tunefs.lustre) 
80     export CHECKSTAT="${CHECKSTAT:-"checkstat -v"} "
81     export FSYTPE=${FSTYPE:-"ldiskfs"}
82     export NAME=${NAME:-local}
83     export LPROC=/proc/fs/lustre
84     export DIR2
85
86     if [ "$ACCEPTOR_PORT" ]; then
87         export PORT_OPT="--port $ACCEPTOR_PORT"
88     fi
89
90     # Paths on remote nodes, if different 
91     export RLUSTRE=${RLUSTRE:-$LUSTRE}
92     export RPWD=${RPWD:-$PWD}
93     export I_MOUNTED=${I_MOUNTED:-"no"}
94
95     # command line
96     
97     while getopts "rvf:" opt $*; do 
98         case $opt in
99             f) CONFIG=$OPTARG;;
100             r) REFORMAT=--reformat;;
101             v) VERBOSE=true;;
102             \?) usage;;
103         esac
104     done
105
106     shift $((OPTIND - 1))
107     ONLY=${ONLY:-$*}
108
109     [ "$TESTSUITELOG" ] && rm -f $TESTSUITELOG || true
110
111 }
112
113 case `uname -r` in
114 2.4.*) EXT=".o"; USE_QUOTA=no; [ ! "$CLIENTONLY" ] && FSTYPE=ext3;;
115     *) EXT=".ko"; USE_QUOTA=yes;;
116 esac
117
118 load_module() {
119     module=$1
120     shift
121     BASE=`basename $module $EXT`
122     lsmod | grep -q ${BASE} || \
123       if [ -f ${LUSTRE}/${module}${EXT} ]; then
124         insmod ${LUSTRE}/${module}${EXT} $@
125     else
126         # must be testing a "make install" or "rpm" installation
127         modprobe $BASE $@
128     fi
129 }
130
131 load_modules() {
132     if [ -n "$MODPROBE" ]; then
133         # use modprobe
134     return 0
135     fi
136     if [ "$HAVE_MODULES" = true ]; then
137     # we already loaded
138         return 0
139     fi
140     HAVE_MODULES=true
141
142     echo Loading modules from $LUSTRE
143     load_module ../lnet/libcfs/libcfs
144     [ -f /etc/modprobe.conf ] && MODPROBECONF=/etc/modprobe.conf
145     [ -f /etc/modprobe.d/Lustre ] && MODPROBECONF=/etc/modprobe.d/Lustre
146     [ -z "$LNETOPTS" -a -n "$MODPROBECONF" ] && \
147         LNETOPTS=$(awk '/^options lnet/ { print $0}' $MODPROBECONF | sed 's/^options lnet //g')
148     echo "lnet options: '$LNETOPTS'"
149     # note that insmod will ignore anything in modprobe.conf
150     load_module ../lnet/lnet/lnet $LNETOPTS
151     LNETLND=${LNETLND:-"socklnd/ksocklnd"}
152     load_module ../lnet/klnds/$LNETLND
153     load_module lvfs/lvfs
154     load_module obdclass/obdclass
155     load_module ptlrpc/ptlrpc
156     [ "$USE_QUOTA" = "yes" ] && load_module quota/lquota
157     load_module mdc/mdc
158     load_module osc/osc
159     load_module lov/lov
160     load_module mgc/mgc
161     if [ -z "$CLIENTONLY" ]; then
162         load_module mgs/mgs
163         load_module mds/mds
164         [ "$FSTYPE" = "ldiskfs" ] && load_module ../ldiskfs/ldiskfs/ldiskfs
165         load_module lvfs/fsfilt_$FSTYPE
166         load_module ost/ost
167         load_module obdfilter/obdfilter
168     fi
169
170     load_module llite/lustre
171     load_module llite/llite_lloop
172     rm -f $TMP/ogdb-`hostname`
173     OGDB=$TMP
174     [ -d /r ] && OGDB="/r/tmp"
175     $LCTL modules > $OGDB/ogdb-`hostname`
176     # 'mount' doesn't look in $PATH, just sbin
177     [ -f $LUSTRE/utils/mount.lustre ] && cp $LUSTRE/utils/mount.lustre /sbin/. || true
178 }
179
180 RMMOD=rmmod
181 if [ `uname -r | cut -c 3` -eq 4 ]; then
182     RMMOD="modprobe -r"
183 fi
184
185 wait_for_lnet() {
186     local UNLOADED=0
187     local WAIT=0
188     local MAX=60
189     MODULES=$($LCTL modules | awk '{ print $2 }')
190     while [ -n "$MODULES" ]; do
191     sleep 5
192     $RMMOD $MODULES >/dev/null 2>&1 || true
193     MODULES=$($LCTL modules | awk '{ print $2 }')
194         if [ -z "$MODULES" ]; then
195         return 0
196         else
197             WAIT=$((WAIT + 5))
198             echo "waiting, $((MAX - WAIT)) secs left"
199         fi
200         if [ $WAIT -eq $MAX ]; then
201             echo "LNET modules $MODULES will not unload"
202         lsmod
203             return 3
204         fi
205     done
206 }
207
208 unload_modules() {
209     wait_exit_ST client # bug 12845
210
211     lsmod | grep lnet > /dev/null && $LCTL dl && $LCTL dk $TMP/debug
212     local MODULES=$($LCTL modules | awk '{ print $2 }')
213     $RMMOD $MODULES > /dev/null 2>&1 || true
214      # do it again, in case we tried to unload ksocklnd too early
215     MODULES=$($LCTL modules | awk '{ print $2 }')
216     [ -n "$MODULES" ] && $RMMOD $MODULES > /dev/null 2>&1 || true
217     MODULES=$($LCTL modules | awk '{ print $2 }')
218     if [ -n "$MODULES" ]; then
219     echo "Modules still loaded: "
220     echo $MODULES 
221     if [ -e $LPROC ]; then
222         echo "Lustre still loaded"
223         cat $LPROC/devices || true
224         lsmod
225         return 2
226     else
227         echo "Lustre stopped but LNET is still loaded, waiting..."
228         wait_for_lnet || return 3
229     fi
230     fi
231     HAVE_MODULES=false
232
233     LEAK_LUSTRE=$(dmesg | tail -n 30 | grep "obd mem.*leaked" || true)
234     LEAK_PORTALS=$(dmesg | tail -n 20 | grep "Portals memory leaked" || true)
235     if [ "$LEAK_LUSTRE" -o "$LEAK_PORTALS" ]; then
236         echo "$LEAK_LUSTRE" 1>&2
237         echo "$LEAK_PORTALS" 1>&2
238         mv $TMP/debug $TMP/debug-leak.`date +%s` || true
239         echo "Memory leaks detected"
240         [ -n "$IGNORE_LEAK" ] && echo "ignoring leaks" && return 0
241         return 254
242     fi
243     echo "modules unloaded."
244     return 0
245 }
246
247 # Facet functions
248 # start facet device options 
249 start() {
250     facet=$1
251     shift
252     device=$1
253     shift
254     echo "Starting ${facet}: $@ ${device} ${MOUNT%/*}/${facet}"
255     do_facet ${facet} mkdir -p ${MOUNT%/*}/${facet}
256     do_facet ${facet} mount -t lustre $@ ${device} ${MOUNT%/*}/${facet} 
257     RC=${PIPESTATUS[0]}
258     if [ $RC -ne 0 ]; then
259         echo "mount -t lustre $@ ${device} ${MOUNT%/*}/${facet}" 
260         echo "Start of ${device} on ${facet} failed ${RC}"
261     else 
262         do_facet ${facet} "sysctl -w lnet.debug=$PTLDEBUG; \
263         sysctl -w lnet.subsystem_debug=${SUBSYSTEM# }; \
264         sysctl -w lnet.debug_mb=${DEBUG_SIZE}"
265
266         do_facet ${facet} sync
267         label=$(do_facet ${facet} "e2label ${device}")
268         [ -z "$label" ] && echo no label for ${device} && exit 1
269         eval export ${facet}_svc=${label}
270         eval export ${facet}_dev=${device}
271         eval export ${facet}_opt=\"$@\"
272         echo Started ${label}
273     fi
274     return $RC
275 }
276
277 stop() {
278     local running
279     facet=$1
280     shift
281     HOST=`facet_active_host $facet`
282     [ -z $HOST ] && echo stop: no host for $facet && return 0
283
284     running=$(do_facet ${facet} "grep -c ${MOUNT%/*}/${facet}' ' /proc/mounts") || true
285     if [ ${running} -ne 0 ]; then
286         echo "Stopping ${MOUNT%/*}/${facet} (opts:$@)"
287         do_facet ${facet} umount -d $@ ${MOUNT%/*}/${facet}
288     fi
289
290     # umount should block, but we should wait for unrelated obd's
291     # like the MGS or MGC to also stop.
292
293     wait_exit_ST ${facet}
294 }
295
296 zconf_mount() {
297     local OPTIONS
298     local client=$1
299     local mnt=$2
300     # Only supply -o to mount if we have options
301     if [ -n "$MOUNTOPT" ]; then
302         OPTIONS="-o $MOUNTOPT"
303     fi
304     local device=$MGSNID:/$FSNAME
305     if [ -z "$mnt" -o -z "$FSNAME" ]; then
306         echo Bad zconf mount command: opt=$OPTIONS dev=$device mnt=$mnt
307         exit 1
308     fi
309
310     echo "Starting client: $OPTIONS $device $mnt" 
311     do_node $client mkdir -p $mnt
312     do_node $client mount -t lustre $OPTIONS $device $mnt || return 1
313
314     do_node $client "sysctl -w lnet.debug=$PTLDEBUG;
315         sysctl -w lnet.subsystem_debug=${SUBSYSTEM# };
316         sysctl -w lnet.debug_mb=${DEBUG_SIZE}"
317     [ -d /r ] && $LCTL modules > /r/tmp/ogdb-`hostname`
318     return 0
319 }
320
321 zconf_umount() {
322     client=$1
323     mnt=$2
324     [ "$3" ] && force=-f
325     local running=$(do_node $client "grep -c $mnt' ' /proc/mounts") || true
326     if [ $running -ne 0 ]; then
327         echo "Stopping client $mnt (opts:$force)"
328         do_node $client umount $force $mnt
329     fi
330 }
331
332 shutdown_facet() {
333     facet=$1
334     if [ "$FAILURE_MODE" = HARD ]; then
335         $POWER_DOWN `facet_active_host $facet`
336         sleep 2 
337     elif [ "$FAILURE_MODE" = SOFT ]; then
338         stop $facet
339     fi
340 }
341
342 reboot_facet() {
343     facet=$1
344     if [ "$FAILURE_MODE" = HARD ]; then
345         $POWER_UP `facet_active_host $facet`
346     else
347         sleep 10
348     fi
349 }
350
351 # verify that lustre actually cleaned up properly
352 cleanup_check() {
353     [ -f $CATASTROPHE ] && [ `cat $CATASTROPHE` -ne 0 ] && \
354         error "LBUG/LASSERT detected"
355     BUSY=`dmesg | grep -i destruct || true`
356     if [ "$BUSY" ]; then
357         echo "$BUSY" 1>&2
358         [ -e $TMP/debug ] && mv $TMP/debug $TMP/debug-busy.`date +%s`
359         exit 205
360     fi
361     LEAK_LUSTRE=`dmesg | tail -n 30 | grep "obd mem.*leaked" || true`
362     LEAK_PORTALS=`dmesg | tail -n 20 | grep "Portals memory leaked" || true`
363     if [ "$LEAK_LUSTRE" -o "$LEAK_PORTALS" ]; then
364         echo "$0: $LEAK_LUSTRE" 1>&2
365         echo "$0: $LEAK_PORTALS" 1>&2
366         echo "$0: Memory leak(s) detected..." 1>&2
367         mv $TMP/debug $TMP/debug-leak.`date +%s`
368         exit 204
369     fi
370
371     [ "`lctl dl 2> /dev/null | wc -l`" -gt 0 ] && lctl dl && \
372         echo "$0: lustre didn't clean up..." 1>&2 && return 202 || true
373
374     if [ "`/sbin/lsmod 2>&1 | egrep 'lnet|libcfs'`" ]; then
375         echo "$0: modules still loaded..." 1>&2
376         /sbin/lsmod 1>&2
377         return 203
378     fi
379     return 0
380 }
381
382 wait_delete_completed () {
383     local TOTALPREV=`awk 'BEGIN{total=0}; {total+=$1}; END{print total}' \
384             $LPROC/osc/*/kbytesavail`
385
386     local WAIT=0
387     local MAX_WAIT=20
388     while [ "$WAIT" -ne "$MAX_WAIT" ]; do
389         sleep 1
390         TOTAL=`awk 'BEGIN{total=0}; {total+=$1}; END{print total}' \
391             $LPROC/osc/*/kbytesavail`
392         [ "$TOTAL" -eq "$TOTALPREV" ] && break
393         echo "Waiting delete completed ... prev: $TOTALPREV current: $TOTAL "
394         TOTALPREV=$TOTAL
395         WAIT=$(( WAIT + 1))
396     done
397     echo "Delete completed."
398 }
399
400 wait_for_host() {
401     HOST=$1
402     check_network "$HOST" 900
403     while ! do_node $HOST "ls -d $LUSTRE " > /dev/null; do sleep 5; done
404 }
405
406 wait_for() {
407     facet=$1
408     HOST=`facet_active_host $facet`
409     wait_for_host $HOST
410 }
411
412 wait_mds_recovery_done () {
413     local timeout=`do_facet mds cat /proc/sys/lustre/timeout`
414 #define OBD_RECOVERY_TIMEOUT (obd_timeout * 5 / 2)
415 # as we are in process of changing obd_timeout in different ways
416 # let's set MAX longer than that
417     MAX=$(( timeout * 4 ))
418     WAIT=0
419     while [ $WAIT -lt $MAX ]; do
420         STATUS=`do_facet mds grep status /proc/fs/lustre/mds/*-MDT*/recovery_status`
421         echo $STATUS | grep COMPLETE && return 0
422         sleep 5
423         WAIT=$((WAIT + 5))
424         echo "Waiting $(($MAX - $WAIT)) secs for MDS recovery done"
425     done
426     echo "MDS recovery not done in $MAX sec"
427     return 1            
428 }
429
430 wait_exit_ST () {
431     local facet=$1
432
433     local WAIT=0
434     local INTERVAL=1
435     # conf-sanity 31 takes a long time cleanup
436     while [ $WAIT -lt 300 ]; do
437         running=$(do_facet ${facet} "[ -e $LPROC ] && grep ST' ' $LPROC/devices") || true
438         [ -z "${running}" ] && return 0
439         echo "waited $WAIT for${running}"
440         [ $INTERVAL -lt 64 ] && INTERVAL=$((INTERVAL + INTERVAL))
441         sleep $INTERVAL
442         WAIT=$((WAIT + INTERVAL))
443     done
444     echo "service didn't stop after $WAIT seconds.  Still running:"
445     echo ${running}
446     return 1
447 }
448
449 client_df() {
450     # not every config has many clients
451     if [ -n "$CLIENTS" ]; then
452         $PDSH $CLIENTS "df $MOUNT" > /dev/null
453     else
454         df $MOUNT > /dev/null
455     fi
456 }
457
458 client_reconnect() {
459     uname -n >> $MOUNT/recon
460     if [ ! -z "$CLIENTS" ]; then
461         $PDSH $CLIENTS "df $MOUNT; uname -n >> $MOUNT/recon" > /dev/null
462     fi
463     echo Connected clients:
464     cat $MOUNT/recon
465     ls -l $MOUNT/recon > /dev/null
466     rm $MOUNT/recon
467 }
468
469 facet_failover() {
470     facet=$1
471     echo "Failing $facet on node `facet_active_host $facet`"
472     shutdown_facet $facet
473     reboot_facet $facet
474     client_df &
475     DFPID=$!
476     echo "df pid is $DFPID"
477     change_active $facet
478     TO=`facet_active_host $facet`
479     echo "Failover $facet to $TO"
480     wait_for $facet
481     local dev=${facet}_dev
482     local opt=${facet}_opt
483     start $facet ${!dev} ${!opt} || error "Restart of $facet failed"
484 }
485
486 obd_name() {
487     local facet=$1
488 }
489
490 replay_barrier() {
491     local facet=$1
492     do_facet $facet sync
493     df $MOUNT
494     local svc=${facet}_svc
495     do_facet $facet $LCTL --device %${!svc} readonly
496     do_facet $facet $LCTL --device %${!svc} notransno
497     do_facet $facet $LCTL mark "$facet REPLAY BARRIER on ${!svc}"
498     $LCTL mark "local REPLAY BARRIER on ${!svc}"
499 }
500
501 replay_barrier_nodf() {
502     local facet=$1    echo running=${running}
503     do_facet $facet sync
504     local svc=${facet}_svc
505     echo Replay barrier on ${!svc}
506     do_facet $facet $LCTL --device %${!svc} readonly
507     do_facet $facet $LCTL --device %${!svc} notransno
508     do_facet $facet $LCTL mark "$facet REPLAY BARRIER on ${!svc}"
509     $LCTL mark "local REPLAY BARRIER on ${!svc}"
510 }
511
512 mds_evict_client() {
513     UUID=`cat /proc/fs/lustre/mdc/${mds_svc}-mdc-*/uuid`
514     do_facet mds "echo $UUID > /proc/fs/lustre/mds/${mds_svc}/evict_client"
515 }
516
517 ost_evict_client() {
518     UUID=`cat /proc/fs/lustre/osc/${ost1_svc}-osc-*/uuid`
519     do_facet ost1 "echo $UUID > /proc/fs/lustre/obdfilter/${ost1_svc}/evict_client"
520 }
521
522 fail() {
523     facet_failover $* || error "failover: $?"
524     df $MOUNT || error "post-failover df: $?"
525 }
526
527 fail_nodf() {
528     local facet=$1
529     facet_failover $facet
530 }
531
532 fail_abort() {
533     local facet=$1
534     stop $facet
535     change_active $facet
536     local svc=${facet}_svc
537     local dev=${facet}_dev
538     local opt=${facet}_opt
539     start $facet ${!dev} ${!opt}
540     do_facet $facet lctl --device %${!svc} abort_recovery
541     df $MOUNT || echo "first df failed: $?"
542     sleep 1
543     df $MOUNT || error "post-failover df: $?"
544 }
545
546 do_lmc() {
547     echo There is no lmc.  This is mountconf, baby.
548     exit 1
549 }
550
551 h2gm () {
552     if [ "$1" = "client" -o "$1" = "'*'" ]; then echo \'*\'; else
553         ID=`$PDSH $1 $GMNALNID -l | cut -d\  -f2`
554         echo $ID"@gm"
555     fi
556 }
557
558 h2ptl() {
559    if [ "$1" = "client" -o "$1" = "'*'" ]; then echo \'*\'; else
560        ID=`xtprocadmin -n $1 2>/dev/null | egrep -v 'NID' | awk '{print $1}'`
561        if [ -z "$ID" ]; then
562            echo "Could not get a ptl id for $1..."
563            exit 1
564        fi
565        echo $ID"@ptl"
566    fi
567 }
568 declare -fx h2ptl
569
570 h2tcp() {
571     if [ "$1" = "client" -o "$1" = "'*'" ]; then echo \'*\'; else
572         echo $1"@tcp" 
573     fi
574 }
575 declare -fx h2tcp
576
577 h2elan() {
578     if [ "$1" = "client" -o "$1" = "'*'" ]; then echo \'*\'; else
579         if type __h2elan >/dev/null 2>&1; then
580             ID=$(__h2elan $1)
581         else
582             ID=`echo $1 | sed 's/[^0-9]*//g'`
583         fi
584         echo $ID"@elan"
585     fi
586 }
587 declare -fx h2elan
588
589 h2openib() {
590     if [ "$1" = "client" -o "$1" = "'*'" ]; then echo \'*\'; else
591         ID=`echo $1 | sed 's/[^0-9]*//g'`
592         echo $ID"@openib"
593     fi
594 }
595 declare -fx h2openib
596
597 facet_host() {
598     local facet=$1
599     varname=${facet}_HOST
600     if [ -z "${!varname}" ]; then
601         if [ "${facet:0:3}" == "ost" ]; then
602             eval ${facet}_HOST=${ost_HOST}
603         fi
604     fi
605     echo -n ${!varname}
606 }
607
608 facet_active() {
609     local facet=$1
610     local activevar=${facet}active
611
612     if [ -f ./${facet}active ] ; then
613         source ./${facet}active
614     fi
615
616     active=${!activevar}
617     if [ -z "$active" ] ; then 
618         echo -n ${facet}
619     else
620         echo -n ${active}
621     fi
622 }
623
624 facet_active_host() {
625     local facet=$1
626     local active=`facet_active $facet`
627     if [ "$facet" == client ]; then
628         hostname
629     else
630         echo `facet_host $active`
631     fi
632 }
633
634 change_active() {
635     local facet=$1
636     failover=${facet}failover 
637     host=`facet_host $failover`
638     [ -z "$host" ] && return
639     curactive=`facet_active $facet`
640     if [ -z "${curactive}" -o "$curactive" == "$failover" ] ; then
641         eval export ${facet}active=$facet
642     else
643         eval export ${facet}active=$failover
644     fi
645     # save the active host for this facet
646     activevar=${facet}active
647     echo "$activevar=${!activevar}" > ./$activevar
648 }
649
650 do_node() {
651     HOST=$1
652     shift
653     local myPDSH=$PDSH
654     if [ "$HOST" = "$(hostname)" ]; then
655         myPDSH="no_dsh"
656     fi
657     if $VERBOSE; then
658         echo "CMD: $HOST $@" >&2
659         $myPDSH $HOST $LCTL mark "$@" > /dev/null 2>&1 || :
660     fi
661     $myPDSH $HOST "(PATH=\$PATH:$RLUSTRE/utils:$RLUSTRE/tests:/sbin:/usr/sbin; cd $RPWD; sh -c \"$@\")" | sed "s/^${HOST}: //"
662     return ${PIPESTATUS[0]}
663 }
664
665 do_facet() {
666     facet=$1
667     shift
668     HOST=`facet_active_host $facet`
669     [ -z $HOST ] && echo No host defined for facet ${facet} && exit 1
670     do_node $HOST "$@"
671 }
672
673 add() {
674     local facet=$1
675     shift
676     # make sure its not already running
677     stop ${facet} -f
678     rm -f ${facet}active
679     do_facet ${facet} $MKFS $*
680 }
681
682 ostdevname() {
683     num=$1
684     DEVNAME=OSTDEV$num
685     #if $OSTDEVn isn't defined, default is $OSTDEVBASE + num
686     eval DEVPTR=${!DEVNAME:=${OSTDEVBASE}${num}}
687     echo -n $DEVPTR
688 }
689
690 ########
691 ## MountConf setup
692
693 stopall() {
694     # make sure we are using the primary server, so test-framework will
695     # be able to clean up properly.
696     activemds=`facet_active mds`
697     if [ $activemds != "mds" ]; then
698         fail mds
699     fi
700     
701     # assume client mount is local 
702     grep " $MOUNT " /proc/mounts && zconf_umount `hostname` $MOUNT $*
703     grep " $MOUNT2 " /proc/mounts && zconf_umount `hostname` $MOUNT2 $*
704     [ "$CLIENTONLY" ] && return
705     stop mds -f
706     for num in `seq $OSTCOUNT`; do
707         stop ost$num -f
708     done
709     return 0
710 }
711
712 cleanupall() {
713     stopall $*
714     unload_modules
715 }
716
717 formatall() {
718     [ "$FSTYPE" ] && FSTYPE_OPT="--backfstype $FSTYPE"
719
720     stopall
721     # We need ldiskfs here, may as well load them all
722     load_modules
723     [ "$CLIENTONLY" ] && return
724     echo Formatting mds, osts
725     if $VERBOSE; then
726         add mds $MDS_MKFS_OPTS $FSTYPE_OPT --reformat $MDSDEV || exit 10
727     else
728         add mds $MDS_MKFS_OPTS $FSTYPE_OPT --reformat $MDSDEV > /dev/null || exit 10
729     fi
730
731     for num in `seq $OSTCOUNT`; do
732         if $VERBOSE; then
733             add ost$num $OST_MKFS_OPTS $FSTYPE_OPT --reformat `ostdevname $num` || exit 10
734         else
735             add ost$num $OST_MKFS_OPTS $FSTYPE_OPT --reformat `ostdevname $num` > /dev/null || exit 10
736         fi
737     done
738 }
739
740 mount_client() {
741     grep " $1 " /proc/mounts || zconf_mount `hostname` $*
742 }
743
744 setupall() {
745     load_modules
746     if [ -z "$CLIENTONLY" ]; then
747         echo Setup mdt, osts
748         echo $REFORMAT | grep -q "reformat" \
749             || do_facet mds "$TUNEFS --writeconf $MDSDEV"
750         start mds $MDSDEV $MDS_MOUNT_OPTS
751         for num in `seq $OSTCOUNT`; do
752             DEVNAME=`ostdevname $num`
753             start ost$num $DEVNAME $OST_MOUNT_OPTS
754         done
755     fi
756     [ "$DAEMONFILE" ] && $LCTL debug_daemon start $DAEMONFILE $DAEMONSIZE
757     mount_client $MOUNT
758     if [ "$MOUNT_2" ]; then
759         mount_client $MOUNT2
760     fi
761     sleep 5
762 }
763
764 mounted_lustre_filesystems() {
765         awk '($3 ~ "lustre" && $1 ~ ":") { print $2 }' /proc/mounts
766 }
767
768 check_and_setup_lustre() {
769     MOUNTED="`mounted_lustre_filesystems`"
770     if [ -z "$MOUNTED" ]; then
771         [ "$REFORMAT" ] && formatall
772         setupall
773         MOUNTED="`mounted_lustre_filesystems`"
774         [ -z "$MOUNTED" ] && error "NAME=$NAME not mounted"
775         export I_MOUNTED=yes
776     fi
777     if [ "$ONLY" == "setup" ]; then
778         exit 0
779     fi
780 }
781
782 cleanup_and_setup_lustre() {
783     if [ "$ONLY" == "cleanup" -o "`mount | grep $MOUNT`" ]; then
784         sysctl -w lnet.debug=0 || true
785         cleanupall
786         if [ "$ONLY" == "cleanup" ]; then 
787             exit 0
788         fi
789     fi
790     check_and_setup_lustre
791 }
792
793 check_and_cleanup_lustre() {
794     if [ "`mount | grep $MOUNT`" ]; then
795         rm -f $DIR/${TESTSUITE}/[Rdfs][0-9]*
796     fi
797     if [ "$I_MOUNTED" = "yes" ]; then
798         cleanupall -f || error "cleanup failed"
799     fi
800     unset I_MOUNTED
801 }
802
803 ####### 
804 # General functions
805
806 check_network() {
807     local NETWORK=0
808     local WAIT=0
809     local MAX=$2
810     while [ $NETWORK -eq 0 ]; do
811         ping -c 1 -w 3 $1 > /dev/null
812         if [ $? -eq 0 ]; then
813             NETWORK=1
814         else
815             WAIT=$((WAIT + 5))
816             echo "waiting for $1, $((MAX - WAIT)) secs left"
817             sleep 5
818         fi
819         if [ $WAIT -gt $MAX ]; then
820             echo "Network not available"
821             exit 1
822         fi
823     done
824 }
825 check_port() {
826     while( !($DSH2 $1 "netstat -tna | grep -q $2") ) ; do
827         sleep 9
828     done
829 }
830
831 no_dsh() {
832     shift
833     eval $@
834 }
835
836 comma_list() {
837     # the sed converts spaces to commas, but leaves the last space
838     # alone, so the line doesn't end with a comma.
839     echo "$*" | tr -s " " "\n" | sort -b -u | tr "\n" " " | sed 's/ \([^$]\)/,\1/g'
840 }
841
842 absolute_path() {
843     (cd `dirname $1`; echo $PWD/`basename $1`)
844 }
845
846 ##################################
847 # OBD_FAIL funcs
848
849 drop_request() {
850 # OBD_FAIL_MDS_ALL_REQUEST_NET
851     RC=0
852     do_facet mds sysctl -w lustre.fail_loc=0x123
853     do_facet client "$1" || RC=$?
854     do_facet mds sysctl -w lustre.fail_loc=0
855     return $RC
856 }
857
858 drop_reply() {
859 # OBD_FAIL_MDS_ALL_REPLY_NET
860     RC=0
861     do_facet mds sysctl -w lustre.fail_loc=0x122
862     do_facet client "$@" || RC=$?
863     do_facet mds sysctl -w lustre.fail_loc=0
864     return $RC
865 }
866
867 drop_reint_reply() {
868 # OBD_FAIL_MDS_REINT_NET_REP
869     RC=0
870     do_facet mds sysctl -w lustre.fail_loc=0x119
871     do_facet client "$@" || RC=$?
872     do_facet mds sysctl -w lustre.fail_loc=0
873     return $RC
874 }
875
876 pause_bulk() {
877 #define OBD_FAIL_OST_BRW_PAUSE_BULK      0x214
878     RC=0
879     do_facet ost1 sysctl -w lustre.fail_loc=0x214
880     do_facet client "$1" || RC=$?
881     do_facet client "sync"
882     do_facet ost1 sysctl -w lustre.fail_loc=0
883     return $RC
884 }
885
886 drop_ldlm_cancel() {
887 #define OBD_FAIL_LDLM_CANCEL             0x304
888     RC=0
889     do_facet client sysctl -w lustre.fail_loc=0x304
890     do_facet client "$@" || RC=$?
891     do_facet client sysctl -w lustre.fail_loc=0
892     return $RC
893 }
894
895 drop_bl_callback() {
896 #define OBD_FAIL_LDLM_BL_CALLBACK        0x305
897     RC=0
898     do_facet client sysctl -w lustre.fail_loc=0x305
899     do_facet client "$@" || RC=$?
900     do_facet client sysctl -w lustre.fail_loc=0
901     return $RC
902 }
903
904 drop_ldlm_reply() {
905 #define OBD_FAIL_LDLM_REPLY              0x30c
906     RC=0
907     do_facet mds sysctl -w lustre.fail_loc=0x30c
908     do_facet client "$@" || RC=$?
909     do_facet mds sysctl -w lustre.fail_loc=0
910     return $RC
911 }
912
913 clear_failloc() {
914     facet=$1
915     pause=$2
916     sleep $pause
917     echo "clearing fail_loc on $facet"
918     do_facet $facet "sysctl -w lustre.fail_loc=0"
919 }
920
921 cancel_lru_locks() {
922     $LCTL mark "cancel_lru_locks $1 start"
923     for d in `find $LPROC/ldlm/namespaces | egrep -i $1`; do
924         [ -f $d/lru_size ] && echo clear > $d/lru_size
925         [ -f $d/lock_unused_count ] && grep [1-9] $d/lock_unused_count /dev/null
926     done
927     $LCTL mark "cancel_lru_locks $1 stop"
928 }
929
930
931 pgcache_empty() {
932     for a in /proc/fs/lustre/llite/*/dump_page_cache; do
933         if [ `wc -l $a | awk '{print $1}'` -gt 1 ]; then
934             echo there is still data in page cache $a ?
935             cat $a;
936             return 1;
937         fi
938     done
939     return 0
940 }
941
942 debugsave() {
943     DEBUGSAVE="$(sysctl -n lnet.debug)"
944 }
945
946 debugrestore() {
947     [ -n "$DEBUGSAVE" ] && sysctl -w lnet.debug="${DEBUGSAVE}"
948     DEBUGSAVE=""
949 }
950
951 ##################################
952 # Test interface 
953 ##################################
954
955 error() {
956     local FAIL_ON_ERROR=${FAIL_ON_ERROR:-true}
957     local TYPE=${TYPE:-"FAIL"}
958     local ERRLOG
959     sysctl -w lustre.fail_loc=0 2> /dev/null || true
960     log " ${TESTSUITE} ${TESTNAME}: @@@@@@ ${TYPE}: $@ "
961     ERRLOG=$TMP/lustre_${TESTSUITE}_${TESTNAME}.$(date +%s)
962     echo "Dumping lctl log to $ERRLOG"
963     # We need to dump the logs on all nodes
964     local NODES=$(nodes_list)
965     for NODE in $NODES; do
966         do_node $NODE $LCTL dk $ERRLOG
967     done
968     debugrestore
969     [ "$TESTSUITELOG" ] && echo "$0: ${TYPE}: $TESTNAME $@" >> $TESTSUITELOG
970     if $FAIL_ON_ERROR; then
971         exit 1
972     fi
973 }
974
975 # use only if we are ignoring failures for this test, bugno required.
976 # (like ALWAYS_EXCEPT, but run the test and ignore the results.)
977 # e.g. error_ignore 5494 "your message"
978 error_ignore() {
979     FAIL_ON_ERROR=false TYPE="IGNORE (bz$1)" error $2
980 }
981
982 skip () {
983         log " SKIP: ${TESTSUITE} ${TESTNAME} $@"
984         [ "$TESTSUITELOG" ] && echo "${TESTSUITE}: SKIP: $TESTNAME $@" >> $TESTSUITELOG
985 }
986
987 build_test_filter() {
988     [ "$ONLY" ] && log "only running test `echo $ONLY`"
989     for O in $ONLY; do
990         eval ONLY_${O}=true
991     done
992     [ "$EXCEPT$ALWAYS_EXCEPT" ] && \
993         log "skipping tests: `echo $EXCEPT $ALWAYS_EXCEPT`"
994     for E in $EXCEPT $ALWAYS_EXCEPT; do
995         eval EXCEPT_${E}=true
996     done
997     for G in $GRANT_CHECK_LIST; do
998         eval GCHECK_ONLY_${G}=true
999         done
1000 }
1001
1002 _basetest() {
1003     echo $*
1004 }
1005
1006 basetest() {
1007     IFS=abcdefghijklmnopqrstuvwxyz _basetest $1
1008 }
1009
1010 run_test() {
1011     export base=`basetest $1`
1012     if [ ! -z "$ONLY" ]; then
1013         testname=ONLY_$1
1014         if [ ${!testname}x != x ]; then
1015             run_one $1 "$2"
1016             return $?
1017         fi
1018         testname=ONLY_$base
1019         if [ ${!testname}x != x ]; then
1020             run_one $1 "$2"
1021             return $?
1022         fi
1023         echo -n "."
1024         return 0
1025     fi
1026     testname=EXCEPT_$1
1027     if [ ${!testname}x != x ]; then
1028         TESTNAME=test_$1 skip "skipping excluded test $1"
1029         return 0
1030     fi
1031     testname=EXCEPT_$base
1032     if [ ${!testname}x != x ]; then
1033         TESTNAME=test_$1 skip "skipping excluded test $1 (base $base)"
1034         return 0
1035     fi
1036     run_one $1 "$2"
1037     
1038     return $?
1039 }
1040
1041 EQUALS="======================================================================"
1042 equals_msg() {
1043     msg="$@"
1044
1045     local suffixlen=$((${#EQUALS} - ${#msg}))
1046     [ $suffixlen -lt 5 ] && suffixlen=5
1047     log `echo $(printf '===== %s %.*s\n' "$msg" $suffixlen $EQUALS)`
1048 }
1049
1050 log() {
1051     echo "$*"
1052     lsmod | grep lnet > /dev/null || load_modules
1053
1054     local MSG="$*"
1055     # Get rif of '
1056     MSG=${MSG//\'/\\\'}
1057     MSG=${MSG//\(/\\\(}
1058     MSG=${MSG//\)/\\\)}
1059     MSG=${MSG//\;/\\\;}
1060     local NODES=$(nodes_list)
1061     for NODE in $NODES; do
1062         do_node $NODE $LCTL mark "$MSG" 2> /dev/null || true
1063     done
1064 }
1065
1066 trace() {
1067         log "STARTING: $*"
1068         strace -o $TMP/$1.strace -ttt $*
1069         RC=$?
1070         log "FINISHED: $*: rc $RC"
1071         return 1
1072 }
1073
1074 pass() {
1075     echo PASS $@
1076 }
1077
1078 check_mds() {
1079     FFREE=`cat /proc/fs/lustre/mds/*/filesfree`
1080     FTOTAL=`cat /proc/fs/lustre/mds/*/filestotal`
1081     [ $FFREE -ge $FTOTAL ] && error "files free $FFREE > total $FTOTAL" || true
1082 }
1083
1084 run_one() {
1085     testnum=$1
1086     message=$2
1087     tfile=f${testnum}
1088     export tdir=d${TESTSUITE}/d${base}
1089     local SAVE_UMASK=`umask`
1090     umask 0022
1091     mkdir -p $DIR/$tdir
1092
1093     BEFORE=`date +%s`
1094     log "== test $testnum: $message ============ `date +%H:%M:%S` ($BEFORE)"
1095     #check_mds
1096     export TESTNAME=test_$testnum
1097     test_${testnum} || error "test_$testnum failed with $?"
1098     #check_mds
1099     check_grant ${testnum} || error "check_grant $testnum failed with $?"
1100     [ -f $CATASTROPHE ] && [ `cat $CATASTROPHE` -ne 0 ] && \
1101         error "LBUG/LASSERT detected"
1102     pass "($((`date +%s` - $BEFORE))s)"
1103     rmdir ${DIR}/$tdir >/dev/null 2>&1 || true
1104     unset TESTNAME
1105     unset tdir
1106     umask $SAVE_UMASK
1107     cd $SAVE_PWD
1108     $CLEANUP
1109 }
1110
1111 canonical_path() {
1112     (cd `dirname $1`; echo $PWD/`basename $1`)
1113 }
1114
1115 sync_clients() {
1116     [ -d $DIR1 ] && cd $DIR1 && sync; sleep 1; sync 
1117     [ -d $DIR2 ] && cd $DIR2 && sync; sleep 1; sync 
1118         cd $SAVE_PWD
1119 }
1120
1121 check_grant() {
1122     export base=`basetest $1`
1123     [ "$CHECK_GRANT" == "no" ] && return 0
1124
1125         testname=GCHECK_ONLY_${base}
1126         [ ${!testname}x == x ] && return 0
1127
1128         echo -n "checking grant......"
1129         cd $SAVE_PWD
1130         # write some data to sync client lost_grant
1131         rm -f $DIR1/${tfile}_check_grant_* 2>&1
1132         for i in `seq $OSTCOUNT`; do
1133                 $LFS setstripe $DIR1/${tfile}_check_grant_$i 0 $(($i -1)) 1
1134                 dd if=/dev/zero of=$DIR1/${tfile}_check_grant_$i bs=4k \
1135                                               count=1 > /dev/null 2>&1 
1136         done
1137         # sync all the data and make sure no pending data on server
1138         sync_clients
1139         
1140         #get client grant and server grant 
1141         client_grant=0
1142     for d in ${LPROC}/osc/*/cur_grant_bytes; do 
1143                 client_grant=$((client_grant + `cat $d`))
1144         done
1145         server_grant=0
1146         for d in ${LPROC}/obdfilter/*/tot_granted; do
1147                 server_grant=$((server_grant + `cat $d`))
1148         done
1149
1150         # cleanup the check_grant file
1151         for i in `seq $OSTCOUNT`; do
1152                 rm $DIR1/${tfile}_check_grant_$i
1153         done
1154
1155         #check whether client grant == server grant 
1156         if [ $client_grant != $server_grant ]; then
1157                 echo "failed: client:${client_grant} server: ${server_grant}"
1158                 return 1
1159         else
1160                 echo "pass"
1161         fi
1162 }
1163
1164 ########################
1165 # helper functions
1166
1167 osc_to_ost()
1168 {
1169     osc=$1
1170     ost=`echo $1 | awk -F_ '{print $3}'`
1171     if [ -z $ost ]; then
1172         ost=`echo $1 | sed 's/-osc.*//'`
1173     fi
1174     echo $ost
1175 }
1176
1177 remote_mds ()
1178 {
1179     [ ! -e /proc/fs/lustre/mds/*MDT* ]
1180 }
1181
1182 remote_ost ()
1183 {
1184     [ $(grep -c obdfilter $LPROC/devices) -eq 0 ]
1185 }
1186
1187 osts_nodes () {
1188     local OSTNODES=$(facet_host ost1)
1189
1190     for num in `seq $OSTCOUNT`; do
1191         local myOST=$(facet_host ost$num)
1192         [[ ! '\ '"$OSTNODES"'\ ' = *'\ '"$myOST"'\ '* ]] && OSTNODES="$OSTNODES $myOST"
1193     done
1194
1195     echo $OSTNODES
1196 }
1197
1198 nodes_list () {
1199     # FIXME. We need a list of clients
1200     local myNODES=`hostname`
1201
1202     [ ! "$mds_HOST" = "$(hostname)" ] && myNODES="$myNODES $mds_HOST"
1203
1204     local OSTNODES=$(osts_nodes)
1205     local myOSTNODES=`echo ' '"$OSTNODES"' ' | sed -e s/[\ ]$mds_HOST[\ ]/\ / -e s/[\ ]$(hostname)[\ ]/\ /`
1206     [ -n "$myOSTNODES" ] && myNODES="$myNODES $myOSTNODES"
1207     echo $myNODES
1208 }
1209
1210 is_patchless ()
1211 {
1212     grep -q patchless $LPROC/version
1213 }
1214
1215 check_runas_id() {
1216     local myRUNAS_ID=$1
1217     shift
1218     local myRUNAS=$@
1219     mkdir $DIR/d0_runas_test
1220     chmod 0755 $DIR
1221     chown $myRUNAS_ID:$myRUNAS_ID $DIR/d0_runas_test
1222     $myRUNAS touch $DIR/d0_runas_test/f$$ || \
1223         error "unable to write to $DIR/d0_runas_test as UID $myRUNAS_ID. 
1224         Please set RUNAS_ID to some UID which exists on MDS and client or 
1225         add user $myRUNAS_ID:$myRUNAS_ID on these nodes."
1226     rm -rf $DIR/d0_runas_test
1227 }