cmd/xfs/tools/README.auto-qa 1.1 Renamed to cmd/xfstests/tools/README.auto-qa
authorNathan Scott <nathans@sgi.com>
Mon, 15 Jan 2001 05:23:30 +0000 (05:23 +0000)
committerNathan Scott <nathans@sgi.com>
Mon, 15 Jan 2001 05:23:30 +0000 (05:23 +0000)
tools/README.auto-qa [new file with mode: 0644]
tools/auto-qa [new file with mode: 0755]
tools/db-walk [new file with mode: 0755]
tools/fs-walk [new file with mode: 0755]
tools/interop [new file with mode: 0755]
tools/srcdiff [new file with mode: 0755]
tools/srctest [new file with mode: 0644]

diff --git a/tools/README.auto-qa b/tools/README.auto-qa
new file mode 100644 (file)
index 0000000..fa36165
--- /dev/null
@@ -0,0 +1,71 @@
+Quick guide to auto-qa                                      dxm 04/10/2000
+______________________                                      ______________
+
+
+       - pick/create a user to run auto-qa and check they 
+            can use ptools to check out of the tree
+       - add your host to cmd/xfs/stress/common.config
+       - add your host to cmd/xfs/tools/auto-qa
+               check both these files in
+       - make a directory "$HOME/qa"
+       - make a workarea "$HOME/qa/linux-xfs" for linux-xfs
+               (easiest to copy one from elsewhere)
+       - cd $HOME/qa ; ln -s linux-xfs/cmd/xfs/tools/auto-qa .
+               (auto-qa must be a link into it's own source tree
+               so it can update itself)
+       - copy an appropriate .config file to
+               $HOME/qa/$HOSTNAME-2.4.0-xfs-qa.config
+       - You'll need a hacked version of 'su' in $HOME/qa that
+                lets your user su to root/root without a password
+                (if you want to run from cron, it mustn't require
+                /dev/tty). Warning - this is a massive security
+                hole.
+       - chown root.root $HOME/qa/su
+       - chmod 6755 $HOME/qa/su
+       - add the soon to be kernel to /etc/lilo.conf
+
+               image=/boot/vmlinuz-2.4.0-xfs-qa
+                       label=linux-xfs-qa
+                       append = "console=ttyS0,38400n8"
+               
+       - $HOME/qa/auto-qa init
+
+At this point, the script should update the workarea, clean it,
+rebuild it, install it and reboot.
+
+Then run
+
+       - $HOME/qa/auto-qa restarted
+
+And the tests should happen... and all pass, of course.
+
+To get it going automagically:
+
+       - add some lines to the appropriate user's crontab:
+
+               0 4 * * *       $HOME/qa/auto-qa cron-init
+               30 4 * * *      $HOME/qa/auto-qa cron-restarted
+
+Notes:
+       - if MODULAR=1 in auto-qa XFS and pagebuf are expected to
+                be modules. if MODULAR=0 they should be built into
+                the kernel
+       - the test device is cleaned at the start of the QA run
+               (to stop nightly QA being stuffed up if someone
+               leaves the device inconsistant etc)
+       - I'm using a hacked su because PCP sudo won't set the
+               gid properly, and normal linux su won't run
+               without a tty even if PAM is pissed-off.
+       - The QA is restarted after reboot by a second cron entry
+               to avoid the test being able to get itself into
+               some stupid loop and so that it's always started
+               by the appropriate user. You might have to make
+               the second cron run later if your build takes ages.
+       - Point the email addresses somewhere appropriate
+       - When run in "cron-init" or "init" states, the script
+               will p_tupdate itself and restart. If you start
+               with an empty source tree, you'll need to check
+               out the cmd/xfs/tools/auto-qa script before it'll
+               work (duh).
+
+good luck.
diff --git a/tools/auto-qa b/tools/auto-qa
new file mode 100755 (executable)
index 0000000..861c721
--- /dev/null
@@ -0,0 +1,537 @@
+#!/bin/sh
+#
+# Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+# 
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+# 
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# 
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like.  Any license provided herein, whether implied or
+# otherwise, applies only to this software file.  Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+# 
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+# 
+# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+# Mountain View, CA  94043, or:
+# 
+# http://www.sgi.com 
+# 
+# For further information regarding this notice, see: 
+# 
+# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+
+# automatic qa system. 31/08/00 dxm@sgi.com
+
+_log()
+{
+    echo "$*" >&2
+    echo "$*" >> $LOG
+}
+
+_fail()
+{
+    if [ "$started" = "1" ] 
+    then
+        echo "auto-qa stopped" | wall
+        started=0
+    fi
+
+    _log "$*"
+    
+    # send special email if a cron'd qa run fails
+    case $state
+    in
+        cron*)
+            mail -s "xfs qa status report" $ADMINEMAIL \
+                < $LOG 2>&1
+       ;;
+    esac
+
+    status=1
+    exit 1
+}
+
+# configuration (you could tune this)
+
+EXTRA="-xfs-qa"
+VERSION="2.4.0"
+BOOT="/boot"
+SOAK_PASSES="-1"
+SOAK_STRESS="10000"
+SOAK_PROC="3"
+
+# this should be constant
+
+ROOT="$HOME/qa"
+HOST=`hostname -s`
+export WORKAREA="$ROOT/linux-xfs"
+
+export PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin/ptools:/usr/local/bin"
+STATE=$ROOT/qa.state
+QADIR="$WORKAREA/cmd/xfs/stress"
+SUDO="su -c"
+IMAGE="$BOOT/vmlinuz-$VERSION$EXTRA"
+SYSTEMMAP="$BOOT/System.map-$VERSION$EXTRA"
+CONFIG="$ROOT/$HOST-$VERSION$EXTRA.config"
+MODULES="/lib/modules/$VERSION$EXTRA"
+SELF="$ROOT/auto-qa"
+SELF_UPDATE="cmd/xfs/tools/auto-qa"
+COMMON_CONFIG="$WORKAREA/cmd/xfs/stress/common.config"
+SH="/bin/sh"
+LOG="$ROOT/qa.log"
+
+# need to add auto-qa hosts here
+
+case $HOST
+in
+    fuzzy)
+        EMAIL="dxm@larry"
+        ADMINEMAIL="dxm@larry"
+        MODULAR=1
+        ;;
+    bruce)
+        EMAIL="dxm@larry"
+        ADMINEMAIL="dxm@larry"
+        MODULAR=1
+        ;;
+    sagan)
+        EMAIL="dxm@larry"
+        ADMINEMAIL="dxm@larry"
+        MODULAR=0
+        ;;
+    troppo)
+       EMAIL="nathans@larry"
+       ADMINEMAIL="nathans@larry"
+       MODULAR=0
+       ;;
+    *)
+        _fail "auto-qa: no configuration information for host '$HOST'"
+        ;;
+esac
+
+# do some cleanup on exit
+
+_cleanup()
+{
+    umount $SCRATCH_DEV &> /dev/null
+    umount $TEST_DEV &> /dev/null
+    if [ "$started" = 1 ]
+    then
+        echo "auto-qa stopped" | wall
+        started=0
+    fi
+}
+status=1
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# clean exit
+
+_success()
+{
+    status=0
+    exit 0
+}
+
+_get_state()
+{
+    state=`cat $STATE`
+}
+
+_set_state()
+{
+    echo $1 > $STATE
+    _get_state
+}
+
+_change_state()
+{
+    new=$1
+    
+    case $state
+    in
+        *-*)
+            case $new
+            in
+                *-*)
+                    _set_state $new
+                    ;;
+                *)
+                    _set_state `echo $state | sed "s/-.*$/-$new/"`
+                    ;;
+            esac
+            ;;
+        *)
+            _set_state $new
+            ;;
+    esac
+}
+
+_sudo()
+{
+    $ROOT/su -c "$*" < /dev/null ;# HACK - we need a hacked su at the mo
+}
+
+_restart()
+{
+    exec $ROOT/su -c "shutdown -r 2 \"auto-qa rebooting\" &" < /dev/null
+}
+
+_log "*** linux-xfs QA (`date`)"
+
+_get_state
+
+# check preconditions for starting state
+case $1
+in
+    cron-init)
+        case $state
+        in
+            *done)
+                ;;
+            *)
+                _fail "    !!! cron-init while not in \"*done\" state"
+                ;;
+        esac
+        ;;
+    cron-restarted)
+        # we don't auto restart after reboot, but cron the restart
+        # to happen a bit later - it's much easier and safer that way
+        if [ $state != "cron-restarted" ]
+        then
+            _fail "    !!! cron-restarted while not in \"cron-restarted\" state"
+        fi
+        ;;
+esac
+
+if [ "$1" != "" ]
+then
+    _set_state $1
+fi
+
+[ $UID -eq 0 ]          && _fail "    !!! QA most be run as a normal user"
+[ -d $ROOT ]            || _fail "    !!! QA root \"$ROOT\" not found"
+[ -d $WORKAREA ]        || _fail "    !!! QA workarea \"$WORKAREA\" not found"
+[ -r $CONFIG ]          || _fail "    !!! Can't read config file $CONFIG"
+. $COMMON_CONFIG       || _fail "    !!! Couldn't source $COMMON_CONFIG"
+
+cd $ROOT
+
+started=1
+echo "auto-qa started" | wall
+
+while true
+do
+    _get_state
+
+    _log "    *** state $state start (`date`)"
+    _log "        (user=$USER, host=$HOST)"
+    new_state=""
+
+    case $state
+    in
+        *init)
+            echo "" > $ROOT/qa.log
+            echo "" > $ROOT/qa.full
+            _log "******************************************"
+            _log "QA init (`date`)"
+            _log "******************************************"
+
+            _change_state "inited"
+            exec $SH -c "cd $WORKAREA ; p_tupdate $SELF_UPDATE ; chmod +x $SELF_UPDATE ; exec $SELF"
+            ;;
+            
+        *inited)
+            _log "        *** QA initialized"
+            new_state="update"
+            ;;
+        
+        *update)
+            _log "        *** p_tupdate"
+            cd $WORKAREA 
+            p_tupdate 2>&1 \
+                                    || _fail "            !!! p_tupdate failed"
+
+            _log "        *** p_check/p_purge"
+            cd $WORKAREA 
+            p_check -s | p_purge -yiu 2>&1 \
+                                    || _fail "            !!! p_check/p_purge failed"
+
+            _log "        *** non-trunk files"
+            cd $WORKAREA 
+            p_list -c 2>&1 \
+                                    || _fail "            !!! p_list failed"
+
+            new_state="clean"
+            ;;
+            
+        *clean)
+            # we need to configure or else we might fail to clean stress/src
+            _log "        *** configure for clean"
+            cd $WORKAREA/cmd/xfs
+            make configure 2>&1 \
+                                    || _fail "            !!! configure for clean failed"
+                                    
+            _log "        *** clean stress/src"
+            cd $WORKAREA/cmd/xfs/stress/src
+            make clobber 2>&1 \
+                                    || _fail "            !!! clean stress/src failed"
+
+            _log "        *** clean xfs tools"
+            cd $WORKAREA/cmd/xfs
+            make realclean 2>&1 \
+                                    || _fail "            !!! clean tools failed"
+
+            _log "        *** clean quota tools"
+            cd $WORKAREA/cmd/quota
+            ( rm -f configure ; autoconf ; sh configure ; make clean ) 2>&1 \
+                                    || _fail "            !!! clean quota failed"
+
+            _log "        *** clean qa"
+            cd $WORKAREA/cmd/xfs/stress
+            rm -f *.full *.bad *.log *.time *.core core 2>&1 \
+                                    || _fail "            !!! clean qa failed"
+
+            _log "        *** clean linux"
+            cd $WORKAREA/linux
+            make mrproper 2>&1 \
+                                    || _fail "            !!! clean linux failed"
+
+            _log "        *** install configuration file"
+            cp -f $CONFIG $WORKAREA/linux/.config 2>&1 \
+                                    || _fail "            !!! failed to install config"
+            
+            _log "        *** remove version file"
+            rm -f include/linux/version.h 2>&1 \
+                                    || _fail "            !!! failed to clean version"
+
+            new_state="reconfig"
+            ;;
+            
+        *reconfig)
+        
+            _log "        *** reconfig kernel"
+            
+            _change_state "clean" ;# if this fails, we'd better start from scratch
+            
+            cd $WORKAREA/linux
+            # we want to use default options for any new config options.
+            echo -e "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" | \
+                make EXTRAVERSION=$EXTRA oldconfig 2>&1 \
+                                    || _fail "            !!! reconfig oldconfig failed"
+            make EXTRAVERSION=$EXTRA dep 2>&1 \
+                                    || _fail "            !!! reconfig dep failed"
+
+            new_state="build"
+            ;;
+            
+        *build)
+            _log "        *** build kernel"
+            
+            _change_state "clean" ;# if this fails, we'd better start from scratch
+            
+            cd $WORKAREA/linux
+            make -j2 EXTRAVERSION=$EXTRA bzImage 2>&1 \
+                                    || _fail "            !!! build bzImage failed"
+            make -j2 EXTRAVERSION=$EXTRA modules 2>&1 \
+                                    || _fail "            !!! build modules failed"
+                                    
+            _log "        *** build tools"
+            cd $WORKAREA/cmd/xfs
+            
+            # use e-fence - but this will only take effect on configure
+            export MALLOCLIB=/usr/lib/libefence.a
+            make configure 2>&1 \
+                                    || _fail "            !!! configure tools failed"
+            make default 2>&1 \
+                                    || _fail "            !!! build tools failed"
+
+            _log "        *** build quota tools"
+            cd $WORKAREA/cmd/quota
+            
+            # use e-fence - but this will only take effect on configure
+            export MALLOCLIB=/usr/lib/libefence.a
+            ( rm -f configure ; autoconf ; sh configure ; make all ) 2>&1 \
+                                    || _fail "            !!! build quota failed"
+
+            _log "        *** build stress/src"
+            cd $WORKAREA/cmd/xfs/stress/src
+            
+            make default 2>&1 \
+                                    || _fail "            !!! build stress/src failed"
+
+            new_state="install"
+            ;;
+            
+        *install)
+            _log "        *** blat old modules"
+            
+            _sudo rm -rf $MODULES
+            
+            _log "        *** install kernel"
+            cd $WORKAREA/linux
+            _sudo cp -f $WORKAREA/linux/arch/i386/boot/bzImage $IMAGE 2>&1 \
+                                    || _fail "            !!! install kernel failed"
+            _sudo cp -f $WORKAREA/linux/System.map $SYSTEMMAP 2>&1 \
+                                    || _fail "            !!! install kernel failed"
+            _sudo make EXTRAVERSION=$EXTRA modules_install 2>&1 \
+                                    || _fail "            !!! install modules failed"
+
+            _log "        *** install xfs tools"
+            cd $WORKAREA/cmd/xfs
+            _sudo make install 2>&1 \
+                                    || _fail "            !!! install tools failed"
+
+            _log "        *** install quota tools"
+            cd $WORKAREA/cmd/quota
+            _sudo make install 2>&1 \
+                                    || _fail "            !!! install quota failed"
+
+            _log "        *** reinit lilo"
+            _sudo /sbin/lilo 2>&1 \
+                                    || _fail "            !!! reinit lilo failed"
+            new_state="restart"
+            ;;
+            
+        *restart)
+            _log "            *** select qa kernel"
+            _sudo /sbin/lilo -R linux-xfs-qa 2>&1 \
+                                    || _fail "            !!! lilo failed"
+            
+            _log "            *** prepare to restart"
+            _change_state "restarted"
+            
+            _log "            *** restarting"
+
+           _restart # doesn't return
+            ;;
+            
+        *restarted)
+            _log "            *** QA reentered after restart"
+            
+            new_state="check"
+            ;;
+          
+        *check)
+            uname=`uname -ar`
+            _log "            *** uname $uname"
+            _log "            *** user tools"
+            ls -l /sbin/*xfs* /usr/sbin/*xfs* 2>&1
+            _log "            *** kernel"
+            ls -l /boot/*$EXTRA*  2>&1
+            _log "            *** kernel modules"
+            ls -l /lib/modules/$VERSION$EXTRA/kernel/fs/pagebuf/* \
+                  /lib/modules/$VERSION$EXTRA/kernel/fs/xfs/*     \
+                  /lib/modules/$VERSION$EXTRA/kernel/fs/xfs/support/* 
+            
+            if [ $MODULAR -eq 0 ]
+            then
+                new_state="reset"
+            else
+                new_state="probe"
+            fi
+            ;;
+            
+        *probe)
+            _log "            *** modules dependencies"
+            
+            _sudo depmod -a  2>&1 \
+                                    || _fail "            !!! failed to depmod -a" 
+            
+            _log "            *** unmounting XFS mounts"
+            
+            _sudo umount -a -t xfs 2>&1
+            
+            _log "            *** removing modules"
+            
+            for m in xfsidbg xfs pagebuf kdbm_pg kdbm_vm
+            do
+                _sudo rmmod $m 2> /dev/null
+            done
+            
+            _log "            *** installing modules"
+
+           _sudo modprobe xfs 2>&1 \
+                                    || _fail "            !!! failed to modprobe xfs"
+
+            new_state="reset"
+            ;;
+            
+        *reset)
+            
+            _log "            *** unmounting TEST_DEV"
+            
+            _sudo umount $TEST_DEV 2>&1
+            
+            _log "            *** unmounting SCRATCH_DEV"
+            
+            _sudo umount $SCRATCH_DEV 2>&1
+            
+            _log "            *** clean TEST_DEV"
+            
+            _sudo mkfs -t xfs -f $TEST_DEV 2>&1 \
+                                    || _fail "            !!! failed to mkfs TEST_DEV"
+            
+            _log "            *** mounting TEST_DEV"
+            
+            _sudo mount -t xfs $TEST_DEV $TEST_DIR 2>&1 \
+                                    || _fail "            !!! failed to mount"
+                                    
+            new_state="run"
+            ;;
+            
+            
+        soak-run)
+            cd $QADIR
+            
+            _log "            *** run soak test"
+            _sudo ./soak $SOAK_PASSES $SOAK_STRESS $SOAK_PROC\
+                                    || _fail "            !!! failed to run soak test"
+
+            new_state="done"
+            ;;
+            
+        *run)
+            cd $QADIR
+            
+            _log "            *** run tests"
+            _sudo ./check -l -g auto 2>&1 | tee $ROOT/qa.out
+            
+            _log ""
+            _log "            *** send status mail"
+            mail -s "xfs qa status report" $EMAIL < $ROOT/qa.out 2>&1
+        
+            new_state="done"
+            ;;
+            
+        *done)
+            _log "*** QA run complete"
+
+            _success
+            ;;
+            
+        *nothing)
+            new_state="done"
+            _log "    *** do nothing"
+            ;;
+            
+        *)
+            _fail "           !!! unknown state $state"
+            ;;
+    esac
+
+    _log "    *** state $state done (`date`)"
+    [ "$new_state" = "" ] && _fail "    !!! no new state set"
+    _change_state $new_state
+    
+done
diff --git a/tools/db-walk b/tools/db-walk
new file mode 100755 (executable)
index 0000000..e64df10
--- /dev/null
@@ -0,0 +1,211 @@
+#!/usr/bin/perl -w
+
+#
+#  Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+#  
+#  This program is free software; you can redistribute it and/or modify it
+#  under the terms of version 2 of the GNU General Public License as
+#  published by the Free Software Foundation.
+#  
+#  This program is distributed in the hope that it would be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#  
+#  Further, this software is distributed without any warranty that it is
+#  free of the rightful claim of any third person regarding infringement
+#  or the like.  Any license provided herein, whether implied or
+#  otherwise, applies only to this software file.  Patent licenses, if
+#  any, provided herein do not apply to combinations of this program with
+#  other software, or any other product whatsoever.
+#  
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write the Free Software Foundation, Inc., 59
+#  Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#  
+#  Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+#  Mountain View, CA  94043, or:
+#  
+#  http://www.sgi.com 
+#  
+#  For further information regarding this notice, see: 
+#  
+#  http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+
+#
+# use db to try to traverse the entire filesystem starting at the root
+#
+#                                                       dxm 5/10/00
+
+my $device;
+my $rootino;
+my $agcount;
+my $versionnum;
+my $dir_version;
+my @dir_inodes;
+my @bmap_blocks;
+my @block_inodes;
+my $mode;
+
+sub db($)
+{
+    my ($args)=@_;
+    my ($ret);
+    
+    $ret=`xfs_db -r $args $device 2> /dev/null`;
+    die "ERROR executing xfs_db -r $args $device" if ($?);
+    
+    return $ret;
+}
+
+sub fmt($)
+{
+    my ($text)=@_;
+    my $c=0;
+    print "        ";
+    foreach (split("\n",$text)) {
+        s/^core\.//;
+        
+        if ($c+length($_) >= 70) {
+            $c=0;
+            print ",\n        ";
+        }
+        if ($c) {
+            print ", ";
+            $c+=2;
+        }
+        print "$_";
+        $c+=length($_)+2;
+    }
+    print "\n";
+}
+
+sub inode($)
+{
+    my ($num)=@_;
+    my ($t);
+    
+    @dir_inodes=();
+    
+    $t=db("-c \"inode $num\" -c \"print\"");
+    print "    *** Inode $num\n";
+    fmt($t);
+    
+    ($mode)= $t=~ /^core.mode = (\d+)$/m;
+    
+    if ($t=~ /a\.bmx/m) {
+        bmap("inode $num","attr");
+        foreach (@bmap_blocks) {
+            attr_block($_);
+        }
+    }
+    if (eval "$mode & 040000") {
+        if ( $t=~ /sfdir/m) {
+            while ($t=~ /inumber(?:\.i[48])? = (\d+)$/mg) {
+                push(@dir_inodes,$1);
+            }
+        }
+        if ( $t=~ /u\.bmx/m) {
+            bmap("inode $num","dir");
+            foreach (@bmap_blocks) {
+                dir_block($_);
+                push(@dir_inodes,@block_inodes);
+            }
+        }
+    } else {
+        bmap("inode $num","file") if ( $t=~ /u\.bmx/m);
+    }
+}
+
+sub bmap($$)
+{
+    my ($cmd,$type)=@_;
+    my ($t);
+    
+    @bmap_blocks=();
+    
+    $flag=($type eq "attr")?"-a":"";
+    
+    $t=db("-c \"$cmd\" -c \"bmap $flag\"");
+    print "    *** bmap $type $cmd\n";
+    fmt($t);
+    
+    if ($type eq "dir" || $type eq "attr") {
+        while ($t=~ /startblock (\d+) \(.+\) count (\d+)/mg) {
+            for ($b=$1;$b<$1+$2;$b++) {
+                push(@bmap_blocks,$b);
+            }
+        }
+    }
+}
+
+sub dir_block($)
+{
+    my ($num)=@_;
+    my ($t);
+    
+    @block_inodes=();
+    
+    $type=($dir_version==2)?"dir2":"dir";
+    
+    $t=db("-c \"fsblock $num\" -c \"type $type\" -c \"print\"");
+    print "    *** $type block $num\n";
+    # need to drop . and ..
+    ($self)= $t=~ /\[(\d+)\].name = \"\.\"/m;
+    ($parent)= $t=~ /\[(\d+)\].name = \"\.\.\"/m;
+    fmt($t);
+    
+    
+    while ($t=~ /\[(\d+)\].inumber = (\d+)/mg) {
+        next if (defined $self && $1 == $self);
+        next if (defined $parent && $1 == $parent);
+        push(@block_inodes, $2);
+    }
+}
+
+sub attr_block($)
+{
+    my ($num)=@_;
+    my ($t);
+    
+    $t=db("-c \"fsblock $num\" -c \"type attr\" -c \"print\"");
+    print "    *** attr block $num\n";
+
+    fmt($t);
+}
+
+sub sb($)
+{
+    my ($num)=@_;
+    my ($t);
+    
+    $t=db("-c \"sb $num\" -c \"print\"");
+    print "    *** SB $num\n";
+    fmt($t);
+    
+    ($rootino)= $t=~ /^rootino = (\d+)$/m;
+    ($agcount)= $t=~ /^agcount = (\d+)$/m;
+    ($versionnum)= $t=~ /^versionnum = (0x[\da-f]+)$/m;
+    $dir_version = (eval "$versionnum & 0x2000")?2:1;
+}
+
+die "Usage: $0 <XFS device>\n" unless (@ARGV == 1);
+
+$device=shift @ARGV;
+die "can't read $device\n" unless (-r $device);
+die "$device is not a block device\n" unless (-b _);
+
+chomp($HOST = `hostname -s`);
+
+print "*** db-walk host $HOST device $device\n";
+
+sb(0);
+for ($ag=1;$ag<$agcount;$ag++) {
+    sb($ag);
+}
+
+@inodes=($rootino);
+while ($_ = shift @inodes) {
+    inode($_);
+    push(@inodes,@dir_inodes);
+}
diff --git a/tools/fs-walk b/tools/fs-walk
new file mode 100755 (executable)
index 0000000..fd6d4af
--- /dev/null
@@ -0,0 +1,117 @@
+#!/usr/bin/perl -w
+
+#
+#  Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+#  
+#  This program is free software; you can redistribute it and/or modify it
+#  under the terms of version 2 of the GNU General Public License as
+#  published by the Free Software Foundation.
+#  
+#  This program is distributed in the hope that it would be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#  
+#  Further, this software is distributed without any warranty that it is
+#  free of the rightful claim of any third person regarding infringement
+#  or the like.  Any license provided herein, whether implied or
+#  otherwise, applies only to this software file.  Patent licenses, if
+#  any, provided herein do not apply to combinations of this program with
+#  other software, or any other product whatsoever.
+#  
+#  You should have received a copy of the GNU General Public License along
+#  with this program; if not, write the Free Software Foundation, Inc., 59
+#  Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#  
+#  Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+#  Mountain View, CA  94043, or:
+#  
+#  http://www.sgi.com 
+#  
+#  For further information regarding this notice, see: 
+#  
+#  http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+
+#
+# traverse the entire filesystem dumping info. 
+#
+#                                                       dxm 5/10/00
+use MD5;
+use Getopt::Std;
+
+my %opt;
+
+sub scan($)
+{
+    my ($file)=@_;
+    my ($md5)=new MD5;
+    my (@stat);
+
+    unless (@stat=lstat("$file")) {
+        printf("%-" . ($opt{v}?65:32) . "s $file\n", "!!! could not lstat");
+        return;
+    }
+
+    $stat[0]=$stat[8]=""; # wipe the device and access time
+    $md5->reset;
+    $md5->add(join(" ",@stat));
+    
+    print join(" ",@stat), "\n";
+    
+    if ($opt{v}) {
+        print $md5->hexdigest . " ";
+        $md5->reset;
+    }
+
+    if (-l "$file") {
+        if (!defined($link = readlink $file)) {
+            printf("%-32s $file\n", "!!! could not readlink");
+            return;
+        }
+        $md5->add($link);
+    } elsif (-f "$file") {
+        if (!open(FILE, "$file")) {
+            printf("%-32s $file\n", "!!! could not read");
+            return;
+        }
+        $md5->addfile(FILE);
+        close (FILE);
+    }
+    print $md5->hexdigest . " $file\n";
+}
+
+getopts('vs', \%opt);
+
+die "Usage: $0 <dir>\n" unless (@ARGV == 1);
+
+$dir=shift @ARGV;
+die "can't read $dir\n" unless (-r $dir);
+die "$dir is not a directory\n" unless (-d _);
+
+chomp($HOST = `hostname -s`);
+
+print "*** fs-walk host $HOST dir $dir\n";
+
+@todo=$dir;
+while ($dir = shift @todo) {
+    scan($dir);
+    unless (opendir(DIR,$dir)) {
+        printf("%-" . ($opt{v}?65:32) . "s $dir\n", "!!! could not opendir");
+        next;
+    }
+    unless (@all=readdir(DIR)) {
+        printf("%-" . ($opt{v}?65:32) . "s $dir\n", "!!! could not readdir");
+        next;
+    }
+    closedir(DIR);
+    @dirs=grep(-d "$dir/$_" && !-l "$dir/$_", @all);
+    foreach (@all) {
+        next if /^\.\.?$/;
+        scan("$dir/$_");
+    }
+    
+    foreach (grep(!/^\.\.?$/, @dirs)) {
+        push (@todo,"$dir/$_");
+    }
+}
+
diff --git a/tools/interop b/tools/interop
new file mode 100755 (executable)
index 0000000..7ccc6c9
--- /dev/null
@@ -0,0 +1,99 @@
+#!/usr/sbin/perl
+
+sub setup()
+{
+    $PATH="$PATH:/usr/local/bin/ptools:/sbin:/usr/sbin";
+    $DISPLAY="clouds:0";
+    
+    if ("$HOST" eq "bruce") {
+        $TOOLS="/home/dxm/isms/slinx-xfs/cmd/xfs/tools";
+        $SCRATCH_DEV="/dev/sdf1";
+        $SCRATCH_MNT="/mnt/xfs3";
+        $MKFS="/sbin/mkfs -t xfs -f";
+        $SUDO="/home/dxm/su -c";
+        $MOUNT="/bin/mount -t xfs";
+        $UMOUNT="/bin/umount";
+        $MKFS_EXTRA="-f";
+    } elsif ("$HOST" eq "whack") {
+        $TOOLS="/hosts/snort/build1/people/dxm/isms/slinx-xfs/cmd/xfs/tools";
+        $SCRATCH_DEV="/dev/dsk/20000080e5114459/lun2s0/c2p1";
+        $SCRATCH_MNT="/lun2";
+        $MKFS="/sbin/mkfs";
+        $SUDO="su root -c";
+        $MOUNT="/sbin/mount -t xfs";
+        $UMOUNT="/sbin/umount";
+        $MKFS_EXTRA="";
+    } else {
+        die "unconfigured host \"$HOST\"\n"
+    }
+}
+
+sub run_no_check(@)
+{
+    system(@_);
+}
+
+sub run(@)
+{
+    system(@_)  == 0
+        || die "ERROR \"" . join(" ",@_) . "\" returned error\n";
+}
+
+sub run_expect_fail(@)
+{
+    system(@_)  == 0
+        && die "ERROR \"" . join(" ",@_) . "\" returned non-error\n";
+}
+
+sub umount_no_check()
+{
+    run_no_check("umount $SCRATCH_DEV");
+}
+
+sub umount()
+{
+    run("umount $SCRATCH_DEV");
+}
+
+sub mount($)
+{
+    my ($ops)=@_;
+    run("mount -t xfs $ops $SCRATCH_DEV $SCRATCH_MNT");
+}
+
+chomp($HOST=`hostname -s`);
+
+die "usage: $ARGV0 <operation> [parameters]\n" unless (scalar(@ARGV));
+print "*** $HOST: Interop started\n";
+print "    *** ", join(" ", @ARGV), "\n";
+
+setup();
+
+$op=shift(@ARGV);
+
+umount_no_check();
+
+if ($op eq "init") {
+
+    run("mkfs -t xfs $MKFS_EXTRA $SCRATCH_DEV");
+    
+} elsif ($op eq "test") {
+
+    run("xfs_repair -n $SCRATCH_DEV");
+    
+} elsif ($op eq "easy") {
+
+    mount("");
+    system("mount");
+    mkdir("$SCRATCH_MNT/fish",0777);
+    
+} elsif ($op eq "check") {
+
+    mount("-o ro");
+    system("cd $SCRATCH_MNT ; $TOOLS/fs-walk .");
+
+} else {
+    die "unknown operation \"$op\"\n";
+}
+
+umount_no_check();
diff --git a/tools/srcdiff b/tools/srcdiff
new file mode 100755 (executable)
index 0000000..70c1fdf
--- /dev/null
@@ -0,0 +1,267 @@
+#!/usr/bin/perl -w
+use strict;
+# 
+# srcdiff is used to compare current user level code with the current
+# kernel code and advise of any differences between files which are
+# sharing some or all of their content.
+# 
+# There are two classes of sharing which we will check - header files
+# in the include directory, which must be exactly the same (use diff)
+# and source files which contain routines which must be exactly the
+# same (but the userland file is always a subset of the kernel file,
+# and hence a more flexible mechanism to "diff" is required).
+# 
+# NB: to cross check that srcdiff is finding all the functions in the
+#     user source file, providing you have "mkproto" installed, you
+#     can "cd cmd/xfs/libxfs" and cut&paste this into a bourne shell:
+#     $ for file in xfs_*.c; do
+#     > mkproto -nps < $file | perl -ne '
+#     > END { print "    $count\t- " }
+#     > s/^.* (xfs\w+|\*xfs\w+|xlog\w+|\*xlog\w+) \(.*/\1/ && { $count++ }'
+#     > echo $file
+#     > done
+# (compare this to "srcdiff | fgrep Total:") ... repeat for logprint.
+# 
+
+die "WORKAREA not set" unless defined $ENV{'WORKAREA'};
+chdir $ENV{'WORKAREA'};
+my $xdiff = $ENV{'XDIFF'};
+my $quiet=0;
+my $usage=0;
+
+foreach (@ARGV) {
+    if (/^-q$/) {
+        $quiet++;
+    } else {
+        print STDERR "Illegal option $_\n";
+        $usage++;
+    }
+}
+
+if ($usage) {
+    print STDERR "Usage: $0 [-q]\n";
+    exit 1;
+}
+
+my @difflist = qw(
+       xfs_ag.h  xfs_alloc.h  xfs_alloc_btree.h xfs_arch.h
+       xfs_attr_leaf.h  xfs_attr_sf.h  xfs_bit.h  xfs_bmap.h
+       xfs_bmap_btree.h  xfs_btree.h  xfs_buf_item.h
+       xfs_da_btree.h  xfs_dfrag.h  xfs_dinode.h  xfs_dir.h
+       xfs_dir2.h  xfs_dir2_block.h  xfs_dir2_data.h
+       xfs_dir2_leaf.h  xfs_dir2_node.h  xfs_dir2_sf.h
+       xfs_dir_leaf.h  xfs_dir_sf.h  xfs_dqblk.h  xfs_dquot_item.h
+       xfs_extfree_item.h  xfs_ialloc.h  xfs_imap.h
+       xfs_ialloc_btree.h  xfs_inode.h  xfs_inode_item.h
+       xfs_inum.h  xfs_log.h  xfs_log_priv.h  xfs_log_recover.h
+       xfs_mount.h  xfs_quota.h  xfs_rtalloc.h
+       xfs_sb.h  xfs_trans.h  xfs_trans_space.h  xfs_types.h
+);
+
+sub straightdiff {
+       my ( $file, $prefix1, $prefix2 ) = @_;
+
+       `diff $prefix1/$file $prefix2/$file >/dev/null 2>&1`;
+        if (!$quiet) {
+           print sprintf("\t%-35s ... ", $file);
+           if ($? != 0)        { print "FAILED\n"; }
+           else                { print "ok\n"; }
+        } elsif ($? != 0) { 
+               printf("\t%-35s ... ", $file);
+                print "FAILED\n"; 
+        }
+}
+
+print "\n=== Checking headers ===\n";
+foreach (@difflist) {
+       straightdiff $_, 'cmd/xfs/include', 'linux/fs/xfs';
+}
+straightdiff 'xfs_cred.h', 'cmd/xfs/include', 'linux/fs/xfs/linux';
+straightdiff 'xfs_fs.h', 'cmd/xfs/include', 'linux/include/linux';
+straightdiff 'attributes.h', 'cmd/xfs/include', 'linux/include/linux';
+straightdiff 'acl.h', 'cmd/xfs/include', 'linux/fs/xfs/pseudo-inc/sys';
+straightdiff 'arch.h', 'cmd/xfs/include', 'linux/fs/xfs/support';
+straightdiff 'xqm.h', 'cmd/xfs/include', 'linux/include/linux';
+
+# 
+# setstate
+# Implements a tri-state FSA, see comments for state transitions
+#  (knows about the way the XFS kernel code is written, & makes
+#   some assumptions so as to not need to parse generic C code).
+# Accepts one line at a time from a source file, picking out the
+#   function bodies so they can be subsequently compared.
+# 
+
+my $line;      # line number in current source file
+my $state;     # current FSA state
+my $funcbody;  # current function body (contents)
+
+sub setstate {
+       my ( $newline ) = @_;
+       $line++;
+
+       # - state 0:
+       #       if line looks like start of a function, transition to 1
+       #               & squirrel line away as line 1 of current function
+       if ($state == 0) {
+               if ($newline =~ m/^[xfs|xlog]/) {
+                       $state = 1;
+                       $funcbody = $newline;
+               }
+       }
+
+       # - state 1:
+       #       if line looks like start of a function, stay here
+       #               & squirrel line away as line 1 of current function
+       #       otherwise if line isn't start of function body,
+       #               squirrel line away as next line of current function
+       #               (args/..., but not sure this is a real function yet)
+       #       otherwise (start of function)
+       #               squirrel line away as next line of current function
+       #               transition to state 2
+       elsif ($state == 1) {
+               if ($newline =~ m/^[xfs|xlog]/) {
+                       $funcbody = $newline;
+               }
+               elsif ($newline =~ m/^\{/) {
+                       $state = 2;
+                       $funcbody .= $newline;
+               }
+       }
+
+       # - state 2:
+       #       if line looks like end of function body,
+       #               squirrel line away as last line of current function
+       #               tell someone we have a complete function ready
+       #               transition to state 0
+       #       otherwise
+       #               squirrel line away as next line of current function
+       elsif ($state == 2) {
+               $funcbody .= $newline;
+               if ($newline =~ m/^\}/) {
+                       $state = 0;
+                       return $funcbody;
+               }
+       }
+
+       else {
+               die "unknown state transition";
+       }
+       return undef;   # i.e. not at end of a function
+}
+
+sub listfuncs {
+       my ( $file ) = @_;
+       my @funcs;
+
+       $funcbody = '';
+       $state = $line = 0;
+
+       open(USER, "$file") || die "cannot open $file";
+       while (<USER>) {
+               my $func = setstate($_);
+               push @funcs, $func if (defined($func)); # store function away
+       }
+       close USER;
+       return @funcs;
+}
+
+sub hashfuncs {
+       my ( $file ) = @_;
+       my %funcs;
+
+       $funcbody = '';
+       $state = $line = 0;
+
+       open(KERN, "$file") || die "cannot open $file";
+       while (<KERN>) {
+               my $func = setstate($_);
+               if (defined($func)) {
+                       $func =~ m/^([xfs|xlog]\w+)\s*\(/;
+                       next unless defined($1);
+                       my $name = $1;
+                       if (defined($func)) {
+                               $funcs{$name} = $func;  # store function away
+                       }
+               }
+       }
+       close KERN;
+       return %funcs;
+}
+
+sub diffme {
+       my ( $sa, $sb ) = @_;
+
+       return unless defined($xdiff);
+
+       open(FILEA, "> /tmp/diff.user.$$") || die "cannot write to /tmp/diff.user.$$";
+       open(FILEB, "> /tmp/diff.kern.$$") || die "cannot write to /tmp/diff.kern.$$";
+       print FILEA $sa;
+       print FILEB $sb;
+       close FILEA;
+       close FILEB;
+       `$xdiff /tmp/diff.user.$$ /tmp/diff.kern.$$`;
+        unlink ("/tmp/diff.user.$$","/tmp/diff.kern.$$");
+}
+
+sub functiondiff {
+       my ( $file, $prefix1, $prefix2 ) = @_;
+       my $plural = '';
+       my $count = 0;
+       my $name;
+        my $found = 0;
+
+       print "\n=== Checking $file routines ===\n" unless ($quiet);
+
+       # iterate over user funcs, match up to kernel funcs
+       # 
+       my @user = listfuncs "$prefix1/$file";
+       my %kern = hashfuncs "$prefix2/$file";
+
+       foreach my $userfunc (@user) {
+               
+               $userfunc =~ m/^([xfs|xlog]\w+)\s*\(/;
+               next unless (defined($1));
+               $name = $1;
+               $count++;
+
+               if (exists($kern{$name})) {
+                       if ($userfunc ne $kern{$name}) {
+                               print "\n=== $file routines ===\n"
+                                    if (!$found++ && $quiet);
+                                    
+                               printf("\t%-35s ... ", $name);
+                               print "FAILED\n";
+                               diffme $userfunc, $kern{$name};
+                       }
+                       elsif (!$quiet) {
+                               printf("\t%-35s ... ", $name);
+                               print "ok\n";
+                       }
+               }
+               else {
+                       print "Cannot find kernel function $userfunc";
+                       print " in file $prefix2/$file\n";
+               }
+       }
+       ($count != 1) && ( $plural = 's' );
+       print "( Total: $count routine$plural checked in $file )\n" unless ($quiet);
+}
+
+# cmd/xfs/{libxfs,logprint}/* fs/xfs/*
+my @funclist = qw(
+       xfs_alloc.c  xfs_alloc_btree.c  xfs_attr_leaf.c  xfs_bit.c
+       xfs_bmap.c  xfs_bmap_btree.c  xfs_btree.c  xfs_da_btree.c
+       xfs_dir.c  xfs_dir2.c  xfs_dir2_block.c  xfs_dir2_data.c
+       xfs_dir2_leaf.c  xfs_dir2_node.c  xfs_dir2_sf.c
+       xfs_dir_leaf.c  xfs_ialloc.c  xfs_ialloc_btree.c
+       xfs_inode.c  xfs_rtalloc.c  xfs_rtbit.c xfs_mount.c
+       xfs_trans.c
+);
+
+print "\n=== Checking libxfs code ===\n";
+foreach (@funclist) {
+       functiondiff $_, 'cmd/xfs/libxfs', 'linux/fs/xfs';
+}
+print "\n=== Checking logprint code ===\n";
+functiondiff 'xfs_log_recover.c', 'cmd/xfs/logprint', 'linux/fs/xfs';
diff --git a/tools/srctest b/tools/srctest
new file mode 100644 (file)
index 0000000..a088a2b
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/sh -x
+# 
+# Simple script which does the following:
+#      o  Generates a src tarball from a WORKAREA
+#      o  Copies it over to ~/test and unpacks it
+#      o  Generates a src tarball from src tarball
+#      o  Compares the build status' ... reports problems
+#      o  removes ~/test
+# 
+
+tmpdir="$HOME/test"
+
+if [ -z "$WORKAREA" ]
+then
+       echo "WORKAREA is not set -- aborting."
+       exit 1
+fi
+
+if [ -d $tmpdir ]
+then
+       echo "$tmpdir exists already -- aborting."
+       exit 1
+else
+       mkdir $tmpdir
+       if [ ! -d $tmpdir ]
+       then
+               echo "Cannot create $tmpdir -- aborting."
+               exit 1
+       fi
+fi
+
+# 
+# Pleasantries are now out of the way, lets proceed.
+# NB: If something goes wrong we'll leave the unpacked
+# source alone for consumption by a human.
+# 
+
+_cleanup()
+{
+       if [ $status -eq 0 ]
+       then
+               rm -fr $tmpdir
+       else
+               echo "Problem?  -- leaving $tmpdir for inspection"
+       fi
+}
+
+_buildme()
+{
+       cd $1
+
+       if ./Makepkgs
+       then
+               :
+       else
+               echo Makepkgs thinks theres a problem in $1
+               exit 1
+       fi
+
+       if [ ! -f build/xfs-cmds-*.src.tar.gz ]
+       then
+               echo Makepkgs failed to create build/xfs-cmds-*.src.tar.gz
+               exit 1
+       fi
+}
+
+status=1
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# first, build from the WORKAREA
+_buildme $WORKAREA/cmd/xfs
+
+cp $WORKAREA/cmd/xfs/build/xfs-cmds-*.src.tar.gz $tmpdir
+cd $tmpdir
+tar xzf xfs-cmds-*.src.tar.gz
+rm xfs-cmds-*.src.tar.gz       # must delete for _buildme "cd" to work
+
+# now, cross check the src build
+_buildme $tmpdir/xfs-cmds-*
+
+status=0