#!/usr/bin/ksh # # defrag_vxfs.ksh # # This script evaluates the degree of fragmentation for vxfs # filesystems on a server. # # Olivier Masse, January 11th 2001 # # Modifications: # # September 9th 2002 O. Masse # ---------------------------- # - Added option -e to exclude filesystems smaller than 256kb (hardcoded - # can be modified to your taste) # - Modification of the rule that determines if a filesystem is fragmented: # when it is over 95% full, it does not check free blocks # - Added -v option for more verbose output # # May 8th 2002 O. Masse # --------------------------- # - Added options -r2 and -r3 to send an email of only fragmented # filesystems. # - Added return codes # - Conversion to a tivoli-friendly script: Added functions techo and # tfilter that are triggered when the script is invoked with -t. # # Novemebr 16th 2004 O. Masse # ------------------------------ # - Re-released under the GPL and translated in english # - Replaced deprecated `xx` calls with $(xx) # # Februrary 21st 2005 O. Masse # ------------------------------ # - Patch submitted by Bruce Gillespie: Added support for AIX # - Corrected a status message which wasn't translated yet # - Changed name of $percentfree variable to $percentfull # # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # TEMPFILE="/tmp/$(basename $0).$$" returncode=0 progname=$(basename $0) # Tivoli echo techo() { [ "$TIVOLI" ] && echo "# $*" || echo "$*" } # Tivoli filter tfilter() { while read line do [ "$TIVOLI" ] && echo "# $line" || echo "$line" done } # Verbose print verbose() { [ "$VERBOSE" ] && techo $* } # Checks the fragmentation of a filesystem checkfrag() { frag_status=0 filesystem="$1" percentfull=$(df -k $filesystem | awk '/allocation used/ {print $1; exit;}') if (nice -19 $FSADM -E $filesystem > $TEMPFILE.2 2>$TEMPFILE.3) then grep " % " $TEMPFILE.2 > $TEMPFILE else verbose "$(cat $TEMPFILE.3)" verbose "Problem with $FSADM -E $filesystem" return 4 fi cat $TEMPFILE | awk '{a=$10; getline; b=$10; print a " " b}' | read a b c=$((100 - $a)) verbose "$(cat $TEMPFILE)" # From the Veritas vxfs docs: # An unfragmented file system will have the following characteristics: # - Less than 5 percent of free space in extents of less than 64 blocks in length # - Less than 1 percent of free space in extents of less than 8 blocks in length # - More than 5 percent of the total file system size available as free extents in # lengths of 64 or more blocks if [ "$a" -lt "5" -a "$b" -lt "1" -a "$c" -gt "5" ] then frag_status=1 verbose "$filesystem is not fragmented." fi # From the Veritas vxfs docs: # A badly fragmented filesystem will have one or more of the following # characteristics: # - More than 50 percent of free space in extents of less than 64 blocks in length # - Greater than 5 percent of free space in extents of less than 8 blocks in length # - Less than 5 percent of the total file system size available as free extents in # lengths of 64 or more blocks if [ "$a" -gt "50" -o "$b" -gt "5" -o "$c" -lt "5" ] then frag_status=2 if [ "$a" -gt "50" ] then verbose "- More than 50 percent of free space in extents of less than 64 blocks in length." fi if [ "$b" -gt "5" ] then verbose "- Greater than 5 percent of free space in extents of less than 8 blocks in length." fi if [ "$c" -lt "5" ] then verbose "- Less than 5 percent of the total file system size available as free extents in lengths of 64 or more blocks." fi if [ "$percentfull" -ge "95" ] then verbose "But it doesn't matter, since the filesystem is over ${percentfull}% full." frag_status=0 else verbose "$filesystem is BADLY fragmented." fi fi # So, we concluded that a filesystem will be moderately fragmented if # we have not satisfied the two previous conditions. if [ "$frag_status" = "0" ] then frag_status=3 if [ "$a" -ge "5" ] then verbose "- More than 5 percent of free space in extents of less than 64 blocks in length." fi if [ "$b" -ge "1" ] then verbose "- More than 1 percent of free space in extents of less than 8 blocks in length." fi if [ "$c" -le "5" ] then verbose "- 5 percent at most of the total file system size available as free extents in lengths of 64 or more blocks" fi if [ "$percentfull" -ge "95" ] then verbose "But it doesn't matter, since the filesystem is over ${percentfull}% full." frag_status=0 else verbose "$filesystem is moderately fragmented." fi fi return $frag_status } usage() { techo techo "Usage: $progname [-r|-r2|-r3|-d] [-t] [-v] [-e] [-f filesystem]" techo techo "-r : Print a fragmentation report" techo "-r2: Print only moderately and badly fragmented filesystems" techo "-r3: Print only badly fragmented filesystems" techo "-t : Print in a tivoli-friendly manner" techo "-d : Defragment automatically if needed" techo "-e : Exclude filesystems smaller than 256Kb" techo "-v : Verbose mode" techo "-f : Specify a particular filesystem. (all are checked by default)" techo techo "Return codes: 1 if one filesystem or more are moderately fragmented." techo " 2 if one filesystem or more are badly fragmented." techo techo } clean() { rm $TEMPFILE 2>/dev/null rm $TEMPFILE.* 2>/dev/null } cleanintr() { techo "Interrupt, cleaning..." rm $TEMPFILE 2>/dev/null rm $TEMPFILE.* 2>/dev/null exit } if [ "$LOGNAME" != "root" ] then techo "Sorry, you must be root." exit fi # Traps on signals 2 and 15 in case we interrupt the script with a kill or CTRL-C trap cleanintr 2 15 # Here we find the fsadm to use depending on the OS arch="$(uname)" case $arch in SunOS) FSADM="/usr/lib/fs/vxfs/fsadm";; HP-UX) FSADM="/usr/sbin/fsadm -F vxfs";; AIX) FSADM="/opt/VRTSvxfs/sbin/fsadm -V vxfs" export PATH=/opt/VRTSvxfs/sbin:$PATH;; *) techo "Architecture $arch not supported, sorry."; exit;; esac unset VERBOSE while [ "$1" != "" ] do case "$1" in -v) VERBOSE="true";; -d) DEFRAG="true";; -r) REPORT="true";; -r2) SHOWFRAG="true";; -r3) SHOWVERYFRAG="true";; -e) EXCLUDESMALL="true";; -t) TIVOLI="true";; -f) shift; FILESYSTEM="$1";; *) techo "Option $i unknown."; usage; exit;; esac shift done if [ ! "$DEFRAG" -a ! "$REPORT" -a ! "$SHOWFRAG" -a ! "$SHOWVERYFRAG" ] then usage exit fi if [ ! "$FILESYSTEM" ] then FILESYSTEM="$(df -F vxfs | awk '{print $1}')" fi for i in $FILESYSTEM do verbose "" unset skip if [ "$EXCLUDESMALL" ] then size=$(df -k $i | grep "total allocated" | head -1 | sed 's/.*:[[:space:]]*//g' | awk '{print $1}') if [ "$size" -lt "262144" ] then verbose "$i excluded, less than 256Mb" skip="true" fi fi if [ ! "$skip" ] then verbose "Checking $i..." checkfrag $i case "$?" in "1") techo "not fragmented: $filesystem" >> $TEMPFILE.notfrag;; "2") techo "BADLY fragmented: $filesystem" >> $TEMPFILE.veryfrag; FSTODEFRAG="$FSTODEFRAG $filesystem"; returncode=2;; "3") techo "fragmented: $filesystem" >> $TEMPFILE.frag; FSTODEFRAG="$FSTODEFRAG $filesystem"; [ "$returncode" -ne "2" ] && returncode=1;; "4") techo "error fsadm: $filesystem" >> $TEMPFILE.error; esac fi done if [ "$REPORT" ] then techo techo "vxfs fragmentation report of $(hostname)" techo "====================================================" techo for file in $TEMPFILE.veryfrag $TEMPFILE.frag $TEMPFILE.notfrag $TEMPFILE.error do [ -s $file ] && cat $file done fi if [ "$SHOWFRAG" ] then [ -s $TEMPFILE.veryfrag -o -s $TEMPFILE.frag ] && techo "Fragmentation seen on these filesystems:" [ -s $TEMPFILE.veryfrag ] && cat $TEMPFILE.veryfrag [ -s $TEMPFILE.frag ] && cat $TEMPFILE.frag fi if [ "$SHOWVERYFRAG" ] then if [ -s $TEMPFILE.veryfrag ] then techo "Fragmentation seen on these filesystems:" cat $TEMPFILE.veryfrag fi fi if [ "$DEFRAG" ] then for filesystem in $FSTODEFRAG do if [ "$i" != "" ] then techo techo techo "Defragmenting $filesystem..." techo if [ "$VERBOSE" ] then $FSADM -e -E -s $filesystem | tfilter $FSADM -d -D -s $filesystem | tfilter else $FSADM -e $filesystem | tfilter $FSADM -d $filesystem | tfilter fi fi done fi clean trap - 2 15 [ "$TIVOLI" ] && echo $returncode || exit $returncode