#!/bin/bash shopt -s extglob eR='\e[31m';eG='\e[32m';eY='\e[33m';eB='\e[34m';eN='\e[0m' function eecho () { C=$1; shift echo -e "$C$*$eN" } function techo () { C=$1; shift echo -en "$C$*$eN" } function ececho () { rc=$1; shift id=$1; shift if [ $rc -eq 0 ]; then [ $terse -ne 0 ] && techo $eG "$id. " || \ eecho $eG "$id# succeeded." else [ $terse -ne 0 ] && techo $eR "$id* " || \ eecho $eR "$id# failed." fi return $rc } function eexec () { local id=`printf "[%3.3s]" $1`; shift local eret=$1; shift echo -e "\t$*" >$outdev if [ $terse -gt 0 ]; then eval $* 1>/dev/null 2>&1 3>&1 else eval $* 3>&2 1>$outdev 2>$errdev fi local ret=$? [ -n "$eret" -a "$eret" -ne 0 ] \ && ret=$(( ret - eret )) ececho $ret $id return $ret } function go_xid () { local xid=$1; shift if [ "$version" == "24" -a $xid -gt 0 ]; then echo -e "\tchcontext --ctx $xid $*" chcontext --ctx $xid $* elif [ $xid -gt 1 ]; then echo -e "\tvcontext --create --xid $xid -- $*" vcontext --create --xid $xid -- $* elif [ $xid -eq 1 ]; then echo -e "\tvcontext --migrate --xid 1 -- $*" vcontext --migrate --xid 1 -- $* else echo -e "\t$*" $* fi } function do_xid_touch () { local path="$1"; shift local pos=1 local ret=0 while [ $# -gt 0 ]; do local file="$path/file_$pos" echo -e "\ttouch $file: $1" go_xid $1 "touch $file" local rc=$? [ $rc -eq 0 ] || { ret=1; eecho $eR "\ttouch $file: $1 [$rc]" 1>&3; } shift pos=$[pos+1]; done return $ret } function do_xid_verify () { local path="$1"; shift local pos=1 ret=0 while [ $# -gt 0 ]; do local file="$path/file_$pos" val=`lsxid -d $file | awk '{print $1}'` echo -e "\tverify $file: $1 = $val" [ "$val" -eq "$1" ] || { ret=1; eecho $eR "\tverify $file: $1 = $val" 1>&3; } shift pos=$[pos+1]; done return $ret } function do_xid_change () { local path="$1"; shift local pos=1 ret=0 while [ $# -gt 0 ]; do local file="$path/file_$pos" echo -e "\tchange $file: $1" chxid -c $1 $file local rc=$? [ $rc -eq 0 ] || { ret=1; eecho $eR "\tchange $file: $1 [$rc]" 1>&3; } shift pos=$[pos+1]; done return $ret } function do_xid_read () { local path="$1"; shift local pos=1 ret=0 while [ $# -gt 1 ]; do local file="$path/file_$pos" local x=0 xx="" for x in 0 1 2 $1; do go_xid $x cat "$file" >/dev/null local rc=$? [ $rc -eq 0 ] && xx="$xx." || xx="$xx^" done [ "$xx" == "$2" ] || { ret=1; eecho $eR "\tread $file: $1 [$xx:$2]" 1>&3; } shift; shift pos=$[pos+1]; done return $ret } function do_xid_write () { local path="$1"; shift local pos=1 ret=0 while [ $# -gt 1 ]; do local file="$path/file_$pos" local x=0 xx="" for x in 0 1 2 $1; do echo "test-$pos" | go_xid $x tee "$file" >/dev/null local rc=$? [ $rc -eq 0 ] && xx="$xx." || xx="$xx^" done [ "$xx" == "$2" ] || { ret=1; eecho $eR "\twrite $file: [$xx:$2] $1" 1>&3; } shift; shift pos=$[pos+1]; done return $ret } function do_xattr_barrier () { local path="$1"; shift local bdir="$1"; shift local ret=0 local x=0 xx="" for x in 0 1 2; do go_xid $x chmod +x "$bdir" local rc=$? chmod -x "$bdir" [ $rc -eq 0 ] && xx="$xx." || xx="$xx^" done [ "$xx" == "$1" ] || { ret=1; eecho $eR "\tbarrier $bdir: [$xx:$1]" 1>&3; } return $ret } function do_xattr_iunlink () { local path="$1"; shift local file="$1"; shift local ret=0 local x=0 xx="" for x in 0 1 2; do go_xid $x chmod +x "$file" local rc=$? chmod -x "$file" [ $rc -eq 0 ] && xx="$xx." || xx="$xx^" done [ "$xx" == "$1" ] || { ret=1; eecho $eR "\tiunlink chmod $file: [$xx:$1]" 1>&3; } return $ret } function do_xattr_cowbreak () { local path="$1"; shift local file="$1"; shift local ret=0 local x=0 xx="" for x in 0 1 2; do ln "$file" "$file.$x" go_xid $x chmod +x "$file.$x" local rc=$? rm -f "$file.$x" [ $rc -eq 0 ] && xx="$xx." || xx="$xx^" done [ "$xx" == "$1" ] || { ret=1; eecho $eR "\tiunlink chmod $file: [$xx:$1]" 1>&3; } return $ret } function do_xattr_verify () { local path="$1"; shift local vcmd="$1"; shift local pos=1 ret=0 while [ $# -gt 0 ]; do local file="$1"; shift val=`$vcmd -d $file | awk '{print $1}'` echo -e "\tverify $file: $1 = $val" case $val in $1) ;; *) ret=1 eecho $eR "\tverify $file: $1 ~ $val" 1>&3 ;; esac shift done return $ret } function do_dlimit_add () { local path="$1"; shift local space="$1"; shift local inodes="$1"; shift local xid="$1"; shift local ret=0 vdlimit --xid "$xid" --set space_used=0 \ --set space_total="$space" --set inodes_used=0 \ --set inodes_total="$inodes" \ --set reserved=0 "$path" || ret=1 return $ret } function do_dlimit_save () { local path="$1"; shift local xid="$1"; shift local space_used=0 local inodes_used=0 _DLIMIT_DF_SPACE=`df "$path" | awk '$3 ~ /^[0-9]+$/ { if (NF == 5) { print $2 } else { print $3 } }'` _DLIMIT_DF_INODES=`df -i "$path" | awk '$3 ~ /^[0-9]+$/ { if (NF == 5) { print $2 } else { print $3 } }'` eval `vdlimit --xid "$xid" "$path" | grep _used=` _DLIMIT_VD_SPACE="$space_used" _DLIMIT_VD_INODES="$inodes_used" return $ret } function do_dlimit_verify () { local path="$1"; shift local xid="$1"; shift local ret=0 local space_used=0 local inodes_used=0 local df_space=0 local df_inodes=0 df_space=`df "$path" | awk '$3 ~ /^[0-9]+$/ { if (NF == 5) { print $2 } else { print $3 } }'` df_inodes=`df -i "$path" | awk '$3 ~ /^[0-9]+$/ { if (NF == 5) { print $2 } else { print $3 } }'` eval `vdlimit --xid "$xid" "$path" | grep _used=` || ret=1 local df_delta_space=`expr $df_space - $_DLIMIT_DF_SPACE` local df_delta_inodes=`expr $df_inodes - $_DLIMIT_DF_INODES` local vd_delta_space=`expr $space_used - $_DLIMIT_VD_SPACE` local vd_delta_inodes=`expr $inodes_used - $_DLIMIT_VD_INODES` test "$df_delta_space" -eq "$vd_delta_space" || ret=1 test "$df_delta_inodes" -eq "$vd_delta_inodes" || ret=1 return $ret } function do_dlimit_space () { local path="$1"; shift local size="$1"; shift local xid="$1"; shift go_xid "$xid" rm -f "$path/space-$xid"* go_xid "$xid" dd if=/dev/zero of="$path/space-$xid" bs=1k count=$size || \ return 1 return 0 } function do_dlimit_cowtest () { local path="$1"; shift local size="$1"; shift local breaks="$1"; shift local xid="$1"; shift go_xid "$xid" rm -f "$path/cow-$xid"* go_xid "$xid" dd if=/dev/zero of="$path/cow-$xid" bs=1k count=$size || return 1 setattr --iunlink "$path/cow-$xid" local i=0 while [ $i -lt $breaks ]; do go_xid "$xid" ln "$path/cow-$xid" "$path/cow-$xid-$i" || return 1 go_xid "$xid" touch "$path/cow-$xid-$i" || return 1 i=$[i+1] done return 0 } function do_dlimit_inodes () { local path="$1"; shift local files="$1"; shift local xid="$1"; shift go_xid "$xid" rm -f "$path/inodes-$xid"* local i=1 while [ $i -lt $files ]; do go_xid "$xid" touch "$path/inodes-$xid-$i" || return 1 i=$[i+1] done return 0 } function do_dlimit_destroy () { local path="$1"; shift local xid="$1"; shift vdlimit --remove --xid "$xid" "$path" 2>/dev/null rm -fr "$path/$xid" return 0 } function do_sync () { sync sleep 6 } function do_fsck () { local fs=$1 local dev="$2" local done=0 ret=0 until [ $done -ne 0 ]; do fsck.$fs -a -f $dev ret=$? if [ $ret -eq 8 ]; then echo . continue fi done=1; done return $ret; } function do_test () { local fs=$1 local mopt=$2 local xopt="$mopt,$tagxid" local X="-" do_sync [ $test_xid -gt 0 ] && { [ $terse -ne 0 ] && echo "($fs format)" eecho $eB "xid related tests ..." local xids="0 1 255 256 666" local rpat="0 .... 1 ..^. 255 ..^." local wpat="0 .... 1 ..^. 255 ..^." eexec 001 0 "mount -t $fs -o $mopt $DEV $MNT 3>&2" || return eexec 002 32 "mount -o remount,$xopt $DEV 3>&2" eval "umount $DEV 3>&2" eexec 011 0 "mount -t $fs -o $xopt $DEV $MNT 3>&2" || return eexec 012 0 "do_xid_touch $MNT $xids" eexec 014 0 "do_xid_verify $MNT $xids" eexec 015 0 "do_xid_read $MNT $rpat" eexec 019 0 "umount $DEV 3>&2" [ $terse -ne 0 ] && echo "" eval "mount -t $fs -o $xopt $DEV $MNT 3>&2" || return eexec 020 0 "do_xid_verify $MNT $xids" eexec 021 0 "mount -o remount,$xopt $DEV 3>&2" eexec 022 0 "do_xid_verify $MNT $xids" eexec 023 0 "mount -o remount,$mopt $DEV 3>&2" eexec 024 0 "do_xid_verify $MNT $xids" eexec 025 0 "do_xid_read $MNT $rpat" eexec 026 0 "do_xid_verify $MNT $xids" eexec 027 0 "do_xid_write $MNT $wpat" eexec 028 0 "do_xid_verify $MNT $xids" [ $terse -ne 0 ] && echo "" local xids="200 201 256 254 777" local rpat="200 ..^." local wpat="200 ..^. 201 ..^." eexec 033 0 "do_xid_change $MNT $xids" eexec 034 0 "do_xid_verify $MNT $xids" eexec 035 0 "do_xid_read $MNT $rpat" eexec 037 0 "do_xid_write $MNT $wpat" eval "umount $DEV 3>&2" [ $terse -ne 0 ] && echo "" X="X" } [ $test_xattr -gt 0 ] && { eecho $eB "xattr related tests ..." case $version in 24) local attr_B="---BU--" attr_b="---bu--" local attr_U="----U--" attr_u="----u--" local lsattr_B="-+(-)-t*(-)" local lsattr_U="-+(-)-i-+(-)-t*(-)" ;; *) local attr_B="---Bui-" attr_b="---bui-" local attr_U="----UI-" attr_u="----ui-" local lsattr_B="-+(-)?(A)+(-)" local lsattr_U="-+(-)-i-+(-)?([AE])+(-)" ;; esac local dpath="$MNT/dir_$$" local fpath="$MNT/file_$$" eexec 101 0 "mount -t $fs -o $mopt $DEV $MNT 3>&2" || return eval "mkdir -p $dpath" eexec 102 0 "setattr --barrier $dpath" eexec 103 0 "do_xattr_verify $MNT showattr $dpath $attr_B" eexec 104 0 "do_xattr_verify $MNT lsattr $dpath $lsattr_B" eexec 106 0 "do_xattr_barrier $MNT $dpath .^^" eexec 108 0 "setattr --~barrier $dpath" eexec 109 0 "do_xattr_verify $MNT showattr $dpath $attr_b" eval "rmdir $dpath" [ $terse -ne 0 ] && echo "" eval "echo five > $fpath" eval "ln $fpath $fpath.x" eexec 112 0 "setattr --iunlink $fpath" eexec 113 0 "do_xattr_verify $MNT showattr $fpath $attr_U" eexec 114 0 "do_xattr_verify $MNT lsattr $fpath $lsattr_U" eexec 115 0 "ln $fpath $fpath.y" [ $KCOW -lt 2 ] && \ eexec 116 0 "do_xattr_iunlink $MNT $fpath $ER" eexec 117 0 "go_xid 2 rm -f $fpath" eexec 118 0 "setattr --~iunlink $fpath.x" eexec 119 0 "do_xattr_verify $MNT showattr $fpath.x $attr_u" eval "rm -f $fpath.y $fpath.x" [ $terse -ne 0 ] && echo "" eval "mkdir -p $dpath" eval "setattr --barrier $dpath" eval "echo five > $fpath" eval "setattr --iunlink $fpath" eval "umount $DEV 3>&2" eval "mount -t $fs -o $mopt $DEV $MNT 3>&2" || return eexec 121 0 "do_xattr_verify $MNT showattr $dpath $attr_B" eexec 122 0 "do_xattr_verify $MNT lsattr $dpath $lsattr_B" eexec 123 0 "do_xattr_verify $MNT showattr $fpath $attr_U" eexec 124 0 "do_xattr_verify $MNT lsattr $fpath $lsattr_U" eexec 125 0 "do_xattr_cowbreak $MNT $fpath ..." eexec 128 0 "umount $DEV 3>&2" eexec 129 0 "do_fsck $fs $DEV 3>&2" [ $terse -ne 0 ] && echo "" if [ $KCOW -ge 2 ]; then eval "mount -t $fs -o $mopt $DEV $MNT 3>&2" || return eexec 138 0 "umount $DEV 3>&2" eexec 139 0 "do_fsck $fs $DEV 3>&2" fi [ $terse -ne 0 ] && echo "" } [ $test_dlimit -gt 0 ] && { eecho $eB "disk limit related tests ..." local xids="300 301 600 900" eval "mount -t $fs -o $xopt $DEV $MNT 3>&2" || return eval "do_dlimit_destroy $MNT $xids" eexec 201 0 "do_dlimit_add $MNT 32 5 $xids" eval "do_dlimit_save $MNT $xids" eexec 202 0 "do_dlimit_space $MNT 16 $xids" eexec 203 0 "do_dlimit_verify $MNT $xids" eval "do_dlimit_save $MNT $xids" eexec 204 0 "do_dlimit_inodes $MNT 3 $xids" eexec 205 0 "do_dlimit_verify $MNT $xids" eval "do_dlimit_save $MNT $xids" eexec 206 1 "do_dlimit_space $MNT 33 $xids" eexec 207 1 "do_dlimit_inodes $MNT 6 $xids" eexec 208 0 "do_dlimit_verify $MNT $xids" if [ $KCOW -ge 1 ]; then [ $terse -ne 0 ] && echo "" eval "do_dlimit_destroy $MNT $xids" eexec 211 0 "do_dlimit_add $MNT 128 10 $xids" eval "do_dlimit_save $MNT $xids" eexec 212 0 "do_dlimit_cowtest $MNT 5 9 $xids" eexec 213 0 "do_dlimit_verify $MNT $xids" eval "do_dlimit_save $MNT $xids" eexec 214 1 "do_dlimit_cowtest $MNT 43 3 $xids" eexec 216 0 "do_dlimit_verify $MNT $xids" eval "rm -f $MNT/cow-300*" eexec 216 0 "do_dlimit_verify $MNT $xids" eexec 215 1 "do_dlimit_cowtest $MNT 3 43 $xids" eexec 216 0 "do_dlimit_verify $MNT $xids" fi eval "umount $DEV 3>&2" [ $terse -ne 0 ] && echo "" } return 0 } verbose=0 terse=0 test_xid=0 test_xattr=1 test_dlimit=0 version="26" tagxid="tagxid" DEV="" MNT="/test" NFS="127.0.0.1:/nfs" FSL="ext2,ext3,xfs,reiser,jfs" mntopt="rw" nfsopt="vers=3,hard,intr,tcp,sync" while getopts ":hlnotvxdD:F:M:N:O:" option; do case $option in h) # help cat << EOF Usage: $cmdname [OPTION]... -h help -l legacy barrier code -n no color codes -t terse output -o mount options [$mntopt] -v be verbose -x xid tagging tests -d disk limit tests -D device to use [$DEV] -F filesystems -M mount point [$MNT] -N nfs source [$NFS] -O nfs options [$nfsopt] examples: $cmdname -F ext2 # check fs $cmdname -v # verbose test EOF exit 0 ;; v) # be verbose verbose=$(( verbose + 1 )) ;; x) # test xid tagging test_xid=1; ;; d) # test disk limits test_dlimit=1 ;; l) # old barrier code version="24"; # tagxid="tagctx"; ;; n) # no color eR='';eG='';eY='';eB='';eN='' nocolor=1; ;; o) # mount options mntopt="$OPTARG" ;; t) # terse output terse=1 ;; D) # device DEV="$OPTARG" ;; F) # single fs FSL="$OPTARG" ;; M) # mount point MNT="$OPTARG" ;; N) # nfs options NFS="$OPTARG" ;; O) # nfs mount options nfsopt="$OPTARG" ;; esac done shift $(($OPTIND - 1)) if [ -z "$DEV" ]; then eecho $eR "Please specify a device!" >&2 exit 1 elif [ ! -e "$DEV" ]; then eecho $eR "Please specify a valid device!" >&2 exit 1 fi if [ ! -d "$MNT" ]; then eecho $eR "Please specify an existing mountpoint or create \"$MNT\"!" >&2 exit 1 fi outdev="/dev/null" [ $verbose -gt 1 ] && outdev="/dev/stdout" errdev="/dev/null" [ $verbose -gt 0 ] && errdev="/dev/stderr" eecho $eY "Linux-VServer FS Test [V0.15] Copyright (C) 2005-2007 H.Poetzl" KERN=`uname -srm` CHCV=`chcontext --version 2>&1` CHCO=`echo -e "$CHCV" | sed -n '/--\|version/ {s/.*\ \([0-9][0-9.]*\).*/\1/g;p;q;}'` INFO=(`sed 's/.*:\t//' /proc/virtual/info 2>/dev/null || echo ''`) KCIN="$[ 16#${INFO[2]} ]"; KCTM=$[ (KCIN >> 24) & 7 ]; KCOW=$[ (KCIN >> 8) & 3 ]; case $KCTM in 0) TAGI="None" ;; 1) TAGI="UID16" ;; 2) TAGI="GID16" ;; 3) TAGI="ID24" ;; 4) TAGI="Internal" ;; 5) TAGI="Runtime" ;; *) TAGI="Unknown" ;; esac echo "$KERN/$CHCO" echo "VCI: $INFO ${INFO[1]} ${INFO[2]} ($TAGI)" fsl=`echo $FSL | tr ',' ' '` for fs in $fsl; do echo "---" eecho $eY "testing $fs filesystem ..." case $fs in nfs) do_test nfs "$nfsopt,$mntopt" continue ;; ext2|ext3) mkfsopt=""; testopt="$mntopt"; ;; xfs|jfs) mkfsopt="-f"; testopt="$mntopt"; ;; reiser*) mkfsopt="-f"; testopt="attrs,$mntopt" fs="reiserfs"; ;; ocfs2*) mkfsopt=""; testopt="$mntopt" fs="ocfs2"; ;; gfs2*) mkfsopt=""; testopt="$mntopt" fs="gfs2"; ;; jffs2*) mkfsopt="--pad=65536 --root=$MNT -o "; testopt="$mntopt" fs="jffs2"; ;; *) eecho $eR "unknown filesystem $fs." continue ;; esac yes | mkfs.$fs $mkfsopt $DEV 1>$outdev 2>$errdev rc=$?; ececho $rc "[000]" [ $rc -gt 0 ] && echo "($fs format failed)" && continue do_test "$fs" "$testopt" [ $terse -ne 0 ] && echo "" done