#!/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 # Last Updated : Craib Bell, IBM 6/1/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. # # This version of the script is for use with a PAIR of single drive # libraries rather than one single drive library and a large disk # storage pool. # # 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: # Two Storage Pools and their corresponding single-drive tape/optical # libraries. These storage pools must be in a hierarchy, ie. one stgpool # is the "next=" value for the other stgpool. The last stgpool in the # heirarchy is considered the "lower" stgpool, and the stgpool whose "next=" # parameter is set to the lower stgpool is the "upper" stgpool. # # How it works................... # The script finds volumes on your lower sequential storage pool (LSP) whose # occupancy is *LESS* 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 LSP volume on to the upper storage pool (USP). # # If the USP gets full, ADSM will (if set) automaticaly migrate the data # back to the LSP thus consolidating the data. # # The USP must have enough available space to hold the reclaimable # data that need to be moved to empty a volume. # # And the process repeats itself until there are no more volumes in the LSP # 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 # # USP - The *UPPER* storage pool name to use for reclamation of LSP. # - This is were the data will be moved to # - This storage pool should migrate to your LSP (see next item). # - Cache'ing should be turned off. # # LSP - 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 LSP storage pool. # # Next Storage Pool - This must be set on your USP storage pool. # - This should be your LSP # # 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="rcb" ADSM_PASSWD="rcb" # # Upper Storage Pool name (where to move the data to). USP="TAPE" # # Storage Pool Name to Reclamate LSP="TAPE2" # # 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 LSP 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 -SE=SHILOH-0" # # 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 LSP 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 LSP 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 # # Upper Storage Pool's (USP) next storage pool to send data to. USP_NSP="" # # # ********************** Define Macro Functions ************** # # Function to load information about LSP for Reclamation. # Returns 0=success, 1=failed. Get_LSP_Info () { Rtn=0 # $DSMADMC q stg $LSP 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 $LSP \"Reclamation Threshold\" value is invalid." Rtn=1 fi # if [ $MSVA -lt 1 ] then Log "! Storage Pool $LSP \"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 USP # Returns 0=success, 1=failed. Get_USP_Info () { Rtn=0 # $DSMADMC q stg $USP 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') USP_NSP=`echo "$var" | awk ' { print $1 } '` ;; esac done # # Did we get everything we need to have? # if [ "$USP_NSP" = "" ] then Log "! Storage Pool $USP must have a \"Next Storage Pool\" value." Rtn=1 fi # return $Rtn } # # # Function to load the LSP 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 LSP? # `echo "$LSP"` # `echo "$LSP" | grep -i $stgpool_name` if [ "$stgpool_name" != "" ] then Rtn=`echo "$LSP" | grep -i $stgpool_name` else Rtn="" fi if [ "$Rtn" != "" ] then # If here, then this is a valid storage pool to work with. echo "Found storage pool" if [ "$status" = "Full" ] then # Volume is in a status of full, might be reclaimable echo "Found full volume" 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 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 LSP_util=`echo "$line" | awk ' FS=":" { print $1 } '` LSP_vol=`echo "$line" | awk ' FS=":" { print $2 } '` # # Volume utilization greater than the Reclamation Threshold (VTH)? if [ $LSP_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. # Begin the moving of data off of this volume. RL_RET=0 MR_PROC_ID=0 Move_Data $LSP_vol $USP Rtn=$? if [ $Rtn != 0 ] then if [ $Rtn = 2 ] then Log "= No data on volume $LSP_vol to move to stgpool $USP." else Log "! Failed to begin a MOVE DATA on volume $LSP_vol to stgpool $USP." fi else Log "+ Move Data started on vol $LSP_vol, process id is $MR_PROC_ID." # # Monitor the process, when its finished, then continue with # the next volume. while true do sleep 60 # 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 # 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 } # # 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 # Check_For_Migration $USP # Load USP information just in case it changed while we were working. Get_USP_Info if [ $? != 0 ] then break fi # # Load LSP information just in case it changed while we were working. Get_LSP_Info if [ $? != 0 ] then break fi # Log "= Storage Pool: $LSP, Reclamation Threshold: $RTH." Log "= Filled volumes with $VTH % occupancy or less will be reclaimed." Log "= Storage Pool: $LSP, 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 # break done # # Cleanup rm -f $REC_TABLE # Log "+ Ended." # # remove lock file rm -f $LCKF # # # (end script)