#!/bin/ksh # # sdreclaim - script that automates manual reclmation for # single drive sequential access storage pools # Adapted from: # mrecsv - Manual Reclamation of Sequential access Volumes # Written By : Van Stokes, Jr 11/13/1995 # Last Updated : Mike Kaczmarski, IBM 1/3/1996 # # # DESCRIPTION: # This script was made available by Van Stokes Jr, and modified slightly # by IBM to provide a means for reclamation in ADSM single-drive # sequential storage pools. # # SUPPORT: # This script is being provided AS IS - no waranties or support is # provided. There are no warranties, express or implied, including # the warranties of merchantability and fitness for a particular # purpose. # # ***************** Work Flow - What is happening? ****************** # # The ADSM server, both version 1.0+ and 2.0+ are not capable of doing a # reclamation on a sequential access devices (tape, optical, etc) that only # have one drive. Nor, to my knowledge, do they have any plans to make it # possible to do so. Because I was in a bind and I didn't have the time to # manually move data between volumes all the time, I wrote this script to # automate this proceedure - Manual Reclamation of Sequential Access Volumes. # # Requirements: # Sequential Access Media - tape, optical, etc. # Random Access Media - Device Class of Disk # Storage Pool for Manual Reclamation # # How it works................... # The script finds volumes on your sequential storage pool (VSP) whose # occupancy is *LOWER* than 100-(Reclamation Threshold) and are in # the 'filled state'. # When the script encounters such a volume, it then proceeds to move the # data off of the VSP volume on to the manual reclamation storage pool (MRSP). # # If the MRSP gets full, ADSM will (if set) automaticaly migrate the data # back to the VSP thus consolidating the data. # # The MSRP must have enough available space to hold the reclaimable # data that need to be moved to emtry a volume. # # If the MRSP doesn't get full, thats OK. The script will automatically move # the data back to the VSP - again, consildating the data. # # And the process repeats itself until there are no more volumes in the VSP # below the "Reclamation Threshold". # # It's really a "round-robin". Data is moved from a partially full sequential # access media volume (tape, optical, etc) to a random access medial volume # (disk) and then back to the sequential access media (tape, optical, etc). # # The goal is to get sequential access medial volumes that are not # completely full and consolidate the data on to fewer volumes. # # # !!!!!!!!!!!!!!!!!!!!!!!!!!!Notice!!!!!!!!!!!!!!!!!!!!!!!!!!! # YOU MUST DO THE FOLLOWING to ensure the proper operation of this script: # # In this Script, you must set: # ADSM_ID - The Admin ID to log into ADSM. Ensure proper permissions. # ADSM_PASSWD - The Admin ID's password to use # # MRSP - The *DISK* storage pool name to use for reclamation of VSP. # - This is were the data will be moved to temporarily. # - This storage pool *CAN NOT* be used by anything else. # - This storage pool should migrate to your VSP (see next item). # - Cache'ing should be turned off. # - Suggested Migration Thresholds: Low: 0%, High: 98% # # VSP - The name of the Storage Pool *TO* Reclamate. # - i.e. Your Tape or Optical storage pool name. # # On the ADSM server, you must set: # Reclamation Threshold - This must be set on your VSP storage pool. # # Next Storage Pool - This must be set on your MRSP storage pool. # - This should be your VSP, but doesn't have to be. # # In this script, Other settings to check: # SLTF - Send logs(status) to the log file (Y or N)? # SLTS - Send logs(status) to the screen (Y or N)? # LOG - Location of the log file (check path). # LCKF - Location of the lock file (check path). # REC_TABLE - Reclamation Table (check path). # # ***************** Macro's that you change per system **************** # # # Login and Password to use when issuing ADSM commands. ADSM_ID="adminuser" ADSM_PASSWD="adminpassword" # # Manual Reclamation Storage Pool name (where to move the data to). MRSP="MRSP" # # Storage Pool Name to Reclamate VSP="FILEPOOL" # # Send logs(status) to the log file (Y or N)? SLTF="Y" # # Send logs(status) to the screen (Y or N)? SLTS="Y" # # Location and Name of the Log File LOG="/tmp/adsm.rec.log" # # Lock file to keep another instance of this script from running. LCKF="/tmp/LCK.ADSMREC" # # Reclamation Table - a list of VSP volumes to reclamate (auto generated). REC_TABLE="/tmp/adsm.rectbl" # # ************* Macro's that should not be changed manually ************ # # Default command that is normally issued. DSMADMC="dsmadmc -ID=$ADSM_ID -PASSWORD=$ADSM_PASSWD -NOCONFIRM" # # Manual Reclamation Process ID (must be zero, will be set by script) MR_PROC_ID=0 # # Reclamation Threshold (must be zero, will be set by script). # This item is retrieved from the VSP Reclamation Threshold field in ADSM. RTH=0 # # Volume Threshold (must be zero, will be set by script). # This is the volume threshold used to choose volumes eligible for # reclmation. The value is the maximum volume occupancy for full # volumes, below which volumes will be reclaimed. This is equivilent # to 100-RTH VTH=0 # # Maximum Scratch Volumes Allowed (must be zero, will be set by script) # This item is retrieved from the VSP Max Scratch Volumes field in ADSM. MSVA=0 # # Current Number of Scratch Volumes (must be zero, will be set by script) CNSV=0 # # Current Number of Volumes being filled (must be zero, will be set by script) CNVF=0 # # Manual Reclamation Storage Pool's (MRSP) next storage pool to send data to. MRSP_NSP="" # # # ********************** Define Macro Functions ************** # # Function to load information about VSP for Reclamation. # Returns 0=success, 1=failed. Get_VSP_Info () { Rtn=0 # $DSMADMC q stg $VSP f=d | tail +8 | while read line do field=`echo "$line" | awk ' FS=":" { print $1 } '` var=`echo "$line" | awk ' FS=":" { print $2 } '` case $field in 'Reclamation Threshold') RTH=`echo "$var" | awk ' { print $1 } '` ;; 'Maximum Scratch Volumes Allowed') MSVA=`echo "$var" | awk ' { print $1 } '` ;; esac done # # Did we get everything we need to have? # if [ $RTH -lt 1 ] then Log "! Storage Pool $VSP \"Reclamation Threshold\" value is invalid." Rtn=1 fi # if [ $MSVA -lt 1 ] then Log "! Storage Pool $VSP \"Maximum Scratch Volumes Allowed\" value is invalid." Rtn=1 fi VTH=0 # Calculate the volume threashold (for occupancy) that will # be used to determine if it can be reclaimed. Note that this # is 100 - the recmation threshold, ince the threshold is # specified in terms of percentage of emty space on the volume if [ $Rtn -eq 0 ] then VTH=`expr 100 - $RTH` fi # return $Rtn } # # # Function to load information about MRSP # Returns 0=success, 1=failed. Get_MRSP_Info () { Rtn=0 # $DSMADMC q stg $MRSP f=d | tail +8 | while read line do field=`echo "$line" | awk ' FS=":" { print $1 } '` var=`echo "$line" | awk ' FS=":" { print $2 } '` case $field in 'Next Storage Pool') MRSP_NSP=`echo "$var" | awk ' { print $1 } '` ;; esac done # # Did we get everything we need to have? # if [ "$MRSP_NSP" = "" ] then Log "! Storage Pool $MRSP must have a \"Next Storage Pool\" value." Rtn=1 fi # return $Rtn } # # # Function to load the VSP volume tables for reclamation. Load_Rec_Table () { # Remove any exisitng tables rm -f $REC_TABLE # $DSMADMC q vol | tail +12 | while read line do if [ "$line" != "" ] then # vol=`echo "$line" | awk '{ print $1 }'` stgpool_name=`echo "$line" | awk '{ print $2 }'` storage_class=`echo "$line" | awk '{ print $3 }'` util=`echo "$line" | awk '{ print $5 }'` status=`echo "$line" | awk '{ print $6 }'` # # Does this volume belong to VSP? # `echo "$VSP"` # `echo "$VSP" | grep $stgpool_name` Rtn=`echo "$VSP" | grep $stgpool_name` if [ "$Rtn" != "" ] then # If you are here, then this is a valid storage pool to work with. if [ "$status" = "Full" ] then # Volume is in a status of full, might be able to reclamate. echo "$util:$vol" >> $REC_TABLE fi # # Are we filling this volume? We need to know for CNSV if [ "$status" = "Filling" ] then # yep, were filling this volume CNVF=`expr $CNVF + 1` fi fi fi done # Rtn=$? if [ "$Rtn" = "0" ] then # got a good table, sort it and continue. cat $REC_TABLE | sort -n > $REC_TABLE return 0 else # Opps, something bit it rm -f $REC_TABLE return 1 fi } # # # Function that finds the current number of available scratch volumes # to make sure we have enough to do a reclamation. Calculate_CNSV () { CNUV=0 # # Load the volumes into the Reclamation Table from ADSM Load_Rec_Table if [ $? != 0 ] then Log "! Failed to load the reclamation table." return 1 fi # # Make sure there is a table to go by. if [ ! -f $REC_TABLE ] then # Opps, no table - how this happen? Log "! Reclamation Table missing. Unable to Calculate_CNSV" return 1 fi # # Make sure MSVA has been set if [ $MSVA -lt 1 ] then # Opps, no table - how this happen? Log "! MSVA is missing! Unable to Calculate_CNSV" return 1 fi # # Get the number of volumes being uses from REC_TABLE CNUV=`cat $REC_TABLE | wc -l | awk '{ print $1 }'` # Calculate the current number of scratch volumes available CNSV=`expr $MSVA - $CNVF - $CNUV` # Any scratch volumes available? if [ $CNSV -lt 1 ] then # Nope, out of scratch volumes to use for reclamation. return 1 fi # # If you are here, all is well, lets continue. return 0 } # # # Function that controls the reclamation Reclamation_Loop () { # Make sure there is a table to go by. if [ ! -f $REC_TABLE ] then # Opps, no table - how this happen? return 1 fi # RL_RET=1 # cat $REC_TABLE | while read line do vsp_util=`echo "$line" | awk ' FS=":" { print $1 } '` vsp_vol=`echo "$line" | awk ' FS=":" { print $2 } '` # # Volume utilization greater than the Reclamation Threshold (VTH)? if [ $vsp_util -gt $VTH ] then # Yep, Nothing to migrate # All volumes packed beyond the RTH. # We'll exit the program with this return so we don't try another pack. return $RL_RET fi # # If you are here, then there is something to migrate. # # Lets ensure the MRSP is empty for reclamation Empty_MRSP # # Lets make sure there are scratch volumes to use for reclamation. Calculate_CNSV if [ $? != 0 ] then Log "! Insufficient scratch volumes available for reclamation." Log "= Storage Pool: $VSP, Scratch Volumes Available: $CNSV." return 1 fi # # Begin the moving of data off of this volume. RL_RET=0 MR_PROC_ID=0 Move_Data $vsp_vol $MRSP Rtn=$? if [ $Rtn != 0 ] then if [ $Rtn = 2 ] then Log "= No data on volume $vsp_vol to move to stgpool $MRSP." else Log "! Failed to begin a MOVE DATA on volume $vsp_vol to stgpool $MRSP." fi # We'll try another volume just in case this one is checked out. else Log "+ Move Data started on vol $vsp_vol, process id is $MR_PROC_ID." # # Monitor the process, when its finished, then continue with # the next volume. while true do sleep 120 # See if the move data process is still running Check_Proc_Status $MR_PROC_ID if [ $? != 0 ] then # Nope, lets break out and do the next volume. break fi # If you are here, our move data process is still running. done fi done # # Sigh - that's all done. But, lets do it again to make sure we # can't pack it even better. return $RL_RET } # # # Function that moves the data from $1 (volume) to $2 (storage pool) # $1 must be the SOURCE volume to that contains data to be moved # $2 must be the DESTINATION storage pool # Returns: # 0 = Move process was successfully started # 1 = Failed to start the move process # 2 = No Data to move Move_Data () { $DSMADMC move data $1 stg=$2 | tail +5 | while read line do # Find our process id msg=`echo "$line" | awk ' { print $1 } '` # # Successfuly started a Move Data Job? if [ "$msg" = "ANS5104I" ] then # yes, Get our process ID. MR_PROC_ID=`echo "$line" | awk ' { print $4 } '` return 0 fi # # Was there any data to move? if [ "$msg" = "ANR2209W" ] then # No there wasn't any data to move return 2 fi # done # # Something went wrong. return 1 } # # # Function to check the status of a process # $1 must be the process number to check Check_Proc_Status () { Rtn=0 # $DSMADMC q proc $1 | tail +5 | while read line do msg=`echo "$line" | awk ' { print $1 } '` if [ "$msg" = "ANR0942E" ] then # Process is no longer running Rtn=1 fi done # return $Rtn } # # # This function checks $1 to ensure it isn't in migration # $1 must be the storage pool to check for migration on Check_For_Migration () { $DSMADMC q stg $1 f=d | grep 'Migration in Progress' | read line # status=`echo "$line" | awk ' FS=":" { print $2 } ' | awk ' { print $1 } '` # if [ "$status" = "Yes" ] then # Yes, migration has commenced. return 1 else # Nope, migration is idle return 0 fi } # # # Function that ensures the MRSP is empty Empty_MRSP () { Log "= Attempting to empty storage pool $MRSP for use in reclamation." # # Make sure the system isn't Migrating MRSP while true do Check_For_Migration $MRSP if [ $? = 0 ] then # Nope, not in progress, yet. break fi # # Yep, there is a migration going. Wait until it's finished. Log "= Migration in progress on storage pool $MRSP, waiting." sleep 300 done # # $DSMADMC q vol stg=$MRSP | tail +12 | while read line do if [ "$line" = "" ] then break fi # # Get the volume(s) associated with MRSP. mrsp_vol=`echo "$line" | awk ' { print $1 } '` # # Begin the moving of data off of this MRSP volume. MR_PROC_ID=0 Move_Data $mrsp_vol $MRSP_NSP Rtn=$? if [ $Rtn != 0 ] then if [ $Rtn = 2 ] then Log "= No data on volume $mrsp_vol to move to stgpool $MRSP_NSP." else Log "! Failed to begin a MOVE DATA on volume $mrsp_vol to stgpool $MRSP_NSP." fi # We'll try another volume just in case this one is checked out. else Log "+ Move Data started on volume $mrsp_vol, process id is $MR_PROC_ID." # # Monitor the process, when its finished, then continue with # the next volume. while true do sleep 120 # Is the move data process is still running? Check_Proc_Status $MR_PROC_ID if [ $? != 0 ] then # Nope, lets break out and do the next volume. break fi # If you are here, our move data process is still running. done fi done # return 0 } # # # Log information to the log file # $1 needs to be the information to log Log () { # Following line sends information to the LOG file. if [ "$SLTF" = "Y" ] then echo "`date +%y/%m/%d` `date +%H:%M` $1" >> $LOG fi # # Following line sends information to the screen. if [ "$SLTS" = "Y" ] then echo "`date +%y/%m/%d` `date +%H:%M` $1" fi } # # # # ********************** Main script area ****************** # # cd /usr/lpp/adsm/bin # # Make sure we are the only process running if [ -f $LCKF ] then echo "A reclamation process is already running, exiting." exit 1 else echo "`date`" > $LCKF Log "+ Started." fi # # while true do # Load MRSP information just in case it changed while we were working. Get_MRSP_Info if [ $? != 0 ] then break fi # # Load VSP information just in case it changed while we were working. Get_VSP_Info if [ $? != 0 ] then break fi # Log "= Storage Pool: $VSP, Reclamation Threshold: $RTH." Log "= Filled volumes with $VTH % occupancy or less will be reclaimed." Log "= Storage Pool: $VSP, Maximum Scratch Volumes Allowed: $MSVA." # # Load the volumes into the Reclamation Table from ADSM Load_Rec_Table if [ $? != 0 ] then Log "! Failed to load the reclamation table." break fi # # Begin the reclamation Reclamation_Loop Rtn=$? # Can we pack any more volumes? if [ $Rtn != 0 ] then # Nope, volumes packed beyond RTH, Reclamation is over. # # Lets ensure the MRSP is completely empty. Empty_MRSP # # And that's it for this time. break fi # # If you are here, Lets try one more reclamation to make sure we can't # pack the volumes even better. done # # Cleanup rm -f $REC_TABLE # Log "+ Ended." # # remove lock file rm -f $LCKF # # # (end script)