#!/bin/ksh # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # # # Licensed Materials - Property of IBM # # (C) COPYRIGHT International Business Machines Corp. 2003,2007 # 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 # @(#)36 1.7.5.2 src/avs/fs/mmfs/ts/admin/mmexportfs.sh, mmfs, avs_rgpfs24, rgpfs24s010a 2/22/07 03:17:55 ############################################################################## # # Usage: # # mmexportfs {Device | all} -o ExportfsFile [-C nodesetId] [-P] # # where # # Device is the file system to be exported. # If "all" is specified, then all file systems in # the cluster are exported. Free disks, if any, # are exported as well. # # -o ExportfsFile is the name of a file where the file system # export information is to be placed. # # # Obsolete option (for use when migrating previous releases): # # -C NodesetId is the nodeset from which file systems are to be # exported. This parameter is used to limit the # scope of the "all" keyword to all file systems # within a given nodeset rather than all file # systems in the cluster. # # Undocumented option: # # -P Do not remove the file system information from # the current version of the mmsdrfs. # ############################################################################## # Include global declarations and service routines. . /usr/lpp/mmfs/bin/mmglobfuncs . /usr/lpp/mmfs/bin/mmsdrfsdef . /usr/lpp/mmfs/bin/mmfsfuncs sourceFile="mmexportfs.sh" [[ -n $DEBUG || -n $DEBUGmmexportfs ]] && set -x $mmTRACE_ENTER "$*" # Local work files. Names should be of the form: # fn=${tmpDir}fn.${mmcmd}.$$ # Note that the following nodesetMember declaration is the prefix for # the file names that will contain the member nodes of each nodeset. # The actual file names will be of the form $nodesetMembers. nodesetMembers=${tmpDir}nodesetMembers.${mmcmd}.$$ LOCAL_FILES=" $nodesetMembers.* " # Local variable declarations usageMsg=570 oflag="" Pflag="" fsBeingExportedList="" newNodesetIdFound=no oldNodesetId="" fsMountPoint="" existingMountPoints="" existingMinorNumbers="" # Local functions #################################################################### # # Function: Based on the cluster type, guess at what the disk type # for a given disk may be. # # Input: None. # # Output: The type of the disk: vsd, lv, nsd, etc. # # Returns: Always zero. # #################################################################### function assignDiskType # { [[ -n $DEBUG || -n $DEBUGassignDiskType ]] && set -x $mmTRACE_ENTER "$*" typeset diskType wait4RVSD # Determine the value of the wait4RVSD parameter. [[ $MMMODE = rpd ]] && wait4RVSD=$(showCfgValue wait4RVSD) case $MMMODE in sp) diskType=vsd ;; hacmp) diskType=lv ;; rpd) [[ $wait4RVSD = yes ]] && diskType=vsd || diskType=lv ;; lc) diskType=nsd ;; single) diskType=disk ;; *) diskType=unknown ;; esac print -- $diskType return 0 } #--------- end of function assignDiskType -------------------- ###################### # Mainline processing ###################### ################################# # Process the command arguments. ################################# [[ $arg1 = '-?' || $arg1 = '-h' || $arg1 = '--help' || $arg1 = '--' ]] && \ syntaxError "help" $usageMsg [[ $argc -lt 3 ]] && \ syntaxError "missingArgs" $usageMsg device=$arg1 # Save stripe group device (always the first parameter). shift 1 # Drop the device name from the parameter list. while getopts :C:o:P OPT do case $OPT in C) # Export the file systems from the specified nodeset. [[ -n $Cflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" sourceNodesetId=$OPTARG Cflag=yes ;; o) # Name of the output file. [[ -n $oflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" fsExportData=$OPTARG oflag=yes ;; P) # Leave the fs information in place. [[ -n $Pflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" Pflag=yes ;; :) syntaxError "missingValue" $usageMsg $OPTARG ;; +[CoP]) syntaxError "invalidOption" $usageMsg $OPT ;; *) # Invalid option specified. syntaxError "invalidOption" $usageMsg $OPTARG ;; esac done shift OPTIND-1 [[ $# != 0 ]] && syntaxError "extraArg" $usageMsg $1 # Verify an output file is specified. [[ -z $oflag ]] && syntaxError "missingArgs" $usageMsg # Be careful not to inadvertently destroy some other file. if [[ -e $fsExportData ]] then # The file already exists. printErrorMsg 42 $mmcmd $fsExportData cleanupAndExit fi # Temporarily add the user specified output file to the list of files # to be removed automatically upon exit. We do this to assure that # there wil be no partial data in case of a failure. Once the data is # complete, we will restore the original LOCAL_FILES value. LOCAL_FILES_SV="$LOCAL_FILES" LOCAL_FILES="$LOCAL_FILES $fsExportData" ####################################################################### # 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. # # Note: We are using a variation of gpfsInit - gpfsInitGeneric, # which allows the command to still run on old GPFS cluster types. # If the cluster type is lc or single, things work as they always do. # But if the cluster type is sp, rpd, or hacmp, we are dealing with # an obsolete GPFS cluster environment. The daemon will never # be allowed to start under these circumstances, nor will be the bulk # of the mm commands allowed to work. The only exception are commands # (mmexportfs, mmdelnode) needed by the user to migrate to a supported # environment. Under such conditions it is acceptable to assume that # the daemon is indeed not runing anywhere (i.e., there is no need to # run verifyDaemonInactive) and to ignore the true commit processing # and the rebuilding of the mmfs environment. The idea is to allow # the user to run "mmexportfs all", followed by "mmdelnode -a", and # then create a new cluster of type lc. # # Note: If the -P option is specified, we are interested only # in retrieving the file system data without changing the current # mmsdrfs file. There is no need to lock the mmsdrfs file because # it will not be changed. ####################################################################### trap pretrap HUP INT QUIT KILL [[ -n $Pflag ]] && lockId=nolock gpfsInitOutput=$(gpfsInitGeneric $lockId) setGlobalVar $? $gpfsInitOutput # If the current nodeset is requested, # use the nodeset id returned from gpfsInit. [[ $sourceNodesetId = "." ]] && sourceNodesetId=$nsId if [[ $sourceNodesetId = 0 ]] then print -u2 "$mmcmd: The nodeset can not be determined. Use the -C option," print -u2 "or issue the command from a node that belongs to the desired nodeset." cleanupAndExit fi # Determine the lookup order for resolving host names. [[ $osName != AIX ]] && resolveOrder=$(setHostResolveOrder) ################################################### # Make sure that the specified file system exists. ################################################### if [[ $device = all ]] then # The scope of the keyword all depends on whether # -C was specified or not. if [[ -z $sourceNodesetId ]] then nodesetId=$GLOBAL_ID else nodesetId=$sourceNodesetId fi else # Obtain the information about the filesystem from the mmsdrfs file. findFSoutput=$(findFS "$device" $mmsdrfsFile) [[ -z $findFSoutput ]] && cleanupAndExit # Parse the output from the findFS function. set -f ; set -- $findFSoutput ; set +f fqDeviceName=$1 deviceName=$2 nodesetId=$3 # Exit with a message if the command was invoked for a remote file system. if [[ $nodesetId != $HOME_CLUSTER ]] then # Command is not allowed for remote file systems. printErrorMsg 106 $mmcmd $device $nodesetId cleanupAndExit fi if [[ -n $sourceNodesetId && $nodesetId != $sourceNodesetId ]] then print -u2 "$mmcmd: File system $device does not exist in nodeset $sourceNodesetId". cleanupAndExit fi fi # end if [[ $device = all ]] ###################################################################### # Create the new version of the mmsdrfs file and collect the relevant # information for the file systems being exported. ###################################################################### $rm -f $newsdrfs $fsExportData $allClusterNodes $nodesetMembers.* IFS=":" 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 # If this is an sp cluster and it does not already # have a cluster Id, assign it one now. if [[ -z ${v[CLUSTERID_Field]} ]] then timeStamp=$($perl -e 'print time') v[$CLUSTERID_Field]="gpfs$timeStamp" fi # Put the line into the fs export file. print_newLine >> $fsExportData checkForErrors "writing to file $fsExportData" $? # Increment the generation number newGenNumber=${v[$SDRFS_GENNUM_Field]}+1 v[$SDRFS_GENNUM_Field]=$newGenNumber ;; $NODESET_HDR ) # this is the header line for a nodeset # If this is the nodeset from which we are exporting, # put the line into the fs export file. if [[ ${v[$NODESETID_Field]} = $nodesetId || $nodesetId = $GLOBAL_ID ]] then print_newLine >> $fsExportData checkForErrors "writing to file $fsExportData" $? fi ;; $MMFSCFG ) # this line contains mmfs.cfg information for some nodeset # If this is the nodeset from which we are exporting, # put the line into the fs export file. if [[ ${v[$NODESETID_Field]} = $nodesetId || $nodesetId = $GLOBAL_ID ]] then print_newLine >> $fsExportData checkForErrors "writing to file $fsExportData" $? fi ;; $MEMBER_NODE ) # this line describes a node that belongs to some nodeset # Create a file with the names of all nodes in the cluster. # Create separate files with the names of the nodes in each nodeset. if [[ ${v[DESIGNATION_Field]} != $DELETED_NODE ]] then print -- "${v[$REL_HOSTNAME_Field]}" >> $allClusterNodes checkForErrors "writing to file $allClusterNodes" $? print -- "${v[$REL_HOSTNAME_Field]}" >> $nodesetMembers.${v[$NODESETID_Field]} checkForErrors "writing to file $nodesetMembers.${v[$NODESETID_Field]}" $? fi ;; $SG_HEADR ) # this is the header line for some file system # Starting the processing of a new file system. If the file # system should be exported, put the line into the fs export # file and remove the line from the mmsdrfs file. # # Note: Unless explicitly requested by their local name, # remote file systems are not exported. if [[ ${v[$DEV_NAME_Field]} = $deviceName || $device = all && ( $nodesetId = $GLOBAL_ID || $nodesetId = ${v[$NODESETID_Field]} ) && ${v[$FS_TYPE_Field]} = $localfs ]] then # This file system should be exported. exportThisFileSystem=true # Put an informational message: processing file system ... print -- "" # put a blank separator line printInfoMsg 250 $mmcmd ${v[$DEV_NAME_Field]} # Check whether the "odd state" flag is set. if [[ -n ${v[$ODD_STATE_Field]} && ${v[$ODD_STATE_Field]} != no ]] then # Tell the user to bring the filesystem data up to date. printErrorMsg 190 $mmcmd ${v[$DEV_NAME_Field]} ${v[$DEV_NAME_Field]} cleanupAndExit fi # Save the line in the fs export file. print_newLine >> $fsExportData checkForErrors "writing to file $fsExportData" $? printLine=false else # This file system should not be exported. exportThisFileSystem="" fi # end if [[ ${v[$DEV_NAME_Field]} = $deviceName || $device = all && ;; $SG_ETCFS ) # this line is a stanza line for one of the filesystems # If this is the first line in the stanza for a file system # that is being exported, save the device name, mount point # and nodeset to which the file system belongs. All stanza # lines for file systems that are being exported are put into # the fs export file and removed from the mmsdrfs file. if [[ -n $exportThisFileSystem ]] then if [[ ${v[$LINE_NUMBER_Field]} = $MOUNT_POINT_Line ]] then fsInfo="${v[$DEV_NAME_Field]}:${v[$ETCFS_TEXT_Field]}:${v[$NODESETID_Field]}" fsBeingExportedList="$fsInfo $fsBeingExportedList" fi # Save the line in the fs export file. print_newLine >> $fsExportData checkForErrors "writing to file $fsExportData" $? printLine=false fi # end if [[ -n $exportThisFileSystem ]] ;; $SG_MOUNT ) # If the line belongs to a file system that is being exported, put the # line into the fs export file and remove the line from the mmsdrfs file. if [[ -n $exportThisFileSystem ]] then # Save the line in the fs export file. print_newLine >> $fsExportData checkForErrors "writing to file $fsExportData" $? printLine=false fi ;; $SG_DISKS ) # Decide if this disk is to be exported. If the disk belongs to some # file system, the exportThisFileSystem flag already has the correct # value. If this is a free disk, it will be exported only if all file # systems are being exported. Note that the exportThisFileSystem flag # is used to control the exporting of disks that are part of some file # system as well as the exporting of free disks. if [[ ${v[$NODESETID_Field]} = $FREE_DISK ]] then if [[ $device != all ]] then exportThisFileSystem="" else exportThisFileSystem=true # If not done already, put an informational message. if [[ -z $freeDiskStartMsg && -n $fsBeingExportedList ]] then # Put an informational message: processing free disks ... print -- "" # put a blank separator line printInfoMsg 98 $mmcmd freeDiskStartMsg=issued fi fi # end if [[ $device = all ]] fi # end if [[ ${v[$NODESETID_Field]} = $FREE_DISK ]] # If exporting this disk, put the SG_DISKS line into the fs export # file and remove it from the mmsdrfs file. if [[ -n $exportThisFileSystem ]] then # Fail the command if the disk is excluded. # The user needs to repair the file system first. # The only exception is if the -P option is specified. if [[ ${v[$EXCLUDE_Field]} = $excludedDisk && -z $Pflag ]] then print -u2 "$mmcmd: File system ${v[$DEV_NAME_Field]} contains excluded disks." cleanupAndExit fi # Make sure the disk type field is set. [[ -z ${v[$DISK_TYPE_Field]} || ${v[$DISK_TYPE_Field]} = unknown ]] && \ v[$DISK_TYPE_Field]=$(assignDiskType) # Save the line in the fs export file. print_newLine >> $fsExportData checkForErrors "writing to file $fsExportData" $? printLine=false fi # end if [[ -n $exportThisFileSystem ]] ;; * ) # 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 || -n $Pflag ]] 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. # Make sure that everything went OK. if [[ $device = all && -z $fsBeingExportedList ]] then # No file systems were found. printErrorMsg 200 $mmcmd cleanupAndExit fi ############################################ # Sort the new version of the mmsdrfs file. ############################################ LC_ALL=C $SORT_MMSDRFS $newsdrfs -o $newsdrfs checkForErrors "sorting $newsdrfs" $? ############################################## # If the -P option is specified, we are done. ############################################## if [[ -n $Pflag ]] then # Remove the output file from the list of files to be deleted upon exit. LOCAL_FILES="$LOCAL_FILES_SV" cleanupAndExit 0 fi ################################################################ # If this is an old cluster type, we managed to extract the # file system data. Perform a fake commit and take an early # exit. The rest of the mm infrastructure does not know how to # handle a real commit, plus the user is expected to tear down # the obsolete environment right away and create a new cluster. ################################################################ if [[ $MMMODE != lc && $MMMODE != single ]] then # Perform a pseudo commit of the changes on this node only. $cp $newsdrfs $mmsdrfsFile $rm -f ${mmfsEnvLevel}+([0-9]) $touch ${mmfsEnvLevel}$newGenNumber # Remove the output file from the list of files to be deleted upon exit. LOCAL_FILES="$LOCAL_FILES_SV" cleanupAndExit 0 fi # end if [[ $MMMODE != lc && $MMMODE != single ]] ############################################ # Lock the gpfs object to prevent daemons # from starting during the commit phase. ############################################ [[ $getCredCalled = no ]] && getCred setRunningCommand "$mmcmd" $primaryServer checkForErrors setRunningCommand $? gpfsLocked=yes ################################################################ # Make sure the file systems being exported are not mounted # and that the currently-appointed fs managers have resigned. ################################################################ for expFs in $(print -- "$fsBeingExportedList") do IFS=':' set -f ; set -- $expFs ; set +f IFS="$IFS_sv" deviceName=$1 fqDeviceName="/dev/$deviceName" fsMountPoint=$2 nodesetId=$3 if [[ -z $daemonDownVerified ]] then preferredNode=0 $mmcommon onactive $preferredNode $nodesetMembers.$nodesetId \ $NO_FILE_COPY $fqDeviceName $CHECK_ALL $NO_LINK \ $MOUNT_CHECK_ONLY $RESIGN_FSMGR 2>$errMsg rc=$? if [[ $rc -eq $MM_FsMounted ]] then # The file system is still mounted; messages were issued by mmcommon. cleanupAndExit elif [[ $rc -eq $MM_DaemonDown ]] then # GPFS is down on all nodes that we care about; that's just fine. rc=0 daemonDownVerified=yes elif [[ $rc -eq $MM_ConnectionReset ]] then # An internode connection was reset. printErrorMsg 257 $mmcmd cleanupAndExit elif [[ $rc -ne 0 ]] then # An unexpected error occurred during the mount check. if [[ -s $errMsg ]] then # Show the error messages from the daemon. $cat $errMsg 1>&2 else # The mount check failed and there were no messages from the daemon. printErrorMsg 171 $mmcmd "mount check for $fqDeviceName" $rc fi # The command was unable to determine whether the file system is mounted. printErrorMsg 564 $mmcmd $fqDeviceName cleanupAndExit fi $rm -f $errMsg fi # end if [[ -z $daemonDownVerified ]] # If exporting a single file system, remove all traces # of that file system from the nodes. Ignore errors. # If exporting all file systems, we will bypass this # time-consuming process; the cluster will most likely # be destroyed anyway. Plus, we will propagate the # changes at the end of the command like we always do. [[ $device != all ]] && \ $mmcommon onall $nodesetMembers.$nodesetId $unreachedNodes \ rmfs $fqDeviceName $fsMountPoint >/dev/null 2>&1 done # end for expFs in $(print -- "$fsBeingExportedList") ############################################################ # Replace the mmsdrfs file in the sdr with the new version. ############################################################ trap "" HUP INT QUIT KILL gpfsObjectInfo=$(commitChanges \ $nsId $nsId $gpfsObjectInfo $newGenNumber $newsdrfs $primaryServer) rc=$? if [[ $rc -ne 0 ]] then # Cannot replace file in the sdr. printErrorMsg 381 $mmcmd cleanupAndExit fi ################################################################### # Unlock the sdr. ################################################################### freeLockOnServer $primaryServer $ourNodeNumber >/dev/null sdrLocked=no trap posttrap HUP INT QUIT KILL # Remove the output file from the list of files to be deleted upon exit. LOCAL_FILES="$LOCAL_FILES_SV" ################################################################# # Propagate the new mmsdrfs file. This process is asynchronous. ################################################################# propagateSdrfsFile async $allClusterNodes $newsdrfs $newGenNumber cleanupAndExit 0