source: gpfs_3.1_ker2.6.20/lpp/mmfs/bin/mmfileid @ 16

Last change on this file since 16 was 16, checked in by rock, 16 years ago
  • Property svn:executable set to *
File size: 18.0 KB
Line 
1#!/bin/ksh
2# IBM_PROLOG_BEGIN_TAG
3# This is an automatically generated prolog.
4
5
6
7# Licensed Materials - Property of IBM
8
9# (C) COPYRIGHT International Business Machines Corp. 2003,2007
10# All Rights Reserved
11
12# US Government Users Restricted Rights - Use, duplication or
13# disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
14
15# IBM_PROLOG_END_TAG
16# @(#)33 1.30.1.2 src/avs/fs/mmfs/ts/admin/mmfileid.sh, mmfs, avs_rgpfs24, rgpfs24s009a 1/14/07 03:50:17
17##############################################################################
18#
19# Usage:
20#
21#   mmfileid Device
22#     {-d [NodeName]:{DiskName|DiskNum|BROKEN}:[PhysAddr1[-PhysAddr2]] | -F DescFile}
23#     [-o OutputFile] [-f NumThreads] [-t Directory]
24#
25# where
26#
27#   Nodename:   specifies a node in the GPFS node set that has access to
28#                 the specified disk
29#   DiskName:   specifies the physical volume name
30#               if no nodename, this is the GPFS diskname or disk number
31#               (mmlsdisk $fsname -i)
32#   PhysAddr1:  the disk physical sector number
33#               if no nodename, this is the GPFS logical sector; if omitted, 0
34#   PhysAddr2:  the last sector number; if omitted, same as PhysAddr1
35#
36#   If PhysAddr1 and PhysAddr2 are both 0, the entire disk is searched.
37#
38#   If BROKEN is used instead of a disk name, files that have disk addresses
39#   marked as "broken" will be found.  Broken addresses are left when a disk
40#   has been deleted, but the data could not be salvaged.
41#
42#   -F DescFile   specifies a file containing the physical volume names
43#                 and the corresponding disk physical address.
44#                 Each line of the file should have the following format:
45#      [NodeName]:{DiskName|DiskNum|BROKEN}:[PhysAddr1[-PhysAddr2]]
46#
47#   -o outFile    format: <inode number> <file name>
48#
49#   -f num        number of threads that need to be created
50#                   (used by tsfindinode utility)
51#
52#   -t tempDirName  Override by using /var/mmfs/tmp for temporary files
53#                   and sorting.
54#
55##############################################################################
56
57# Include global declarations and service routines.
58. /usr/lpp/mmfs/bin/mmglobfuncs
59. /usr/lpp/mmfs/bin/mmsdrfsdef
60. /usr/lpp/mmfs/bin/mmfsfuncs
61
62sourceFile="mmfileid.sh"
63[[ -n $DEBUG || -n $DEBUGmmfileid ]] && set -x
64$mmTRACE_ENTER "$*"
65
66# Local work files.  Names should be of the form:
67#   fn=${tmpDir}fn.${mmcmd}.$$
68inputPVDesc=${tmpDir}inputPVDesc.${mmcmd}.$$  # file of pvs from the input list
69newLVDesc=${tmpDir}newLVDesc.${mmcmd}.$$      # LV list passed to tsfileid
70outFidu=${tmpDir}outFidu.${mmcmd}.$$          # tsfileid output goes here
71localLspvList=${tmpDir}lspvList.${mmcmd}.$$   # local lspv output list
72inInodeList=${tmpDir}inInodeList.${mmcmd}.$$  # input to the tsfindinode cmd
73
74LOCAL_FILES=" $inputPVDesc $newLVDesc $outFidu $localLspvList $inInodeList"
75
76# Local variables
77
78usageMsg=560                   # mmfileid usage message
79integer rc=0                   # return code default to success
80integer numThreads=16          # default is 16 threads
81
82newLVList=""
83pvDescFile=""
84inodeDesc=""
85specialInode=""
86fiduDevicename=NULL
87
88dflag=""                       # indicator that -d was specified
89diskPVList=""                  # arguments following the -d argument
90Farg=""                        # DescFile following -F
91Fflag=""                       # indicator that -F was specified
92fflag=""                       # indicator that -f was specified
93oflag=""                       # indicator that -o was specified
94tflag=""                       # indicator that -t was specified
95
96# Local routines
97
98
99##############################################################################
100#
101# Preprocessor function
102#
103# mmfileidPreprocess scans each line in the DescFile and tokenizes the line.
104#
105# 1. Find PVID for hdisk.  If error, stop processing.
106# 2. Get gpfsDiskName.  If error, stop processing.
107# 3. Convert ranges.  If error, stop processing.
108# 4. Echo new values to $newLVDescFile. (Format:  gpfsDiskName:lvnum1-lvnum2)
109#
110##############################################################################
111function mmfileidPreprocess
112{
113  typeset sourceFile="mmfileid.sh"
114  [[ -n $DEBUG || -n $DEBUGmmfileidPreprocess ]] && set -x
115  $mmTRACE_ENTER "$*"
116
117  typeset addr1 addr2 pvRange pvDesc lvRange hostResult
118  typeset diskName=""
119  typeset gpfsDiskName=""
120  typeset nodeName=""
121  typeset nodeset1=""
122  typeset nodeset2=""
123  typeset pvID=""
124  typeset relNodeName=""
125  integer lineNumber=0
126  typeset ec=0
127
128  # Loop through the physical volume descriptors file.
129  exec 3<&-
130  exec 3< $pvDescFile
131  while read -u3 pvDesc
132  do
133    IFS=':'
134    set -f ; set -- $pvDesc ; set +f
135    nodeName=$1
136    diskName=$2
137    pvRange=$3
138    IFS='-'
139    set -f ; set -- $pvRange ; set +f
140    addr1=$1
141    addr2=$2
142    IFS="$IFS_sv"
143
144    lineNumber=lineNumber+1
145
146    # Skip empty and comment lines.
147    [[ $pvDesc = *([$BLANKchar$TABchar])   ]] && continue
148    [[ $pvDesc = *([$BLANKchar$TABchar])#* ]] && continue
149
150    # Make sure the input arguments are all defined.
151    [[ -z $addr1 ]] && addr1=-1
152    [[ -z $addr2 ]] && addr2=$addr1
153    if [[ -z $diskName ]]
154    then
155      if [[ -n $Fflag ]]
156      then
157        printErrorMsg 567 $mmcmd $lineNumber $pvDescFile
158        print -u2 $pvDesc"
159        syntaxError "incorrectSyntax" 0 "[NodeName]:{DiskName|DiskNum|BROKEN}:[PhysAddr1[-PhysAddr2]]"
160      else
161        printErrorMsg 560 $mmcmd
162        cleanupAndExit 1
163      fi
164    fi
165
166    # Check for address range correctness.
167    if [[ $addr1 -gt $addr2 ]]
168    then
169      if [[ -n $Fflag ]]
170      then
171        printErrorMsg 567 $mmcmd $lineNumber $pvDescFile
172        print -u2 $pvDesc"
173      fi
174      syntaxError "incorrectRange" 0 $addr1 $addr2
175    fi
176
177    if [[ -z $nodeName ]]
178    then
179      gpfsDiskName=$diskName
180      if [[ $addr1 = -1 && $addr2 = -1 ]]
181      then
182        lvRange="0-0"
183      else
184        lvRange="$addr1-$addr2"
185      fi
186    else
187      # Find the reliable hostname for specified node.
188      relNodeName=$(checkAndConvertNodeValue $nodeName $REL_HOSTNAME_Field)
189      [[ $? -ne 0 ]] && cleanupAndExit
190
191      # Get our nodeset id.
192      nodeset1=$(getNodeInfo $NODESETID_Field $REL_HOSTNAME_Field $relNodeName $GLOBAL_ID $mmsdrfsFile)
193      if [[ -z $nodeset1 ]]
194      then
195        printErrorMsg 282 $mmcmd $relNodeName
196        cleanupAndExit 1
197      fi
198
199      # Get the GPFS disk name.
200      if [[ $relNodeName = $ourNodeName ]]
201      then
202        gpfsDiskName=$(getGpfsDiskName $diskName 2>$errMsg)
203      else
204        gpfsDiskName=$($mmcommon on1 $relNodeName getGpfsDiskName $diskName 2>$errMsg)
205      fi
206      ec=$?
207      if [[ $ec -ne 0 || -z $gpfsDiskName ]]
208      then
209        # We were unable to acquire the pvid.
210        [[ -s $errMsg ]] && $cat $errMsg 1>&2
211        printErrorMsg 585 $mmcmd $diskName $relNodeName
212        $rm -f $errMsg
213        cleanupAndExit $ec
214      fi
215
216      $rm -f $errMsg
217
218      nodeset2=$(getDiskInfo $NODESETID_Field $gpfsDiskName $mmsdrfsFile)
219
220      # Check whether the node and diskName belong to the same GPFS nodeset.
221      if [[ $nodeset1 != $nodeset2 ]]
222      then
223        print -u2 "$mmcmd: Disk $diskName and node $relNodeName do not belong to the same nodeset."
224        cleanupAndExit 1
225      fi
226
227      # Invoke tsaddrmap on the specified node to convert
228      # the physical disk address to a logical disk address.
229      if [[ $relNodeName = $ourNodeName ]]
230      then
231        lvRange=$($tsaddrmap $diskName -p1 $addr1 -p2 $addr2 2>$errMsg)
232      else
233        lvRange=$($mmcommon on1 $relNodeName adminCmd tsaddrmap $diskName -p1 $addr1 -p2 $addr2 2>$errMsg)
234      fi
235      ec=$?
236      if [[ $ec -ne 0 || -z $lvRange ]]
237      then
238        # Range error.  Show any tsaddrmap errors and issue an error message.
239        [[ -s $errMsg ]] && $cat $errMsg 1>&2
240        printErrorMsg 587 $mmcmd $diskName $relNodeName
241        $rm -f $errMsg
242        cleanupAndExit $ec
243      fi
244      $rm -f $errMsg
245    fi  # end of if [[ -z $nodeName ]]
246
247    # Add the converted data that needs to be passed to the tsfileid command.
248    print -- "${gpfsDiskName}:${lvRange}" >> $newLVDesc
249
250  done  # end of while read -u3 pvDesc do
251
252  return 0
253
254}  # ----- end of function mmfileidPreprocess ---------------------
255
256
257##############################################################################
258#
259# Function:  mmfileidPostprocess
260#
261# This function merges the tsfileid output with the tsfindinode output.
262#
263# Format of tsfileid output:     {inodeNumber address snapshotId}
264# Format of tsfindinode output:  {inodeNumber fileName}
265# Format after post processing:  {inodeNumber address snapshotId fileName}
266#
267# Note:  Ideally, it would have been better for tsfindinode to do this.
268#
269##############################################################################
270function mmfileidPostprocess
271{
272  typeset sourceFile="mmfileid.sh"
273  [[ -n $DEBUG || -n $DEBUGmmfileidPostprocess ]] && set -x
274  $mmTRACE_ENTER "$*"
275
276  integer indexCnt=0
277  integer i=0
278  typeset inode inodeName lvAddress tsInode snapId
279  typeset inodeLine inodeArrayData
280  set -f ; set -A inodeArray ; set +f
281
282  # Reuse the localLspvList file.
283  $tsfindinode -i $inInodeList $fiduDevicename -t $numThreads > $localLspvList
284  rc=$?
285  if [[ $rc -ne 0 ]]
286  then
287    $cat $inInodeList $localLspvList
288    cleanupAndExit $rc
289  fi
290
291  sortdir="/tmp"
292  [[ -n $tflag ]] && sortdir=$tmpdir
293  $sort -T $sortdir -b -k 1,1n $localLspvList -o $localLspvList
294  rc=$?
295  [[ $rc = 0 ]] && $sort -T $sortdir -b -k 1,1n $inInodeList -o $inInodeList && rc=$?
296  if [[ $rc -ne 0 ]]
297  then
298    $cat $inInodeList $localLspvList
299    printErrorMsg 171 "$mmcmd" "sort" $rc
300    cleanupAndExit $rc
301  fi
302
303  $join -1 1 -2 1 $inInodeList $localLspvList
304  rc=$?
305  if [[ $rc -ne 0 ]]
306  then
307    $cat $inInodeList $localLspvList
308    printErrorMsg 171 "$mmcmd" "mmfileidPostprocess: join " $rc
309    cleanupAndExit $rc
310  fi
311
312  return 0
313
314}  # ----- end of function mmfileidPostprocess ---------------------
315
316
317
318#######################
319# Mainline processing
320#######################
321
322
323##############################################################################
324# Process the input arguments.
325##############################################################################
326[[ $arg1 = '-?' || $arg1 = '-h' || $arg1 = '--help' || $arg1 = '--' ]] &&  \
327  syntaxError "help" $usageMsg
328
329[[ $argc -lt 2  ]] &&  \
330  syntaxError "missingArgs" $usageMsg
331
332device=$arg1     # Save stripe group device (always the first parameter).
333shift 1
334
335while getopts :d:F:f:o:t: OPT
336do
337
338  case $OPT in
339    d) # Only one disk address needs to be searched.
340       [[ -n $dflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
341       [[ -n $Fflag ]] &&  \
342         syntaxError "invalidCombination"  $usageMsg "-d" "-F"
343       diskPVList=$OPTARG
344       dflag=yes
345       ;;
346
347    F) # DescFile file
348       [[ -n $Fflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
349       [[ -n $dflag ]] &&  \
350          syntaxError "invalidCombination"  $usageMsg "-d" "-F"
351       Farg=$OPTARG
352       Fflag=yes
353       ;;
354
355    o) # output filename
356       [[ -n $oflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
357       outFname=$OPTARG
358       oflag=yes
359       ;;
360
361    f) # number of threads to be spawned
362       [[ -n $fflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
363       numThreads=$(checkIntRange "-f" $OPTARG 1)
364       [[ $? -ne 0 ]] && cleanupAndExit
365       fflag=yes
366       ;;
367
368    t) # temp working dir name
369       [[ -n $tflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT"
370       tmpDir=${OPTARG}/
371       tflag=yes
372       # Reset local work files.
373       inputPVDesc=${tmpDir}inputPVDesc.${mmcmd}.$$  # file of physical volumes
374                                                     #   from the input list
375       newLVDesc=${tmpDir}newLVDesc.${mmcmd}.$$    # LV list passed to tsfileid
376       outFidu=${tmpDir}outFidu.${mmcmd}.$$        # tsfileid output goes here
377       localLspvList=${tmpDir}lspvList.${mmcmd}.$$   # local lspv output list
378       inInodeList=${tmpDir}inInodeList.${mmcmd}.$$  # input to the tsfindinode cmd
379       LOCAL_FILES=" $inputPVDesc $newLVDesc $outFidu $localLspvList $inInodeList"
380
381       ;;
382
383    +[dFoft]) # invalid option specified
384       syntaxError "invalidOption" $usageMsg $OPT
385       ;;
386
387    :) # missing required value after an option
388       syntaxError "missingValue" $usageMsg $OPTARG
389       ;;
390
391    *) # invalid option specified
392       syntaxError "invalidOption" $usageMsg $OPTARG
393       ;;
394
395  esac
396
397done
398
399shift OPTIND-1   # Drop the processed options from the parameter list.
400[[ $# != 0 ]] && syntaxError "extraArg" $usageMsg $1
401
402
403# Finish the parameter checking.
404
405#####################################################################
406# If -d was specified, create a file that contains the physical
407# disk address information of the specified nodes.  If the -F option
408# was used, just use its operand as the file for disk addresses.
409#####################################################################
410if [[ -n $dflag ]]
411then
412  # Add the physical volume descriptor to the descriptor file.
413  print -- $diskPVList > $inputPVDesc
414  checkForErrors "writing to file $inputPVDesc" $?
415  pvDescFile=$inputPVDesc
416fi
417
418if [[ -n $Fflag ]]
419then
420  # The -f option was specified.  Check whether the file exists.
421  if [[ ! -f $Farg || ! -r $Farg ]]
422  then
423    # Can't read the input disk address file.
424    printErrorMsg 43 $mmcmd $Farg
425    cleanupAndExit
426  fi
427
428  # Check that the physical volume descriptors file is not empty.
429  if [[ ! -s $Farg ]]
430  then
431    # The descriptors file is empty.
432    printErrorMsg 561 $mmcmd $Farg
433    cleanupAndExit
434  fi
435  pvDescFile=$Farg
436fi
437
438
439######################################################################
440# Set up trap exception handling and call the gpfsInit function.
441# It will ensure that the local copy of the mmsdrfs and the rest of
442# the GPFS system files are up-to-date and will obtain the sdr lock.
443######################################################################
444trap pretrap HUP INT QUIT KILL
445gpfsInitOutput=$(gpfsInit $lockId)
446setGlobalVar $? $gpfsInitOutput
447
448[[ -z $ourNodeName ]] && getLocalNodeData    # sanity check
449
450
451############################################################
452# Make sure the specified file system exists and is local.
453############################################################
454findFSoutput=$(findFS "$device" $mmsdrfsFile)
455[[ -z $findFSoutput ]] && cleanupAndExit
456
457# Parse the output from the findFS function.
458set -f ; set -- $findFSoutput ; set +f
459fqDeviceName=$1
460deviceName=$2
461fsHomeCluster=$3
462
463# Exit with a message if the command was invoked for a remote file system.
464if [[ $fsHomeCluster != $HOME_CLUSTER ]]
465then
466  # Command is not allowed for remote file systems.
467  printErrorMsg 106 $mmcmd $device $fsHomeCluster
468  cleanupAndExit 1
469fi
470
471# Determine the lookup order for resolving host names.
472[[ $osName != AIX ]] && resolveOrder=$(setHostResolveOrder)
473
474# mmfileid requires that the device be mounted on the node on which
475# mmfileid is executed.  If this is not true, tsfindinode will fail.
476if [[ $osName = Linux ]]; then
477  fiduDevicename=$($awk '{if ($1 == fs) print $2}' fs="/dev/$deviceName" $etcFilesystems)
478else
479  fiduDevicename=$($lsfs -c "/dev/$deviceName" 2>/dev/null | $tail -n +2 | $awk -F: '{print $1}')
480fi
481
482# Check whether the filesystem is locally mounted.
483# This is required or the later invocation of tsfindinode will not work.
484$tsfindinode -i 1 $fiduDevicename > /dev/null 2>&1
485rc=$?
486if [[ $rc -ne 0 ]]
487then
488  printErrorMsg 563 $mmcmd $deviceName $ourNodeName
489  cleanupAndExit 1
490fi
491
492# Create a file containing the local output of the lspv command.
493if [[ $osName = AIX ]]
494then
495  $(LC_ALL=C $lspv > $localLspvList)
496  rc=$?
497  if [[ $rc -ne 0 ]]
498  then
499    cleanupAndExit $rc
500  fi
501else   # Use the output of the mmlsnsd command in the non-AIX case.
502  $mmlsnsd -f $deviceName -m > $localLspvList
503  rc=$?
504  if [[ $rc -ne 0 ]]
505  then
506    cleanupAndExit $rc
507  fi
508fi
509
510
511
512# Pre-process the input.
513mmfileidPreprocess
514
515
516#################################################
517# If the file system is in a different nodeset,
518# or the local daemon is not available, find an
519# active node and send the command there.
520#################################################
521
522# Create a file with the reliable names that form
523# the cluster to which the file system belongs.
524nodeCount=$(getNodeFile $REL_HOSTNAME_Field $fsHomeCluster $mmsdrfsFile $nodefile)
525if [[ $nodeCount -eq 0 ]]
526then
527  # The cluster is empty; there is no node to run the command.
528  printErrorMsg 171 $mmcmd "getNodeFile (nodeCount=0)" 1
529  cleanupAndExit
530fi
531
532preferredNode=0
533$mmcommon onactive $preferredNode $nodefile                  \
534                   $newLVDesc $NO_MOUNT_CHECK NULL $NO_LINK  \
535                   tsfileid $fqDeviceName -F $newLVDesc > $outFidu
536rc=$?
537if [[ $rc -ne 0 ]]
538then
539  cleanupAndExit $rc
540fi
541
542
543#######################################################################
544# Check whether the output from tsfileid is empty.  If so, it means
545# that tsfileid returned successfully (rc already checked above)
546# but could not find any disk addresses that matched the input.
547#######################################################################
548if [[ ! -s $outFidu ]]
549then
550  # tsfileid did not find any addresses that matched the input.
551  printErrorMsg 562 $mmcmd $outFidu
552  cleanupAndExit $rc
553fi
554
555# If oflag is true, then create an empty output filename.
556[[ -n $oflag ]] && $rm -f $outFname
557
558
559#####################################################################
560# Look for special inodes (line starts with "Address").
561# tsfindinode cannot understand these special inode comments.
562# Convert the inode numbers returned by tsfileid to file names.
563#####################################################################
564# If an output file name was specified, redirect stdout to the file.
565[[ -n $oflag ]] && exec 1>> $outFname
566
567exec 3<&-
568exec 3< $outFidu
569while read -u3 inodeDesc
570do
571  set -f ; set -- $inodeDesc ; set +f
572  specialInode=$1
573
574  # Don't put lines for special inodes (i.e., those that start with
575  # "Address") into the file that will be passed to tsfindinode.
576  if [[ $specialInode = "Address" ]]
577  then
578    print $inodeDesc
579  else
580    print $inodeDesc >> $inInodeList
581  fi
582done
583
584# Call mmfileidPostprocess only if the inInodeList file is not empty.
585if [[ ! -s $inInodeList ]]
586then
587  rc=$?
588  cleanupAndExit $rc
589fi
590
591mmfileidPostprocess
592
593cleanupAndExit 0
594
Note: See TracBrowser for help on using the repository browser.