1 #! /usr/bin/ksh -p
   2 #
   3 # CDDL HEADER START
   4 #
   5 # The contents of this file are subject to the terms of the
   6 # Common Development and Distribution License (the "License").
   7 # You may not use this file except in compliance with the License.
   8 #
   9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10 # or http://www.opensolaris.org/os/licensing.
  11 # See the License for the specific language governing permissions
  12 # and limitations under the License.
  13 #
  14 # When distributing Covered Code, include this CDDL HEADER in each
  15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16 # If applicable, add the following below this CDDL HEADER, with the
  17 # fields enclosed by brackets "[]" replaced with your own identifying
  18 # information: Portions Copyright [yyyy] [name of copyright owner]
  19 #
  20 # CDDL HEADER END
  21 #
  22 
  23 #
  24 # Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  25 # Use is subject to license terms.
  26 #
  27 # start multiple nfsh scripts on background to generate simultaneous
  28 # SETATTR requests
  29 #
  30 # Usage: 
  31 #    uidmapping_stress02 <number_of_process>  <number_of_requests_per_process>
  32 #       number_of_process - number of send_setattr_reqs process. 60 by default
  33 #       number_of_requests_per_process - number of SETATTR sent by each 
  34 #                                        process. 400 by default
  35 
  36 [ -n "$DEBUG" ] && [ "$DEBUG" != "0" ] && set -x
  37 
  38 NAME=${0##*/}
  39 CDIR=`pwd`
  40 
  41 UIDMAPENV="./uid_proc"
  42 UNINITIATED=6
  43 
  44 # set up script running environment
  45 if [ ! -f $UIDMAPENV ]; then
  46         echo "$NAME: UIDMAPENV[$UIDMAPENV] not found; test UNINITIATED."
  47         exit $UNINITIATED
  48 fi
  49 . $UIDMAPENV
  50 
  51 NUM_OF_PROCS=${1:-60}
  52 NUM_OF_REQS=${2:-400}
  53 TESTDIR="$ZONE_PATH/$NAME"
  54 
  55 function setup
  56 {
  57         # Create mount point directory
  58         mkdir -p "$TESTDIR" 2>$ERRLOG
  59         ckreturn $? "failed to create $TESTDIR" $ERRLOG "ERROR" || \
  60             return 1
  61 
  62         # Mount file system shared with root access("anon=0" option)
  63         mountit "$SERVER" "$ROOTDIR" "$TESTDIR" 4 1>$ERRLOG 2>&1
  64         ckreturn $? "failed to mount directory." $ERRLOG "ERROR"
  65         if [ $? -ne 0 ]; then
  66             rm -rf $TESTDIR
  67             return 1
  68         fi
  69 
  70         # Create test files
  71         typeset -i x=1
  72         while (( $x <= $NUM_OF_PROCS ))
  73         do
  74                 echo "test file for nfsmapid stress test" > $TESTDIR/mapid.$$.$x
  75                 if [[ ! -f $TESTDIR/mapid.$$.$x ]]; then
  76                         echo "\t Test UNINITIATED: \c"
  77                         echo "failed to create $TESTDIR/mapid.$$.$x file"
  78                         cleanup $UNINITIATED
  79                 fi
  80                 x=$(($x+1))
  81         done
  82 }
  83 
  84 function cleanup {
  85         echo "\t END TIME: `date`"
  86 
  87         # Remove test files
  88         #
  89         # Although removing files doesn't use nfsmapid service directly, it 
  90         # actually need that. The reason is when accesing a directory or a
  91         # file, Solaris performs access permission checking, which in turn 
  92         # need nfsmapid service. For this reason, the following command may
  93         # hang if nfsmapid service is stressed:
  94         #
  95         #       rm -f $TESTDIR/mapid.$$.$x
  96         #
  97         # Instead it is better to use the following r-command in this case.
  98         #
  99         execute $SERVER root "rm -f $ROOTDIR/mapid.$$.*"
 100 
 101         # Unmount file system
 102         umountit "$TESTDIR" 1>$ERRLOG 2>&1
 103         ckreturn $? "failed to unmount $TESTDIR" $ERRLOG "WARNING"
 104 
 105         # remove mount point 
 106         rm -rf $TESTDIR 1>$ERRLOG 2>&1
 107         ckreturn $? "failed to remove $TESTDIR" $ERRLOG "WARNING"
 108 
 109         # remove temporary files
 110         rm -f $TMPDIR/$NAME.$$.* 
 111 
 112         exit $1
 113 }
 114 
 115 # must run as root
 116 is_root $NAME "NFSv4 mapid stress test"
 117 
 118 setup || exit $UNINITIATED
 119 
 120 echo "$NAME{1}: generating simultaneous kernel upcall to stress nfsmapid\n"
 121 echo "\t START TIME: `date`"
 122 
 123 # export the common domain for the test
 124 Cdomain=$(cat /var/run/nfs4_domain)
 125 
 126 # Start children processes to stress nfsmapid
 127 x=1
 128 while [ $x -le $NUM_OF_PROCS ]
 129 do 
 130         # start the x-th instance of send_setattr_reqs.tcl
 131         $TESTROOT/nfsh send_setattr_reqs $ROOTDIR/mapid.$$.$x $NUM_OF_REQS \
 132              >$TMPDIR/$NAME.$$.$x 2>&1 &
 133 
 134         # record the child's pid
 135         pid_list[$x]=$!
 136 
 137         x=$(($x+1))
 138 done
 139 
 140 [ "$DEBUG" -eq "1" ] && echo "$NUM_OF_PROCS processes started: ${pid_list[*]}"
 141 
 142 # Check if the server is overcome by the requests from the client.
 143 #
 144 # For each rpc call, there is a timer associated with it. If the client
 145 # doesn't get reply from server and the timer expires, the rpc call fails.
 146 # In that case, Solaris nfs client will keep trying until that it succeeds.
 147 # If the server keeps not responding, the client hangs.(notes: a simple 
 148 # experiment shows the default timeout value of a rpc call on solaris is 
 149 # 120 seconds)
 150 #
 151 # nfsh is different from Solaris nfs client in that it doesn't retry. Instead,
 152 # the Compound command just fails and returns. That means, nfsh client never
 153 # really hangs. In the worst situation(no reply from server), it exits after
 154 # the rpc call timer expires.
 155 #
 156 # To check if the server works well with nfsh clients, we can check the clients'
 157 # exit status. If a client gets reply from the server, it exits successfully.
 158 # Otherwise, the RPC call timer expires and we think the client "hangs".
 159 x=1
 160 failed=0
 161 while [ $x -le $NUM_OF_PROCS ]
 162 do 
 163         # get the x-th child's pid
 164         pid=${pid_list[$x]}
 165 
 166         # wait until it exits and get its exit status
 167         wait $pid
 168         status=$?
 169 
 170         if [ "$status" != "0" ]; then
 171                 if [ "$DEBUG" == "1" -o "$failed" == "0" ]; then
 172                         echo "\nERROR: process $pid failed!"
 173                         echo "------------- $TMPDIR/$NAME.$$.$x -------------"
 174                         cat $TMPDIR/$NAME.$$.$x
 175                         echo "-------------------- END ----------------------"
 176                 fi
 177                 failed=$(( failed + 1))
 178         fi
 179 
 180         x=$(($x+1))
 181 done 
 182 
 183 # Print all out log files in debug mode
 184 
 185 if [ "$DEBUG" -eq "1" ]; then
 186         x=1
 187         while [ $x -le $NUM_OF_PROCS ]
 188         do
 189                 echo "------------- $TMPDIR/$NAME.$$.$x -------------"
 190                 cat $TMPDIR/$NAME.$$.$x
 191                 echo "-------------------- END ----------------------"
 192                 x=$(($x+1))
 193         done
 194 fi
 195 
 196 
 197 # Print test result
 198 
 199 if [ "$failed" -eq 0 ]; then 
 200         echo "\t Test PASS: test run completed successfully"
 201         cleanup $PASS
 202 else 
 203         echo "\t Test FAIL: Total <$failed> children processes failed"
 204         cleanup $FAIL
 205 fi
 206