#!/bin/ksh # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # # # Licensed Materials - Property of IBM # # (C) COPYRIGHT International Business Machines Corp. 2000,2006 # All Rights Reserved # # US Government Users Restricted Rights - Use, duplication or # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # # IBM_PROLOG_END_TAG # @(#)08 1.67.1.2 src/avs/fs/mmfs/ts/admin/mmcrnsd.sh, mmfs, avs_rgpfs24, rgpfs24s005a 6/14/06 14:40:06 ############################################################################### # # Usage: # mmcrnsd -F DescFile [-v {yes | no}] # # where # -F DescFile specifies a file containing the disk descriptors for # the network shared disks to be created # -v {yes | no} verification flag; a value of "yes" specifies that the # disks in DescFile should only be created if they have # not been previously formatted as an NSD, while a value # of "no" specifies the disks should be created regardless # of whether they have been previously formatted or not. # The default value is "yes". # ############################################################################### # Include global declarations and service routines. . /usr/lpp/mmfs/bin/mmglobfuncs . /usr/lpp/mmfs/bin/mmsdrfsdef . /usr/lpp/mmfs/bin/mmfsfuncs sourceFile="mmcrnsd.sh" [[ -n $DEBUG || -n $DEBUGmmcrnsd ]] && set -x $mmTRACE_ENTER "$*" # Local work files. Names should be of the form: # fn=${tmpDir}fn.${mmcmd}.$$ tdescfile=${tmpDir}tdescfile.${mmcmd}.$$ # temp file for descriptors LOCAL_FILES=" $tdescfile " # Local variables integer highestGpfsDiskNbr integer seqNo=0 usageMsg=410 noUsageMsg=0 hadSuccess=false # Local functions ###################### # Mainline processing ###################### ###################################### # Process the command line arguments. ###################################### [[ $arg1 = '-?' || $arg1 = '-h' || $arg1 = '--help' || $arg1 = '--' ]] && \ syntaxError "help" $usageMsg [[ $argc -lt 1 ]] && \ syntaxError "missingArgs" $usageMsg while getopts :F:v: OPT do case $OPT in F) # node names file [[ -n $Farg ]] && syntaxError "multiple" $noUsageMsg "-$OPT" Farg=$OPTARG if [[ ! -r $Farg ]] then # Cannot open the file printErrorMsg 43 $mmcmd $Farg cleanupAndExit fi ;; v) [[ -n $vflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" if [[ $OPTARG = yes || $OPTARG = no ]] then vflag="$OPTARG" else syntaxError "YesNoValue" $noUsageMsg "-$OPT" fi ;; +[Fv]) # Invalid option syntaxError "invalidOption" $usageMsg $OPT ;; :) # Missing argument syntaxError "missingValue" $usageMsg $OPTARG ;; *) # Invalid option syntaxError "invalidOption" $usageMsg $OPTARG ;; esac done # end while getopts :F:v: OPT shift OPTIND-1 [[ $# != 0 ]] && syntaxError "extraArg" $usageMsg $1 [[ -z $vflag ]] && vflag=yes # Verify the mandatory -F parameter. [[ -z $Farg ]] && syntaxError "missingArgs" $usageMsg descfile=$Farg checkUserFile $descfile $descfile [[ $? -ne 0 ]] && cleanupAndExit ##################################################################### # Set up trap exception handling and call the gpfsInit function. # It will ensure that the local copy of the mmsdrfs and the rest of # the GPFS system files are up-to-date and will obtain the sdr lock. ##################################################################### trap pretrap HUP INT QUIT KILL gpfsInitOutput=$(gpfsInit $lockId) setGlobalVar $? $gpfsInitOutput ######################################################################### # Create a new version of the mmsdrfs file with a new generation number. # Generate a file containing the names of the nodes in the cluster. ######################################################################### $rm -f $nodefile $newsdrfs IFS=":" # Change the field separator to ':'. exec 3<&- exec 3< $mmsdrfsFile while read -u3 sdrfsLine do # Parse the line. set -f ; set -A v -- - $sdrfsLine ; set +f IFS="$IFS_sv" # Restore the default IFS settings. printLine=true # Assume the line will be printed. # Change some of the fields depending on the type of line. case ${v[$LINE_TYPE_Field]} in $VERSION_LINE ) # this is the global header line # Increment the generation number and save the line for later output. newGenNumber=${v[$SDRFS_GENNUM_Field]}+1 v[$SDRFS_GENNUM_Field]=$newGenNumber versionLine_A="${v[1]}:${v[2]}:${v[3]}:${v[4]}:${v[5]}:${v[6]}" versionLine_A="$versionLine_A:${v[7]}:${v[8]}:${v[9]}:${v[10]}" highestGpfsDiskNbr=${v[$HIGHEST_GPFS_DISK_NBR_Field]} versionLine_B="${v[12]}:${v[13]}:${v[14]}:${v[15]}:${v[16]}" versionLine_B="$versionLine_B:${v[17]}:${v[18]}:${v[19]}:${v[20]}" versionLine_B="$versionLine_B:${v[21]}:${v[22]}:${v[23]}:${v[24]}" printLine=false ;; $MEMBER_NODE ) # this line describes a node # Add the reliable node name to nodefile. print -- ${v[$REL_HOSTNAME_Field]} >> $nodefile checkForErrors "writing to file $nodefile" $? [[ ${v[$NODE_NUMBER_Field]} = $ourNodeNumber ]] && \ preferredNode=${v[$REL_HOSTNAME_Field]} ;; * ) # Pass all other lines without a change. ;; esac # end Change some of the fields # Build and write the line to the new mmsdrfs file. if [[ $printLine = true ]] then print_newLine >> $newsdrfs checkForErrors "writing to file $newsdrfs" $? fi IFS=":" # Change the separator back to ":" for the next iteration. done # end while read -u3 sdrfsLine IFS="$IFS_sv" # Restore the default IFS settings. ############################################################################ # Process the descriptors for the new disks. Each descriptor is validated. # If the descriptor appears to be ok, tspreparedisk is invoked to generate # a unique physical id on the disk. For each disk that is successfully # processed by tspreparedisk, an SG_DISKS line is added to the sdrfs file. ############################################################################ exec 3<&- exec 3< $descfile $rm -f $tdescfile while read -u3 mmDiskDesc do # Skip empty lines and comment lines ('#' is the first non-white char). if [[ $mmDiskDesc = *([$BLANKchar$TABchar])#* || $mmDiskDesc = *([$BLANKchar$TABchar]) ]] then # Preserve the line "as is" in the user's input file. print -- "$mmDiskDesc" >> $tdescfile continue fi # Append the commented-out descriptor to the temporary descriptor file. # If the descriptor passes all error checking, this line will be followed # by the converted descriptor with the assigned global name. print -- "# $mmDiskDesc" >> $tdescfile checkForErrors "writing to file $tdescfile" $? # Parse the disk descriptor. IFS=':' set -f ; set -- $mmDiskDesc ; set +f device=$1 diskName=${device##+(/)dev+(/)} # name stripped of /dev/ prefix server=$2 backup=$3 diskUsage=$4 failureGroup=$5 desiredName=$6 storagePool=$7 IFS="$IFS_sv" # Issue an informational progress message (processing disk xyz ...). printInfoMsg 251 $mmcmd $diskName # If a server node was specified, check that it is valid # and convert it if necessary to an admin adapter name. if [[ -n $server ]] then server=$(checkAndConvertNodeValue $server $REL_HOSTNAME_Field) [[ $? -ne 0 ]] && cleanupAndExit fi if [[ -n $backup ]] then backup=$(checkAndConvertNodeValue $backup $REL_HOSTNAME_Field) [[ $? -ne 0 ]] && cleanupAndExit fi # Generate a template SG_DISK line for the new disk. # For now, we assume that everything will check out. diskSize=0 [[ -z $failureGroup ]] && failureGroup=-1 [[ -z $diskUsage ]] && diskUsage=dataAndMetadata pvid="" primaryNsdNode="" backupNsdNode="" diskType="nsd" # Determine the name the nsd will be called. if [[ -z $desiredName ]] then highestGpfsDiskNbr=highestGpfsDiskNbr+1 nsdName="gpfs${highestGpfsDiskNbr}nsd" nameSource="$cmdGenerated" else # Check whether the desired disk name conforms to naming rules. # If it does not, skip to the next disk descriptor. checkName diskName 255 "$desiredName" [[ $? -ne 0 ]] && continue # Issue an error and skip to the next descriptor # if the desired name begins with "gpfs". if [[ $desiredName = gpfs* ]] then # The desired disk name begins with "gpfs". printErrorMsg 505 $mmcmd $desiredName continue # Skip to the next disk descriptor. fi # Issue an error and skip to the next descriptor # if the desired name is already in use. dn=$(getDiskInfo $DISK_NAME_Field $desiredName $newsdrfs) rc=$? if [[ $rc -ne 0 && -z $dn ]] then nsdName="$desiredName" else # The desired disk name is already in use by GPFS. printErrorMsg 432 $mmcmd $desiredName continue # Skip to the next disk descriptor. fi nameSource="$userSpecified" fi # Create a free disk line as a starting point for the validate routine. freeDiskLine="$FREE_DISK:$SG_DISKS:$NO_DEVICE:$seqNo:$nsdName:$diskSize" freeDiskLine="${freeDiskLine}:$failureGroup:$diskUsage:$pvid:$diskType" freeDiskLine="${freeDiskLine}:$primaryNsdNode:$backupNsdNode::::$nameSource" freeDiskLine="${freeDiskLine}::$includedDisk:" # Check the correctness of the disk descriptor. If everything is OK, # validateAndConvertNsdDescriptor will return an updated SG_DISKS line. validateDescriptorOutput=$(validateAndConvertNsdDescriptor "$mmDiskDesc" \ $freeDiskLine $NO_DEVICE $FREE_DISK NULL) rc=$? if [[ $rc -ne 0 ]] then # If an error was found, the validate routine issued a message. # We will now print the entire descriptor to help the guy some more. printErrorMsg 386 $mmcmd "$mmDiskDesc" [[ -z $desiredName ]] && highestGpfsDiskNbr=highestGpfsDiskNbr-1 continue # Skip to the next disk descriptor. fi # If the descriptor seems to be OK, parse the output # from the validateAndConvertNsdDescriptor routine. set -f ; set -- $validateDescriptorOutput ; set +f updatedDiskLine="$1" # Generate and write a unique pvid on sector 2 of the disk. # If an NSD server is specified, invoke the function on that node. # This call will also return the type of the underlying disk. if [[ -z $server || $server = $ourNodeName ]] then invokedNode=$ourNodeName createNsdOutput=$(createNsd $diskName $vflag mmcrnsd NULL) rc=$? else invokedNode=$server createNsdOutput=$(run on1 $server \ createNsd $diskName $vflag mmcrnsd NULL) rc=$? fi # The output of createNsd consists of a one-word NSD subtype value, # followed by the output from tspreparedisk. Separate the two parts. nsdSubtype=${createNsdOutput%% *} tspreparediskOutput=${createNsdOutput#* } # Set the value for the nsd subtype diskname if the nsd subtype # is lv, vsd or file; this name is persistent across the nodes. nsdSubtypeDiskname="" [[ $nsdSubtype = lv || $nsdSubtype = vsd || $nsdSubtype = file ]] && \ nsdSubtypeDiskname=$diskName # Parse the output from the tspreparedisk command. IFS=":" set -f ; set -- $tspreparediskOutput ; set +f magicWord=$1 rc2=$2 pvid=$3 primaryLocalName=$4 status=$5 diskSize=$6 oldPvid=$8 IFS="$IFS_sv" if [[ $rc -ne 0 || $nsdSubtype = error || $rc2 -ne 0 || $magicWord != tspreparedisk ]] then # Try to make sense of the error. if [[ $nsdSubtype = error ]] then : # determineNsdSubtype failed. Messages were already issued. elif [[ $magicWord = tspreparedisk ]] then # tspreparedisk was executed but was not happy about something. if [[ $rc2 = 1 ]] then # Permission was denied for disk. printErrorMsg 523 $mmcmd $device elif [[ $rc2 = 2 ]] then # The disk was not found. printErrorMsg 524 $mmcmd $device elif [[ $rc2 = 5 ]] then # I/O error printErrorMsg 525 $mmcmd $device elif [[ $rc2 = $MM_DeviceNotFound ]] then # A return code of ENODEV was returned for the disk. printErrorMsg 187 $mmcmd $invokedNode $device elif [[ $rc2 = 27 ]] then # The disk is too large. printErrorMsg 508 $mmcmd $device elif [[ $rc2 = 50 ]] then # The disk is fenced out. printErrorMsg 395 $mmcmd $invokedNode $device else # Show the result from tspreparedisk. print -u2 "$tspreparediskOutput" # Unexpected error from tspreparedisk printErrorMsg 171 "$mmcmd" "tspreparedisk $diskName" $rc2 fi # end if [[ $rc2 = 1 ]] else # Something is really wrong. Output error information if any. [[ -n $createNsdOutput ]] && print -u2 "$createNsdOutput" fi # end if [[ $nsdSubtype = error ]] # Issue "failed while processing disk descriptor xyz" message. [[ -z $server ]] && server=$ourNodeName printErrorMsg 411 $mmcmd "$mmDiskDesc" $server # We will process the rest of the descriptors to create # NSDs for those that are good and to flush out as many # errors with the descriptors as possible. [[ -z $desiredName ]] && highestGpfsDiskNbr=highestGpfsDiskNbr-1 continue # Skip to the next disk descriptor. fi # end if [[ $rc -ne 0 || $nsdSubtype = error || ... if [[ $status = old ]] then # The tspreparedisk command discovered that this is an already-defined NSD. # Find the SG_DISKS line for the disk and remove it from the mmsdrfs file. # Note that it is possible that there is no SG_DISKS line for this disk. # This can happen if a disk is forcefully deleted (mmdelnsd -p) from the # mmsdrfs file but the pvid was not destroyed because the disk was not # available, or a previous mmcrnsd could have failed after tspreparedisk # successfully completed but before the information could be committed. $rm -f $tmpfile existingDiskLine=$($awk -F: ' \ # If the line is for our disk, assign it to existingDiskLine. \ # Do not put the line in the temp file. \ /':$SG_DISKS:'/ { \ if ($'$PVID_Field' == "'$oldPvid'") { \ { print $0 } \ { next } \ } \ } \ # Write all other lines to tmpfile. \ { print $0 >> "'$tmpfile'" } \ ' $newsdrfs) # Prepare the newsdrfs file for the next iteration. # It will contain all of its original lines except the line # that describes the disk that is currently being processed. $mv $tmpfile $newsdrfs checkForErrors "mv $tmpfile $newsdrfs" $? # Find the global name of the disk. IFS=":" set -f ; set -- $existingDiskLine ; set +f IFS="$IFS_sv" existingGlobalName=$5 if [[ $vflag = yes ]] then # The user requested existing disks to be flagged as an error. printErrorMsg 412 $mmcmd "$mmDiskDesc" $existingGlobalName [[ -z $desiredName ]] && highestGpfsDiskNbr=highestGpfsDiskNbr-1 # Put the old line back in the file and go to the next descriptor. if [[ -n $existingDiskLine ]] then print -- $existingDiskLine >> $newsdrfs checkForErrors "writing to file $newsdrfs" $? fi continue fi # The user specified that existing disks are acceptable (-v no). # Was a line for the disk found in the mmsdrfs file? if [[ -n $existingDiskLine ]] then # An SG_DISKS line for the disk was found. # Did the user specify a name for the nsd? if [[ -n $desiredName ]] then # Use the new nsd name specified by the user. nsdName=$desiredName else # Reuse the old nsd name and un-increment the highest disk number. nsdName=$existingGlobalName highestGpfsDiskNbr=highestGpfsDiskNbr-1 fi else # No SG_DISKS line was found for this disk; treat the disk as new. status=new fi # end of if [[ -n $existingDiskLine ]] fi # end of if [[ $status = old ]] # At this point updatedDiskLine contains the SG_DISKS information # for a disk which is successfully defined as an NSD by tspreparedisk. IFS=":" set -f ; set -A v -- - $updatedDiskLine ; set +f IFS="$IFS_sv" # Update descriptor values that might have been set by the validate function. failureGroup=${v[$FAILURE_GROUP_Field]} diskUsage=${v[$DISK_USAGE_Field]} # Add the missing or updated information. v[$DISK_NAME_Field]=$nsdName v[$DISK_SIZE_Field]=$diskSize v[$PVID_Field]=$pvid v[$NSD_SUBTYPE_Field]=$nsdSubtype v[$NSD_SUBTYPE_DISKNAME_Field]=$nsdSubtypeDiskname updatedDiskLine=$(print_newLine) # If a backup NSD node is specified, run the tspreparedisk command # on that node to verify that the disk is properly connected. if [[ -n $backup ]] then if [[ $nsdSubtype = vsd ]] then # Attempt to write to sector 2 of the disk from the backup # server in order to determine whether the disk is accessible. # (This will cause the backup server to be unfenced from the # vsd if necessary.) if [[ $backup = $ourNodeName ]] then invokedNode=$ourNodeName createNsdOutput=$(createNsd $diskName yes mmcrnsd vsd) rc=$? else invokedNode=$backup createNsdOutput=$(run on1 $backup \ createNsd $diskName yes mmcrnsd vsd) rc=$? fi # The output of createNsd consists of a one-word NSD subtype value # followed by the tspreparedisk output. Extract the tspreparedisk output. tspreparediskOutput=${createNsdOutput#* } else if [[ $backup = $ourNodeName ]] then invokedNode=$ourNodeName tspreparediskOutput=$($tspreparedisk -p $pvid -t $nsdSubtype) rc=$? else invokedNode=$backup tspreparediskOutput=$(run on1 $backup adminCmd \ tspreparedisk -p $pvid -t $nsdSubtype) rc=$? fi fi # Parse the output from the tspreparedisk command. IFS=":" set -f ; set -- $tspreparediskOutput ; set +f magicWord=$1 rc2=$2 backupPvid=$3 backupLocalName=$4 status=$5 IFS="$IFS_sv" if [[ $rc -ne 0 || $magicWord != tspreparedisk || $rc2 -ne 0 || $pvid != $backupPvid ]] then # Try to make sense of the error. if [[ $magicWord = tspreparedisk ]] then # tspreparedisk was executed but was not happy about something. if [[ $rc2 = 1 ]] then # Permission was denied for disk. printErrorMsg 523 $mmcmd $device elif [[ $rc2 = 2 ]] then # The disk was not found. printErrorMsg 524 $mmcmd $device elif [[ $rc2 = 5 ]] then # I/O error printErrorMsg 525 $mmcmd $device elif [[ $rc2 = $MM_DeviceNotFound ]] then # A return code of ENODEV was returned for the disk. printErrorMsg 187 $mmcmd $invokedNode $device elif [[ $rc2 = 50 ]] then # The disk is fenced out. printErrorMsg 395 $mmcmd $invokedNode $device elif [[ $pvid != $backupPvid ]] then print -u2 "$mmcmd: Mismatched disk PVIDs" else # Show the result from tspreparedisk. print -u2 "$tspreparediskOutput" # Unexpected error from tspreparedisk -p printErrorMsg 171 "$mmcmd" \ "tspreparedisk -p $pvid -t $nsdSubtype" $rc2 fi # end if [[ $rc2 = 1 ]] else # Something is really wrong. Output error information if any. [[ -n $tspreparediskOutput ]] && print -u2 "$tspreparediskOutput" fi # end if [[ $magicWord = tspreparedisk ]] # Failed while processing disk descriptor printErrorMsg 411 $mmcmd "$mmDiskDesc" $backup [[ -z $desiredName ]] && highestGpfsDiskNbr=highestGpfsDiskNbr-1 continue # Skip to the next disk descriptor. fi # end if [[ $rc -ne 0 || $magicWord != tspreparedisk || ... ]] fi # end of if [[ -n $backup ]] # At this point, the descriptor passed all checks successfully, # the disk was formatted as an NSD, and updatedDiskLine contains # the SG_DISKS line that needs to go in the mmsdrfs file. print -- $updatedDiskLine >> $newsdrfs checkForErrors "writing to file $newsdrfs" $? # Append the good modified descriptor to the temporary descriptor file. print -- "$nsdName:::$diskUsage:$failureGroup::$storagePool" >> $tdescfile checkForErrors "writing to file $tdescfile" $? # There is at least one good disk descriptor. hadSuccess=true done # end of while read -u3 mmDiskDesc # If all of the descriptors had some kind of error and not a single # disk was created, give up. Messages have already been issued. [[ $hadSuccess != true ]] && \ cleanupAndExit #################################################################### # We have now finished processing descriptors. # Create a new version line with an updated HIGHEST_GPFS_DISK_NBR # value that reflects the highest disk number currently assigned # and add it back to the mmsdrfs file. Commit the changes. #################################################################### newVersionLine="$versionLine_A:$highestGpfsDiskNbr:$versionLine_B" print -- $newVersionLine >> $newsdrfs checkForErrors "writing to file $newsdrfs" $? # Sort the new sdrfs file. LC_ALL=C $SORT_MMSDRFS $newsdrfs -o $newsdrfs # Replace the mmsdrfs file. # This makes the new disks visible to other mm commands. trap "" HUP INT QUIT KILL gpfsObjectInfo=$(commitChanges \ $FREE_DISK $nsId $gpfsObjectInfo $newGenNumber $newsdrfs $primaryServer) rc=$? if [[ $rc -ne 0 ]] then # We were unable to replace the file in the sdr. printErrorMsg 381 $mmcmd cleanupAndExit fi ################## # Unlock the sdr. ################## [[ $sdrLocked = yes ]] && \ freeLockOnServer $primaryServer $ourNodeNumber >/dev/null sdrLocked=no trap posttrap HUP INT QUIT KILL ############################################################################# # Move the updated (and any commented out) descriptors into the user's file. ############################################################################# $mv $tdescfile $descfile checkForErrors "writing to file $descfile" $? ################################################################# # Propagate the new mmsdrfs file. This process is asynchronous. ################################################################# propagateSdrfsFile async $nodefile $newsdrfs $newGenNumber rereadnsd ################################################### # If installed, invoke the syncfsconfig user exit. ################################################### if [[ -x $syncfsconfig ]] then print -- "$mmcmd: Starting $syncfsconfig ..." $syncfsconfig print -- "$mmcmd: $syncfsconfig finished." fi cleanupAndExit 0