AIX Tip of the Week

splitmirrorvg Shell Script

Audience: All

Date: March 8, 2002

Audience Systems Administrators, DBA's.

One use for "split mirror copy" is to quickly move large amounts of data between systems on a SSA loop, SAN or equivalent. You simply vary off the volume group containing the copy and vary it on another server. It avoids the congesting the network with large file transfers, and the procedure takes only minutes.

The attached "splitmirrorvg" shell script automates the split mirror copy process. The split copy is placed into a new volume group, which can then be exported/imported onto another system on the same SSA loop or SAN.

The script illustrates many useful AIX LVM commands. It's worth a look even if you don't have a need for split mirror copy.

Acknowledgement: Thanks to Dan Braden for the shell script.


Notes


Steps:
1. create VG
  mkvg -y  -s  
  mkvg -f -y'splitmirrorvg' -s'8' hdisk13 hdisk14 hdisk 15 hdisk17 hdisk18 hdisk19 hdisk20 hdisk21
2. Create LV (original copy)
  mklv -y  -e x -w n   
  mklv -y'lvnum1' -e'x' -w'n' splitmirrorvg 18 hdisk16 hdisk17 hdisk18
3. Create first copy of LV
  mklvcopy  2 
  mklvcopy lvnum1 2 hdisk19 hdisk20 hdisk21
4. Create second copy of LV
  mklvcopy  3 
  mklvcopy lvnum1 3 hdisk13 hdisk14 hdisk15
5. List out LV map

root@f1n3 > lslv -m lvnum1
lvnum1:N/A
LP    PP1  PV1               PP2  PV2               PP3  PV3
0001  0109 hdisk16           0109 hdisk19           0109 hdisk15
0002  0109 hdisk17           0055 hdisk20           0055 hdisk14
0003  0109 hdisk18           0055 hdisk21           0055 hdisk13
0004  0110 hdisk16           0110 hdisk19           0110 hdisk15
0005  0110 hdisk17           0056 hdisk20           0056 hdisk14
0006  0110 hdisk18           0056 hdisk21           0056 hdisk13
0007  0111 hdisk16           0111 hdisk19           0111 hdisk15
0008  0111 hdisk17           0057 hdisk20           0057 hdisk14
0009  0111 hdisk18           0057 hdisk21           0057 hdisk13
0010  0112 hdisk16           0112 hdisk19           0112 hdisk15
0011  0112 hdisk17           0058 hdisk20           0058 hdisk14
0012  0112 hdisk18           0058 hdisk21           0058 hdisk13
0013  0113 hdisk16           0113 hdisk19           0113 hdisk15
0014  0113 hdisk17           0059 hdisk20           0059 hdisk14
0015  0113 hdisk18           0059 hdisk21           0059 hdisk13
0016  0114 hdisk16           0114 hdisk19           0114 hdisk15
0017  0114 hdisk17           0060 hdisk20           0060 hdisk14
0018  0114 hdisk18           0060 hdisk21           0060 hdisk13

6. Create a filesystem for testing (for raw LVs this wouldn't be necessary)
crfs -v jfs -d lvnum1  -m /tmp/fs  -A yes
Note that this creates a jfslog LV which we also need to mirror

7. Mirror the jfslog to (which will also be split later)
mklvcopy loglv00 3 hdisk16 hdisk13
root@f1n3 > lslv -m loglv00
loglv00:N/A
LP    PP1  PV1               PP2  PV2               PP3  PV3
0001  0121 hdisk19           0115 hdisk16           0061 hdisk13

8. Mount the FS and put some data in there for testing
# mount /tmp/fs
# cd /tmp/fs
# cp -R /etc/ .

9. Unmount the filesystem (i.e. stop I/O)
# umount /tmp/fs

10. Split off a copy of the LVs (use hdisk13 so the split LVs are on the same set of hdisks)
 splitlvcopy -y lvnum2 lvnum1 2 hdisk13         (for the filesystem LV)
 splitlvcopy -y newloglv00 loglv00 2 hdisk13    (for the jfslog LV)

root@f1n3> lslv -m lvnum2
lvnum2:N/A
LP    PP1  PV1               PP2  PV2               PP3  PV3
0001  0109 hdisk15
0002  0055 hdisk14
0003  0055 hdisk13
0004  0110 hdisk15
0005  0056 hdisk14
0006  0056 hdisk13
0007  0111 hdisk15
0008  0057 hdisk14
0009  0057 hdisk13
0010  0112 hdisk15
0011  0058 hdisk14
0012  0058 hdisk13
0013  0113 hdisk15
0014  0059 hdisk14
0015  0059 hdisk13
0016  0114 hdisk15
0017  0060 hdisk14
0018  0060 hdisk13
root@f1n3> lslv -m newloglv00
newloglv00:N/A
LP    PP1  PV1               PP2  PV2               PP3  PV3
0001  0061 hdisk13

11. Mount the original LV
# mount /tmp/fs

12. Save the LV maps for newloglv00 and lonum2
Using the reformatmap script:

#!/bin/ksh
# reformap - script to take an LV and get it's map and create a map
#            that can be used by mklv
# input is an LV name, output is a file of name $lvmap
lv=$1
cat /dev/null > ${lv}map
lslv -m $lv | grep -v ^$lv | grep -v ^LP | while read lpnum ppnum pv
do
echo ${pv}:$ppnum >>  ${lv}map
done

# reformatmap lvnum2
# reformatmap newloglv00

root@f1n3 > pg lvnum2map
hdisk15:0109
hdisk14:0055
hdisk13:0055
hdisk15:0110
hdisk14:0056
hdisk13:0056
hdisk15:0111
hdisk14:0057
hdisk13:0057
hdisk15:0112
hdisk14:0058
hdisk13:0058
hdisk15:0113
hdisk14:0059
hdisk13:0059
hdisk15:0114
hdisk14:0060
hdisk13:0060
root@f1n3.dsc.ibm.com (/tmp) > cat newloglv00map
hdisk13:0061

13. Add entry to /etc/filesystems for new filesystem
/tmp/newfs:
        dev             = /dev/lvnum2
        vfs             = jfs
        log             = /dev/newloglv00
        mount           = false
        options         = rw
        account         = false

14. Mount it and see if the data is there (make sure new mount point is there first)
# mkdir /tmp/newfs
# mount /tmp/newfs
# find /tmp/newfs -print

15. Unmount the filesystem and remove the new LVs in preparation for creating them in
   a new VG on hdisk13, hdisk14 and hdisk15
Unmount
# umount /tmp/newfs
Remove the LVs
# rmlv -f lvnum2
# rmlv -f newloglv00

16. Remove the disks from the VG
Remove the disks from the VG
# reducevg splitmirrorvg hdisk13 hdisk14 hdisk15

17. Create a new VG with the same partition size

# mkvg -y newvg -s 8 hdisk13 hdisk14 hdisk15

18. Make the LVs using the maps we saved earlier
 mklv -y lvnum2 -m lvnum2map newvg 18
 mklv -y newloglv00 -m newloglv00map newvg 1
Note that we used the same LVname (lvnum2) and the number of LPs (18)
One can get the number of LPs from the following command:
# lslv  | grep ^LPs | awk '{print $2}'
We also used the same LVname for the jfslog, the mount point doesn't change

19. Mount the filesystem and check it out
# mount /tmp/newfs
# find /tmp/newfs -print


At this time, one could varyoff the VG, then import it on another machine
connected to the disk.

splitmirrorvg Shell Script


#!/bin/ksh
# splitmirrorvg
# Use this script to split off a mirror copy containing all LVs in a VG.
# The split off copy is placed into a new VG so that the data can be
# exported/imported into another system.
#
# Usage: splitmirrorvg  
# where the listed hdisks are a set of disks that have one copy of the LVs on
# them and will be put into another VG
#
# The new VG and LVs will be preceded by the prefix mir to
# designate that it is a mirrored VG/LV.  Mount points will be
# .
#
# NOTE:  NO CHECKING OF THE SETUP IS DONE.  IT IS ASSUMED THAT YOUR VG IS SETUP
# AND MIRRORED CORRECTLY USING SUPER STRICT COPIES (I.E. EACH COPY OF THE LVS
# ARE ON DISTINCT SETS OF DISKS), and that your input is correct.
# This also assumes you have 3 copies of the LVs - it won't work for 2
# This also assumes any JFS log you have is of type "jfslog"
# This also assumes the VG is synced
# Your LV and VG names should not exceed 12 characters
#
# Standard Disclaimers:  backup your data, test first on a development system.


#---------------------------------------------
# "Are you sure" warning message
# You can erase this section between the lines

tput clear
echo $0 ":This script splits off the LVs in the mirror copy on " $@
echo "into a new volume group."
echo "*** Caution *** This script assumes your VG is setup and mirrored "
echo "correctly. See comments in this script."
echo "\nContinue?  (yes/no)"
read
if [[ ! $REPLY = yes ]] then
	echo "Exiting"
        exit
fi

#--------------------------------------------



# Get a list of LV, mountpoint, #LPs, and hdisk and put them in a file
cat /dev/null > /tmp/splitlvdata

# First get a list of the LVs in the VG
lvs=`lsvg -l $1 | tail -n +3 | awk '{print $1}'`

# Now we loop on the LVs
for lv in ${lvs}
do
   # determine the mount point if any associated with the LV
   mountpt=`lslv $lv | grep "MOUNT" | awk '{print $3}'`
   # Determine the number of LPs
   lps=`lslv $lv | grep ^LPs | awk '{print $2}'`
   # Determine one of the input hdisks on which the copy exists
   for disk in $@
   do
     if [ "$disk" = "$1" ]
     then continue
     fi
     lspv -l $disk | grep ^$lv > /dev/null
     if [ "$?" = "0" ]
     then  {
        hdisk=$disk
        break
        }
     fi
   done
echo "$lv $mountpt $lps $hdisk" >> /tmp/splitlvdata
done

# Now for each LV, we unmount it first
print "Starting to umount the filesystems"
for lv in ${lvs}
do
   # Do the umount only if it is a filesystem
   fs=`grep ^$lv /tmp/splitlvdata | cut -f2 -d" "`
   if [ "$fs" != "N/A" ]
     then  {
     # Check to see if it is mounted first
     mount | grep " /dev/$lv " > /dev/null
     if [ "$?" = "0" ]
         then {
            umount $fs
            if [ "$?" != "0" ]
            then  {
               print "Error unmounting $fs - script stopping"
               exit 99
            }
           fi
        }
    fi
    }
  fi
done

# Now for each LV, we split it
print "Starting to split the LVs"
for lv in ${lvs}
do
   hdisk=`grep ^$lv /tmp/splitlvdata | cut -f4 -d" "`
   splitlvcopy -y mir${lv} $lv 2 $hdisk
done

# Now we mount the original filesystems and assure the new mount point exists
for lv in ${lvs}
do
  mountpt=`grep ^$lv /tmp/splitlvdata | cut -f2 -d" "`
  if [ "$mountpt" != "N/A" ]
  then
    mount $mountpt
    mkdir $mountpt/mir
  fi
done
print "Application can be restarted now!"

# Now we update /etc/filesystems
print "Starting to update /etc/filesystems"
# To do this first we need to know which is the JFS log
lsvg -l $1| grep jfslog > /dev/null
if [ "$?" = "0" ]
   then log=`lsvg -l $1 | grep jfslog | cut -f1 -d" "`
fi
for lv in ${lvs}
do
   # is this lv a filesystem?
   mountpt=`grep ^$lv /tmp/splitlvdata | cut -f2 -d" "`/mir
   if [ "$mountpt" != "N/A/mir" ]
   then {
      echo " " >> /etc/filesystems
      echo "$mountpt:" >> /etc/filesystems
      echo "    dev     = /dev/mir${lv}" >> /etc/filesystems
      echo "    vfs     = jfs" >> /etc/filesystems
      echo "    log     = /dev/mir${log}" >> /etc/filesystems
      echo "    mount   = false" >> /etc/filesystems
      echo "    options = rw" >> /etc/filesystems
      echo "    account = false" >> /etc/filesystems
   }
  fi
done

# Now make map files for the LVs
print "Starting to make map files"
for lv in ${lvs}
do
   cat /dev/null > /tmp/mir${lv}map
   lslv -m mir$lv | grep -v ^mir$lv: | grep -v ^LP | while read lpnum ppnum pv
     do
     echo ${pv}:$ppnum >>  /tmp/mir${lv}map
     done
done

# Now remove the mirLVs
print "Removing the split LVs"
for lv in ${lvs}
do
   rmlv -f mir$lv
done

# Now remove the input disks from the VG
print "Removing the disks from the VG"
disks=`echo $@ | cut -f 2- -d" "`
reducevg $1 $disks

# Now create the newVG
print "Starting to make the new VG"
# First we need the old partition size
ppsize=`lsvg $1 | grep "PP SIZE" | awk '{print $6}'`

mkvg -y mir$1 -s $ppsize $disks

# Now create the LVs using the maps

for lv in ${lvs}
do
   lps=`grep ^$lv /tmp/splitlvdata | cut -f 3 -d" "1`
   mklv -y mir$lv -m /tmp/mir${lv}map mir$1 $lps
done


Bruce Spencer,
baspence@us.ibm.com