BigAdmin System Administration Portal
Community-Submitted Tech Tip
Print-friendly VersionPrint-friendly Version
This content is submitted by a BigAdmin user. It has not been reviewed for technical accuracy by Sun Microsystems, though it may have been lightly edited to improve readability. If you find an error or would like to comment on the article, please contact the submitter or use the comment field at the bottom of the article. Community submissions may not follow Sun trademark guidelines. For information on Sun trademarks, please see http://www.sun.com/suntrademarks/.
 
 

Scripts for Backing Up and Restoring ZFS File Systems in the Solaris 10 OS

Victor Feng, October 2007

Introduction

This tech tip provides an overview of two scripts for the Solaris 10 Operating System: a zfsdumpd.sh script for backing up ZFS file systems and a zfsrestored.sh script for restoring ZFS file systems.

As you know, UFS has ufsdump and ufsrestore utilities. ZFS is a great file system, but it does not have equivalent zfsdump and zfsrestore utilities. If your environment has 100 users, and each user has their own file system, using the zfsdumpd.sh and zfsrestored.sh scripts can save you a lot of time backing up and restoring those 100 ZFS file systems.

Here's the source code for the two scripts. Please rename the files so that the extension is .sh instead of .txt.

Explanation of the zfsdumpd.sh Script

Usage

  zfsdumpd.sh [-d backup_dir] [-r] [-z zfs]

where:

  • -d backup_dir specifies the directory in which to back up the file system. The default backup directory is /var/zfsbk on the disk, which can be changed through $DIR in the zfsdumpd.sh script.

  • -r causes the script to recursively back up the file system's descendants.

  • -z zfs specifies which one file system should be backed up. Without the -z option, the script backs up every file system.

The zfsdumpd.sh script does not accept positional parameters. If there are any positional parameters, the total number of parameters will not equal the number of command-line options and the script will exit when the following script code is executed:

  [ $# -ne `expr $OPTIND - 1` ] && Usage $0 && exit 2

The zfsdumpd.sh script dumps file systems to disk using the zfs send command.

If -z zfs is not specified, $zfs will be empty when the following script code is executed:

  (if [ "X$zfs" != X ]),

In such a case, Create_BackupSnapshotsAll is called to create and back up a snapshot for each file system. Create_BackupSnapshotsAll destroys each existing snapshot first. The snapshot format is filesystem@today's_date, for example, tank/home/bo@20070910.

If -z zfs is specified, Create_BackupSnapshots is called to create and back up a snapshot for the specified file system. Any existing snapshot is deleted first.

If -r is specified, Create_BackupSnapshots creates and backs up a snapshot for each descendant file system. Any existing snapshots are deleted first.

For each snapshot that is created, for example, tank/home/bo@20070910, GetBackupfileprefixFromSnapshot determines the backup file prefix in the format path_to_filesystem.today's_date, for example, tank_home_bo.20070910. Before the backup is created in /var/zfsbk, the script deletes any existing file that has the format path_to_filesystem.*, for example, tank_home_bo.*.

for snapshot in $SNAPSHOTS; do
  file_prefix=`GetBackupfileprefixFromSnapshot "$snapshot"`
  if find "$DIR" | grep "${file_prefix}\." >/dev/null 2>&1; then
      rm ${DIR}/${file_prefix}.*
  fi

  if zfs send "$snapshot" > ${DIR}/${file_prefix}.$mydate; then
      myzfs=`echo $snapshot | awk -F@ '{print $1}'`
      echo "$myzfs is backed up as ${DIR}/${file_prefix}.$mydate"
  fi
done

Examples

Example 1: Back up each file system in every storage pool in the system.

  # zfsdumpd.sh

Example 2: Recursively back up each file system in the storage pool tank.

  # zfsdumpd.sh -r -z tank

Example 3: Recursively back up tank/home.

  # zfsdumpd.sh -r -z tank/home

Example 4: Back up tank/home.

  # zfsdumpd.sh -z tank/home

Explanation of the zfsrestored.sh Script

Usage

  zfsrestored.sh [-d backup_dir] [-n] [-r] [-z zfs]

where:

  • -d backup_dir specifies the directory from which to restore the file system. The default restore directory is /var/zfsbk on disk, which can be changed through $DIR in the zfsrestored.sh script.

  • -n specifies to not back up the file system to a temporary directory before restoring. The default temporary backup dir is /var/zfsbk_tmp, which can be changed through $DIRTMP in the zfsrestored.sh script.

  • -r causes the script to recursively restore the file system's descendants.

  • -z zfs specifies which one file system should be restored. Without the -z option, the script restores every file system.

The zfsrestored.sh script restores file systems from the disk using the zfs receive command.

If -z zfs is not specified, $zfs will be empty when the following script code is executed:

  (if [ "X$zfs" != X ]),

In such a case, then each file system is restored. For each file system in each storage pool, CheckBackupNeeds checks to see if there is a backup. If not, the zfsrestored.sh script displays a "backup needed" message and exits.

for zfs in $POOLS;  do
  ZFSs=`zfs list -t filesystem -o name -r $zfs | grep -vw NAME`
    CheckBackupNeeds
done

If -n is not specified, (that is, $nobackup equals 1), the zfsdumpd.sh script is called to dump all the file systems to a temporary directory in case you want to roll back. For the root file system in each pool, the script destroys the descendants, then restores the root file system and its descendants using RestoreBasedonCurrentZfs.

[ $nobackup -eq 1 ] && zfsdumpd.sh -d $DIRTMP
  for zfs in $POOLS;  do
    ZFSs=`zfs list -t filesystem -o name -r $zfs | grep -vw NAME`
    zfs destroy -r $zfs
      RestoreBasedonCurrentZfs
  done

RestoreBasedonCurrentZfs calls RestoreSingleCurrentZfs to restore a file system and its descendants.

The root file system is not restored back to its original place, because whenever a pool is created, a corresponding root file system is created for it. So a good practice is to not put anything in the root file system except for creating the file system in it.

For a file system, for example, tank/home/bo, GetBackupfileprefixFromZfsname gets the backup file's prefix (tank_home_bo). Then the script looks for the backup file using the file prefix, and it restores the backup snapshot.

RestoreSingleCurrentZfs ()
{
  each_zfs=$1
  if echo $POOLS | grep -w $each_zfs > /dev/null;   then
    echo "Warning: $each_zfs is not allowed to restore. You may
      use zfs receive $each_zfs/xxx"
  else
    file_prefix=`GetBackupfileprefixFromZfsname $each_zfs`
    BACKUPSNAPSHOT=`find "$DIR" | grep "$file_prefix\."`

    if zfs receive $each_zfs < $BACKUPSNAPSHOT; then
      echo "$each_zfs is restored from $BACKUPSNAPSHOT"
    fi
  fi
}
 

If -z zfs is specified, we need to identify some illegal file systems, for example, /tank/home/bo and tank/home/bo.

if echo $zfs | egrep "^/|/$" > /dev/null
 then
   echo "The format of zfs is tank/home/norma"
   exit 2
 fi

If -r is used with -z zfs, the zfsrestored.sh script checks to see whether the file system exists. 1) If it exists, the script checks to see if all the file systems have a backup. 2) If it does not exist, the script calls RestoreBasedonBackupZfss to restore whatever it could find in the default backup location.

if [ $recursive -eq 0 ]
  then
    if ZFSs=`zfs list -t filesystem -o name -r $zfs 2>/dev/null |
      grep -vw NAME`
    then
      CheckBackupNeeds
      [ $nobackup -eq 1 ] && zfsdumpd.sh -d $DIRTMP -r -z $zfs
      zfs destroy -r $zfs

      if RestoreBasedonCurrentZfss; then
        echo "\nYou may empty $DIRTMP after checking the
          restoration."
      fi
    else
       RestoreBasedonBackupZfss $zfs
    fi
else

RestoreBasedonBackupZfss first gets the backup file prefix for the file system, for example, tank_home_bo. Then it searches the backup snapshot file for the file system and all of its descendants using prefixes with the format tank_home_bo.* and tank_home_bo_*. Then GetZfsnameFromSnapshot gets the file system (for example, tank/home/bo) from its backup snapshot file (for example, tank_home_bo.20070910). Finally, the file system (for example, tank/home/bo) is restored from the backup file (for example, tank_home_bo.20070910). If there is no backup file, the script displays an error and exits.

RestoreBasedonBackupZfss ()
{
  file_prefix=`GetBackupfileprefixFromZfsname $1`
   if find "$DIR" | egrep "${file_prefix}_|${file_prefix}\."
     >/dev/null 2>&1
   then
     for snapshot in `find "$DIR" | egrep "${file_prefix}_|
       ${file_prefix}\."`
     do
       zfsname=`GetZfsnameFromSnapshot $snapshot`
       if zfs receive $zfsname < "$snapshot"; then
         echo "$zfsname is restored from $snapshot."
       fi
    done
   else
    echo "Error: Backup file $file_prefix.* does not exist in $DIR"
    exit 2
   fi
}

If -r is used with -z zfs and the file system (for example, tank/home) and its backup exist, the script renames the file system (for example, tank/home) to something else. The file system cannot be destroyed, because it might have descendants.

After the file system is restored, its descendants are renamed back under it, for example, from tank/home_$pid. The variable zfs_c makes sure that only those immediate descendants of tank/home_$pid, for example, tank/home/bo, are renamed. This is because sub-immediate descendants, for example, tank/home/bo/projects, are automatically renamed. If a descendant file system has exactly one more field than the parent file system has, it is the immediate descendant file system.

pid=$$
zfs rename $zfs ${zfs}_$pid
RestoreSingleCurrentZfs $zfs

zfs_c=`echo $zfs | nawk -F'/' '{print NF}'`
zfs_c=`expr $zfs_c + 1`
for zpid in `zfs list -t filesystem -o name -r ${zfs}_$pid |
  grep  ${zfs}_${pid}/`;   do
 if [ `echo $zpid | nawk -F'/' '{print NF}'` -eq $zfs_c ]; then
    zfs rename $zpid `echo $zpid | sed "s,^${zfs}_$pid,$zfs,"`
 fi
done
zfs destroy -r ${zfs}_$pid

Examples

Example 1: Restore each file system in every storage pool in the system.

  # zfsrestored.sh

Example 2: Recursively restore each file system in the storage pool tank.

  # zfsrestored.sh -r -z tank

Example 3: Recursively restore tank/home.

  # zfsrestored.sh -r -z tank/home

Example 4: Restore tank/home.

  # zfsrestored.sh -z tank/home

Example 5: Restore the file systems without making a temporary backup.

  # zfsrestored.sh -n
The information and links on this page have been provided by a BigAdmin user. The submitter is solely responsible for such information and links. Sun is not responsible for the availability of external sites or resources, and does not endorse and is not responsible or liable for any content, advertising, products, or other materials on or available from such sites or resources. Sun will not be responsible or liable, directly or indirectly, for any actual or alleged damage or loss caused by or in connection with use of or reliance on the information posted here, or goods or services available on or through any external site or resource.
 
 

Comments (latest comments first)

Discuss and comment on this resource in the BigAdmin Wiki

Unless otherwise licensed, code in all technical manuals herein (including articles, FAQs, samples) is provided under this License.


BigAdmin