From: Nathan Scott Date: Mon, 15 Jan 2001 05:23:30 +0000 (+0000) Subject: cmd/xfs/tools/README.auto-qa 1.1 Renamed to cmd/xfstests/tools/README.auto-qa X-Git-Tag: v1.1.0~1341 X-Git-Url: http://git.apps.os.sepia.ceph.com/?p=xfstests-dev.git;a=commitdiff_plain;h=08299f237084fe0544d5f1067ad56c9e5b04915a cmd/xfs/tools/README.auto-qa 1.1 Renamed to cmd/xfstests/tools/README.auto-qa --- diff --git a/tools/README.auto-qa b/tools/README.auto-qa new file mode 100644 index 00000000..fa36165a --- /dev/null +++ b/tools/README.auto-qa @@ -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 index 00000000..861c721b --- /dev/null +++ b/tools/auto-qa @@ -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 index 00000000..e64df100 --- /dev/null +++ b/tools/db-walk @@ -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 \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 index 00000000..fd6d4af0 --- /dev/null +++ b/tools/fs-walk @@ -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 \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 index 00000000..7ccc6c9e --- /dev/null +++ b/tools/interop @@ -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 [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 index 00000000..70c1fdf7 --- /dev/null +++ b/tools/srcdiff @@ -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 () { + 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 () { + 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 index 00000000..a088a2ba --- /dev/null +++ b/tools/srctest @@ -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