Whamcloud - gitweb
LU-8235 scripts: pass unrecognized options to lfs migrate 21/20621/6
authorSteve Guminski <stephenx.guminski@intel.com>
Thu, 19 Oct 2017 14:52:07 +0000 (10:52 -0400)
committerOleg Drokin <oleg.drokin@intel.com>
Tue, 9 Jan 2018 05:35:21 +0000 (05:35 +0000)
Pass through any unrecognized options to the "lfs migrate" command,
allowing the script to support migrate options without any special
handling.

Add new options "--rsync" and "--no-rsync" to specify how rsync
is used as a fallback alternative for the "lfs migrate" command.
The "--rsync" option forces the use of rsync instead of lfs migrate,
while the "--no-rsync" option prevents falling back to rsync in
the case where lfs migrate fails.

Add new "--dry-run" option.  The current "-n" option for a dry-run
duplicates the "-n" option to designate non-block for "lfs migrate".
The script's usage of "-n" is therefore deprecated, so that a future
patch can instead pass it through.

Add new "-v" option to increase verbosity, to help test/debug/monitor
what is being done by the script.  This option is also passed
through to "lfs migrate".

Test-Parameters: trivial
Signed-off-by: Nathan Dauchy <Nathan.Dauchy@noaa.gov>
Signed-off-by: Steve Guminski <stephenx.guminski@intel.com>
Change-Id: Ia3f56bf528d2ac8155f08d93d01abd8bb9168cc4
Reviewed-on: https://review.whamcloud.com/20621
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: John L. Hammond <john.hammond@intel.com>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
lustre/doc/lfs_migrate.1
lustre/scripts/lfs_migrate
lustre/tests/sanity.sh

index 8195ea4..892c265 100644 (file)
@@ -1,19 +1,19 @@
-.TH lfs_migrate 1 "Jun 16, 2017" Lustre "utilities"
+.TH lfs_migrate 1 "Dec 19, 2017" Lustre "utilities"
 .SH NAME
 .B lfs_migrate
 \- simple tool to migrate files between Lustre OSTs
 .SH SYNOPSIS
 .B lfs_migrate
 .SH NAME
 .B lfs_migrate
 \- simple tool to migrate files between Lustre OSTs
 .SH SYNOPSIS
 .B lfs_migrate
-.RB [ -c <stripe_count> ]
+.RB [ --dry-run ]
 .RB [ -h ]
 .RB [ -h ]
-.RB [ -n ]
+.RB [ --no-rsync | --rsync ]
 .RB [ -q ]
 .RB [ -R ]
 .RB [ -s ]
 .RB [ -q ]
 .RB [ -R ]
 .RB [ -s ]
-.RB [ -S <stripe_size> ]
+.RB [ -v ]
 .RB [ -y ]
 .RB [ -0 ]
 .RB [ -y ]
 .RB [ -0 ]
-.RI [ file | "directory ..." ]
+.RI [ FILE | DIR ]...
 .br
 .SH DESCRIPTION
 .B lfs_migrate
 .br
 .SH DESCRIPTION
 .B lfs_migrate
@@ -47,6 +47,17 @@ suitable for use with
 .BR lfs (1) " find"
 to locate files on specific OSTs and/or matching other file attributes.
 .PP
 .BR lfs (1) " find"
 to locate files on specific OSTs and/or matching other file attributes.
 .PP
+Any options and arguments not explicitly recognized by the script are passed
+through to the
+.B lfs migrate
+command, see
+.BR lfs-migrate (1).
+To maintain backward compatibility, the \fI-n \fRoption is used by the script
+for a dry-run, and is not passed to
+.B lfs migrate
+as the non-block option.  To specify non-block, use the long option
+.IR --non-block .
+.PP
 The current file allocation policies on MDS dictate where the new files
 are placed, taking into account whether specific OSTs have been disabled
 on the MDS via
 The current file allocation policies on MDS dictate where the new files
 are placed, taking into account whether specific OSTs have been disabled
 on the MDS via
@@ -58,30 +69,38 @@ directory (potentially changing the stripe count, stripe size, OST pool,
 or OST index of a new file).
 .SH OPTIONS
 .TP
 or OST index of a new file).
 .SH OPTIONS
 .TP
-.B \\-c <stripe_count>
-Restripe file using the specified stripe count. This option may not be
-specified at the same time as the -R option.
+.B \\--dry-run
+Only print the names of files to be migrated.
 .TP
 .B \\-h
 Display help information.
 .TP
 .TP
 .B \\-h
 Display help information.
 .TP
-.B \\-n
-Only print the names of files to be migrated.
+.B \\--no-rsync
+Do not fall back to using rsync if
+.BR lfs (1) " migrate" " fails."
+Cannot be used at the same time as \fI--rsync\fR.
 .TP
 .B \\-q
 Run quietly (don't print filenames or status).
 .TP
 .TP
 .B \\-q
 Run quietly (don't print filenames or status).
 .TP
+.B \\--rsync
+Force rsync to be used instead of
+.BR lfs (1) " migrate" .
+May not be used at the same time as \fI--no-rsync\fR.
+.TP
 .B \\-R
 Restripe file using default directory striping instead of keeping striping.
 .B \\-R
 Restripe file using default directory striping instead of keeping striping.
-This option may not be specified at the same time as the -c or -S options.
+This option may not be specified at the same time as the -c or -S options
+(these options are passed through to
+.BR "lfs migrate" ,
+and are therefore not listed here).
 .TP
 .B \\-s
 Skip file data comparison after migrate.  Default is to compare migrated file
 against original to verify correctness.
 .TP
 .TP
 .B \\-s
 Skip file data comparison after migrate.  Default is to compare migrated file
 against original to verify correctness.
 .TP
-.B \\-S <stripe_size>
-Restripe file using the specified stripe size. This option may not be
-specified at the same time as the -R option.
+.B \\-v
+Show verbose debug messages.
 .TP
 .B \\-y
 Answer 'y' to usage warning without prompting (for scripts, use with caution).
 .TP
 .B \\-y
 Answer 'y' to usage warning without prompting (for scripts, use with caution).
index 0c080b7..6abc0e3 100755 (executable)
@@ -16,10 +16,9 @@ RSYNC=${RSYNC:-rsync}
 LFS_MIGRATE_RSYNC_MODE=${LFS_MIGRATE_RSYNC_MODE:-false}
 ECHO=echo
 LFS=${LFS:-lfs}
 LFS_MIGRATE_RSYNC_MODE=${LFS_MIGRATE_RSYNC_MODE:-false}
 ECHO=echo
 LFS=${LFS:-lfs}
-LFS_MIGRATE_RSYNC=${LFS_MIGRATE_RSYNC:-false}
 RSYNC_WITH_HLINKS=false
 LFS_MIGRATE_TMP=${TMPDIR:-/tmp}
 RSYNC_WITH_HLINKS=false
 LFS_MIGRATE_TMP=${TMPDIR:-/tmp}
-MIGRATED_SET="$(mktemp ${LFS_MIGRATE_TMP}/lfs_migrate-$$.links.XXXXXX)"
+MIGRATED_SET="$(mktemp ${LFS_MIGRATE_TMP}/lfs_migrate.links.XXXXXX)"
 NEWNAME=""
 REMOVE_FID='s/^\[[0-9a-fx:]*\] //'
 
 NEWNAME=""
 REMOVE_FID='s/^\[[0-9a-fx:]*\] //'
 
@@ -45,27 +44,33 @@ old_fid_in_set() {
 
 usage() {
     cat -- <<USAGE 1>&2
 
 usage() {
     cat -- <<USAGE 1>&2
-usage: lfs_migrate [-c <stripe_count>] [-h] [-n] [-q] [-R] [-s]
-                   [-S <stripe_size>] [-y] [-0] [file|dir ...]
-    -c <stripe_count>
-       restripe file using the specified stripe count
-    -h show this usage message
-    -n only print the names of files to be migrated
-    -q run quietly (don't print filenames or status)
-    -R restripe file using default directory striping
-    -s skip file data comparison after migrate
-    -S <stripe_size>
-       restripe file using the specified stripe size
-    -y answer 'y' to usage question
-    -0 input file names on stdin are separated by a null character
+usage: lfs_migrate [--dry-run] [-h] [--no-rsync|--rsync] [-q] [-R] [-s]
+                  [-v] [-y] [-0] [FILE|DIR...]
+       --dry-run only print the names of files to be migrated
+       -h show this usage message
+       --no-rsync do not fall back to rsync mode even if lfs migrate fails
+       -q run quietly (don't print filenames or status)
+       --rsync force rsync mode instead of using lfs migrate
+       -R restripe file using default directory striping
+       -s skip file data comparison after migrate
+       -v show verbose debug messages
+       -y answer 'y' to usage question
+       -0 input file names on stdin are separated by a null character
 
 The -c <stripe_count> and -S <stripe_size> options may not be specified at
 the same time as the -R option.
 
 
 The -c <stripe_count> and -S <stripe_size> options may not be specified at
 the same time as the -R option.
 
+The --rsync and --no-rsync options may not be specified at the same time.
+
 If a directory is an argument, all files in the directory are migrated.
 If no file/directory is given, the file list is read from standard input.
 
 If a directory is an argument, all files in the directory are migrated.
 If no file/directory is given, the file list is read from standard input.
 
-e.g.: lfs_migrate /mnt/lustre/dir
+Any arguments that are not explicitly recognized by the script are passed
+through to the 'lfs migrate' utility.
+
+Examples:
+      lfs_migrate /mnt/lustre/dir
+      lfs_migrate -p newpool /mnt/lustre/dir
       lfs find /test -O test-OST0004 -size +4G | lfs_migrate -y
 USAGE
     exit 1
       lfs find /test -O test-OST0004 -size +4G | lfs_migrate -y
 USAGE
     exit 1
@@ -78,35 +83,124 @@ cleanup() {
 
 trap cleanup EXIT
 
 
 trap cleanup EXIT
 
-OPT_CHECK=y
-OPT_STRIPE_COUNT=""
-OPT_STRIPE_SIZE=""
+OPT_CHECK=true
+OPT_DEBUG=false
+OPT_NO_RSYNC=false
+OPT_DRYRUN=false
+OPT_YES=false
+OPT_RESTRIPE=false
+OPT_NULL=false
+OPT_PASSTHROUGH=()
+STRIPE_COUNT=""
+STRIPE_SIZE=""
+POOL=""
+
+# Examine any long options and arguments.  getopts does not support long
+# options, so they must be stripped out and classified as either options
+# for the script, or passed through to "lfs migrate".
+LONG_OPT=false
+SHORT_OPT=false
+OPTS=()
+
+for f in $(seq 1 $#); do
+       arg=${!f}
+       if [ "${arg:0:2}" = "--" ]; then
+               SHORT_OPT=false
+               if [ "$arg" = "--block" ]; then
+                       BLOCK="$arg"
+                       OPT_YES=true
+               elif [ "$arg" = "--non-block" ]; then
+                       BLOCK="$arg"
+               elif [ "$arg" = "--dry-run" ]; then
+                       OPT_DRYRUN=true
+                       OPT_YES=true
+               elif [ "$arg" = "--rsync" ]; then
+                       LFS_MIGRATE_RSYNC_MODE=true
+               elif [ "$arg" = "--no-rsync" ]; then
+                       OPT_NO_RSYNC=true
+                       OPT_YES=true
+               else
+                       LONG_OPT=true
+                       OPT_PASSTHROUGH+=("$arg")
+               fi
+       elif [ "${arg:0:1}" = "-" ]; then
+               LONG_OPT=false
+               if [ "$arg" == "-b" ]; then
+                       BLOCK="$arg"
+               else
+                       SHORT_OPT=true
+                       OPTS+=("$arg")
+               fi
+       elif $LONG_OPT; then
+               LONG_OPT=false
+               # This will prevent long options from having file name
+               # arguments, but allows long options with no arguments to work.
+               if [ -f "$arg" -o -d "$arg" ]; then
+                       OPTS+=("$arg")
+               else
+                       [ "${OPT_PASSTHROUGH[-1]}" = "--stripe-count" ] &&
+                               STRIPE_COUNT="$arg"
+                       [ "${OPT_PASSTHROUGH[-1]}" = "--stripe-size" ] &&
+                               STRIPE_SIZE="$arg"
+                       [ "${OPT_PASSTHROUGH[-1]}" = "--pool" ] &&
+                               POOL="$arg"
+                       OPT_PASSTHROUGH+=("$arg")
+               fi
+       elif $SHORT_OPT; then
+               [ "${OPTS[-1]}" = "-c" ] &&
+                       STRIPE_COUNT="$arg"
+               [ "${OPTS[-1]}" = "-S" ] &&
+                       STRIPE_SIZE="$arg"
+               [ "${OPTS[-1]}" = "-p" ] &&
+                       POOL="$arg"
+               SHORT_OPT=false
+               OPTS+=("$arg")
+       else
+               OPTS+=("$arg")
+       fi
+done
 
 
-while getopts "c:hlnqRsS:y0" opt $*; do
+# Reset the argument list to include only the short options and file names
+set -- "${OPTS[@]}"
+
+while getopts ":hlnqRsvy0" opt $*; do
     case $opt in
     case $opt in
-       c) OPT_STRIPE_COUNT=$OPTARG;;
+       h) usage;;
        l) ;; # maintained for backward compatibility
        l) ;; # maintained for backward compatibility
-       n) OPT_DRYRUN=n; OPT_YES=y;;
+       n) OPT_DRYRUN=true
+          OPT_YES=true
+          echo "$(basename $0): -n deprecated, use --dry-run instead" 1>&2
+          echo "$(basename $0): to specify non-block, use --non-block instead" 1>&2;;
        q) ECHO=:;;
        q) ECHO=:;;
-       R) OPT_RESTRIPE=y;;
-       s) OPT_CHECK="";;
-       S) OPT_STRIPE_SIZE=$OPTARG;;
-       y) OPT_YES=y;;
-       0) OPT_NULL=y;;
-       h|\?) usage;;
+       R) OPT_RESTRIPE=true;;
+       s) OPT_CHECK=false;;
+       v) OPT_DEBUG=true; ECHO=echo; OPT_PASSTHROUGH+=("-v");;
+       y) OPT_YES=true;;
+       0) OPT_NULL=true;;
+       *) # Pass through any unrecognized options to 'lfs migrate'
+          OPT_PASSTHROUGH+=("-$OPTARG")
+          if [[ ${!OPTIND:0:1} != "-" && ! -f "${!OPTIND}" &&
+                ! -d "${!OPTIND}" ]]; then
+               OPT_PASSTHROUGH+=("${!OPTIND}")
+               ((OPTIND++))
+          fi;;
     esac
 done
 shift $((OPTIND - 1))
 
     esac
 done
 shift $((OPTIND - 1))
 
-if [ -n "$OPT_STRIPE_COUNT""$OPT_STRIPE_SIZE" -a "$OPT_RESTRIPE" ]; then
-       echo ""
-       echo "$(basename $0) error: The -c <stripe_count> option and" 1>&2
-       echo "-S <stripe_size> option may not" 1>&2
-       echo "be specified at the same time as the -R option." 1>&2
+if $OPT_RESTRIPE && [[ "$STRIPE_COUNT" || "$STRIPE_SIZE" ]]; then
+       echo "$(basename $0): Options -c <stripe_count> and -S <stripe_size> "\
+       "may not be specified at the same time as the -R option." 1>&2
        exit 1
 fi
 
        exit 1
 fi
 
-if [ -z "$OPT_YES" ]; then
+if $LFS_MIGRATE_RSYNC_MODE && $OPT_NO_RSYNC; then
+       echo "$(basename $0): Options --rsync and --no-rsync may not be "\
+       "specified at the same time." 1>&2
+       exit 1
+fi
+
+if ! $OPT_YES; then
        echo ""
        echo "lfs_migrate is currently NOT SAFE for moving in-use files." 1>&2
        echo "Use it only when you are sure migrated files are unused." 1>&2
        echo ""
        echo "lfs_migrate is currently NOT SAFE for moving in-use files." 1>&2
        echo "Use it only when you are sure migrated files are unused." 1>&2
@@ -135,33 +229,40 @@ umask 0077
 lfs_migrate() {
        while IFS='' read -d '' OLDNAME; do
                local hlinks=()
 lfs_migrate() {
        while IFS='' read -d '' OLDNAME; do
                local hlinks=()
+               local stripe_size="$STRIPE_SIZE"
+               local stripe_count="$STRIPE_COUNT"
+               local parent_count=""
+               local parent_size=""
+
+               $ECHO -n "$OLDNAME: "
 
                # avoid duplicate stat if possible
 
                # avoid duplicate stat if possible
-               local nlink_type=($(LANG=C stat -c "%h %F" "$OLDNAME" || true))
+               local nlink_type=($(LANG=C stat -c "%h %F" "$OLDNAME"   \
+                                2> /dev/null))
 
                # skip non-regular files, since they don't have any objects
                # and there is no point in trying to migrate them.
                if [ "${nlink_type[1]}" != "regular" ]; then
 
                # skip non-regular files, since they don't have any objects
                # and there is no point in trying to migrate them.
                if [ "${nlink_type[1]}" != "regular" ]; then
-                       echo -e "$OLDNAME: not a regular file, skipped"
+                       echo -e "\r\e[K$OLDNAME: not a regular file, skipped"
                        continue
                fi
 
                # working out write perms is hard, let the shell do it
                if [ ! -w "$OLDNAME" ]; then
                        continue
                fi
 
                # working out write perms is hard, let the shell do it
                if [ ! -w "$OLDNAME" ]; then
-                       echo -e "$OLDNAME: no write permission, skipped"
+                       echo -e "\r\e[K$OLDNAME: no write permission, skipped"
                        continue
                fi
 
                        continue
                fi
 
-               if [ "$OPT_DRYRUN" ]; then
-                       echo -e "$OLDNAME: dry run, skipped"
+               if $OPT_DRYRUN && ! $OPT_DEBUG; then
+                       $ECHO "dry run, skipped"
                        continue
                fi
 
                # xattrs use absolute file paths, so ensure provided path is
                # also absolute so that the names can be compared
                local oldname_absolute=$(readlink -f "$OLDNAME")
                        continue
                fi
 
                # xattrs use absolute file paths, so ensure provided path is
                # also absolute so that the names can be compared
                local oldname_absolute=$(readlink -f "$OLDNAME")
-               if [ $? -ne 0 ]; then
-                       echo -e "$OLDNAME: cannot resolve full path"
+               if [ -z "$oldname_absolute" ]; then
+                       echo -e "\r\e[K$OLDNAME: cannot resolve full path, skipped"
                        continue
                fi
                OLDNAME=$oldname_absolute
                        continue
                fi
                OLDNAME=$oldname_absolute
@@ -170,14 +271,14 @@ lfs_migrate() {
                # should be replaced with a single call to
                # "lfs path2links" once that command is available.  The logic
                # for detecting unlisted hard links could then be removed.
                # should be replaced with a single call to
                # "lfs path2links" once that command is available.  The logic
                # for detecting unlisted hard links could then be removed.
-               local fid=$(lfs path2fid "$OLDNAME" 2> /dev/null)
+               local fid=$($LFS path2fid "$OLDNAME" 2> /dev/null)
                if [ $? -ne 0 ]; then
                if [ $? -ne 0 ]; then
-                       echo -n "$OLDNAME: cannot determine FID; skipping; "
+                       echo -n "\r\e[K$OLDNAME: cannot determine FID; skipping; "
                        echo "is this a Lustre file system?"
                        continue
                fi
 
                        echo "is this a Lustre file system?"
                        continue
                fi
 
-               if [[ ${nlink_type[0]} -gt 1 || $RSYNC_WITH_HLINKS == true ]]; then
+               if [[ ${nlink_type[0]} -gt 1 ]] || $RSYNC_WITH_HLINKS; then
                        # don't migrate a hard link if it was already migrated
                        if path_in_set "$OLDNAME"; then
                                $ECHO -e "$OLDNAME: already migrated via another hard link"
                        # don't migrate a hard link if it was already migrated
                        if path_in_set "$OLDNAME"; then
                                $ECHO -e "$OLDNAME: already migrated via another hard link"
@@ -192,7 +293,7 @@ lfs_migrate() {
                        local migrated=$(old_fid_in_set "$fid")
                        if [ -n "$migrated" ]; then
                                $ECHO -e "$OLDNAME: already migrated via another hard link"
                        local migrated=$(old_fid_in_set "$fid")
                        if [ -n "$migrated" ]; then
                                $ECHO -e "$OLDNAME: already migrated via another hard link"
-                               if [[ $LFS_MIGRATE_RSYNC == true ]]; then
+                               if $LFS_MIGRATE_RSYNC_MODE; then
                                        # Only the rsync case has to relink.
                                        # The lfs migrate case preserves the
                                        # inode so the links are already
                                        # Only the rsync case has to relink.
                                        # The lfs migrate case preserves the
                                        # inode so the links are already
@@ -205,7 +306,7 @@ lfs_migrate() {
                        fi
                fi
 
                        fi
                fi
 
-               if [ "$OPT_RESTRIPE" ]; then
+               if $OPT_RESTRIPE; then
                        UNLINK=""
                else
                # if rsync copies Lustre xattrs properly in the future
                        UNLINK=""
                else
                # if rsync copies Lustre xattrs properly in the future
@@ -213,22 +314,45 @@ lfs_migrate() {
                # then we don't need to do this getstripe/mktemp stuff.
                        UNLINK="-u"
 
                # then we don't need to do this getstripe/mktemp stuff.
                        UNLINK="-u"
 
-                       [ "$OPT_STRIPE_COUNT" ] &&
-                               stripe_count=$OPT_STRIPE_COUNT ||
-                               stripe_count=$($LFS getstripe -c "$OLDNAME" \
-                                              2> /dev/null)
-                       [ "$OPT_STRIPE_SIZE" ] &&
-                               stripe_size=$OPT_STRIPE_SIZE ||
-                               stripe_size=$($LFS getstripe -S \
-                                             "$OLDNAME" 2> /dev/null)
-
-                       if [ -z "$stripe_count" -o -z "$stripe_size" ]; then
-                               UNLINK=""
-                               echo -e "$OLDNAME: cannot determine stripe info; skipping"
-                               continue
+                       [ -z "$stripe_count" ] &&
+                               stripe_count=$($LFS getstripe -c "$OLDNAME" 2> /dev/null)
+
+                       [ -z "$stripe_size" ] &&
+                               stripe_size=$($LFS getstripe -S "$OLDNAME" 2> /dev/null)
+
+                       [ -z "$stripe_count" -o -z "$stripe_size" ] && UNLINK=""
+               fi
+
+               if $OPT_DEBUG; then
+                       if $OPT_RESTRIPE; then
+                               parent_count=$($LFS getstripe -c \
+                                              $(dirname "$OLDNAME") 2> \
+                                              /dev/null)
+                               parent_size=$($LFS getstripe -S \
+                                             $(dirname "$OLDNAME") 2> \
+                                             /dev/null)
                        fi
                        fi
-                       stripe_size="-S$stripe_size"
-                       stripe_count="-c$stripe_count"
+
+                       $ECHO -n "stripe" \
+                               "count=${stripe_count:-$parent_count}," \
+                               "size=${stripe_size:-$parent_size}," \
+                               "pool=${POOL:-not in a pool}: "
+               fi
+
+               if $OPT_DRYRUN; then
+                       $ECHO "dry run, skipped"
+                       continue
+               fi
+
+               if [[ "$stripe_count" && -z "$STRIPE_COUNT" ]]; then
+                       stripe_count="-c $stripe_count"
+               else
+                       stripe_count=""
+               fi
+               if [[ "$stripe_size" && -z "$STRIPE_SIZE" ]]; then
+                       stripe_size="-S $stripe_size"
+               else
+                       stripe_size=""
                fi
 
                # detect other hard links and store them on a global
                fi
 
                # detect other hard links and store them on a global
@@ -236,56 +360,62 @@ lfs_migrate() {
                local mntpoint=$(df -P "$OLDNAME" |
                                awk 'NR==2 { print $NF; exit }')
                if [ -z "$mntpoint" ]; then
                local mntpoint=$(df -P "$OLDNAME" |
                                awk 'NR==2 { print $NF; exit }')
                if [ -z "$mntpoint" ]; then
-                       echo -e "$OLDNAME: cannot determine mount point; skipping"
+                       echo -e "\r\e[K$OLDNAME: cannot determine mount point; skipped"
                        continue
                fi
                        continue
                fi
-               local hlinks=$(lfs fid2path "$mntpoint" "$fid" 2> /dev/null)
+               hlinks=$($LFS fid2path "$mntpoint" "$fid" 2> /dev/null)
                if [ $? -ne 0 ]; then
                if [ $? -ne 0 ]; then
-                       echo -n "$OLDNAME: cannot determine hard link paths"
+                       echo -e "\r\e[K$OLDNAME: cannot determine hard link paths, skipped"
                        continue
                fi
                hlinks+=("$OLDNAME")
 
                # first try to migrate via Lustre tools, then fall back to rsync
                        continue
                fi
                hlinks+=("$OLDNAME")
 
                # first try to migrate via Lustre tools, then fall back to rsync
-               if [[ $LFS_MIGRATE_RSYNC == false ]]; then
-                       if $LFS migrate "$stripe_count" "$stripe_size" "$OLDNAME"; then
-                               $ECHO -e "$OLDNAME: done migrate"
+               if ! $LFS_MIGRATE_RSYNC_MODE; then
+                       if $LFS migrate "${OPT_PASSTHROUGH[@]}" ${BLOCK} \
+                          ${stripe_count} ${stripe_size} "$OLDNAME" &> \
+                          /dev/null; then
+                               $ECHO "done migrate"
                                for link in ${hlinks[*]}; do
                                        add_to_set "$fid" "$link"
                                done
                                continue
                                for link in ${hlinks[*]}; do
                                        add_to_set "$fid" "$link"
                                done
                                continue
+                       elif $OPT_NO_RSYNC; then
+                               echo -e "\r\e[K$OLDNAME: refusing to fall back to rsync, skipped" 1>&2
+                               continue
                        else
                        else
-                               echo -e "$OLDNAME: falling back to rsync-based migration"
-                               LFS_MIGRATE_RSYNC=true
+                               $ECHO -n "falling back to rsync: "
+                               LFS_MIGRATE_RSYNC_MODE=true
                        fi
                fi
 
                NEWNAME=$(mktemp $UNLINK "$OLDNAME-lfs_migrate.tmp.XXXXXX")
                if [ $? -ne 0 -o -z "$NEWNAME" ]; then
                        fi
                fi
 
                NEWNAME=$(mktemp $UNLINK "$OLDNAME-lfs_migrate.tmp.XXXXXX")
                if [ $? -ne 0 -o -z "$NEWNAME" ]; then
-                       echo -e "$OLDNAME: can't make temp file, skipped" 1>&2
+                       echo -e "\r\e[K$OLDNAME: can't make temp file, skipped" 1>&2
                        continue
                fi
 
                        continue
                fi
 
-               [ "$UNLINK" ] && $LFS setstripe ${stripe_count} \
-                       ${stripe_size} "$NEWNAME"
+               [ "$UNLINK" ] && $LFS setstripe ${OPT_PASSTHROUGH}      \
+                                ${stripe_count} ${stripe_size}         \
+                                "$NEWNAME" &> /dev/null
 
                # we use --inplace, since we created our own temp file already
                if ! $RSYNC -a --inplace $RSYNC_OPTS "$OLDNAME" "$NEWNAME";then
 
                # we use --inplace, since we created our own temp file already
                if ! $RSYNC -a --inplace $RSYNC_OPTS "$OLDNAME" "$NEWNAME";then
-                       echo -e "$OLDNAME: copy error, exiting" 1>&2
+                       echo -e "\r\e[K$OLDNAME: copy error, exiting" 1>&2
                        exit 4
                fi
 
                        exit 4
                fi
 
-               if [ "$OPT_CHECK" ] && ! cmp -s "$OLDNAME" "$NEWNAME"; then
-                       echo -e "$NEWNAME: compare failed, exiting" 1>&2
+               if $OPT_CHECK && ! cmp -s "$OLDNAME" "$NEWNAME"; then
+                       echo -e "\r\e[K$NEWNAME: compare failed, exiting" 1>&2
                        exit 8
                fi
 
                if ! mv "$NEWNAME" "$OLDNAME"; then
                        exit 8
                fi
 
                if ! mv "$NEWNAME" "$OLDNAME"; then
-                       echo -e "$OLDNAME: rename error, exiting" 1>&2
+                       echo -e "\r\e[K$OLDNAME: rename error, exiting" 1>&2
                        exit 12
                fi
 
                        exit 12
                fi
 
-               $ECHO -e "$OLDNAME: done migrate via rsync"
+               $ECHO "done migrate via rsync"
                for link in ${hlinks[*]}; do
                        if [ "$link" != "$OLDNAME" ]; then
                                ln -f "$OLDNAME" "$link"
                for link in ${hlinks[*]}; do
                        if [ "$link" != "$OLDNAME" ]; then
                                ln -f "$OLDNAME" "$link"
@@ -303,7 +433,7 @@ lfs_migrate() {
 }
 
 if [ "$#" -eq 0 ]; then
 }
 
 if [ "$#" -eq 0 ]; then
-       if [ "$OPT_NULL" ]; then
+       if $OPT_NULL; then
                lfs_migrate
        else
                tr '\n' '\0' | lfs_migrate
                lfs_migrate
        else
                tr '\n' '\0' | lfs_migrate
@@ -311,11 +441,11 @@ if [ "$#" -eq 0 ]; then
 else
        while [ "$1" ]; do
                if [ -d "$1" ]; then
 else
        while [ "$1" ]; do
                if [ -d "$1" ]; then
-                       $LFS find "$1" -type f -print0 | lfs_migrate
+                       $LFS find "$1" -type f -print0
                else
                else
-                       echo -en "$1\0" | lfs_migrate
+                       echo -en "$1\0"
                fi
                shift
                fi
                shift
-       done
+       done | lfs_migrate
 fi
 
 fi
 
index ddae93b..abe92e9 100755 (executable)
@@ -5162,6 +5162,222 @@ test_56w() {
 }
 run_test 56w "check lfs_migrate -c stripe_count works"
 
 }
 run_test 56w "check lfs_migrate -c stripe_count works"
 
+test_56wb() {
+       local file1=$DIR/$tdir/file1
+       local create_pool=false
+       local initial_pool=$($LFS getstripe -p $DIR)
+       local pool_list=()
+       local pool=""
+
+       echo -n "Creating test dir..."
+       test_mkdir $DIR/$tdir &> /dev/null || error "cannot create dir"
+       echo "done."
+
+       echo -n "Creating test file..."
+       touch $file1 || error "cannot create file"
+       echo "done."
+
+       echo -n "Detecting existing pools..."
+       while IFS='' read thispool; do
+               pool_list+=("$thispool")
+       done < <($LFS pool_list $MOUNT | awk -F '.' 'NR>=2 { print $2 }')
+
+       if [ ${#pool_list[@]} -gt 0 ]; then
+               echo "${pool_list[@]}"
+               for thispool in "${pool_list[@]}"; do
+                       if [[ -z "$initial_pool" ||
+                             "$initial_pool" != "$thispool" ]]; then
+                               pool="$thispool"
+                               echo "Using existing pool '$pool'"
+                               break
+                       fi
+               done
+       else
+               echo "none detected."
+       fi
+       if [ -z "$pool" ]; then
+               pool=${POOL:-testpool}
+               [ "$initial_pool" = "$pool" ] && pool="testpool2"
+               echo -n "Creating pool '$pool'..."
+               create_pool=true
+               pool_add $pool &> /dev/null ||
+                       error "pool_add failed"
+               echo "done."
+
+               echo -n "Adding target to pool..."
+               pool_add_targets $pool 0 0 1 &> /dev/null ||
+                       error "pool_add_targets failed"
+               echo "done."
+       fi
+
+       echo -n "Setting pool using -p option..."
+       $LFS_MIGRATE -y -q --no-rsync -p $pool $file1 &> /dev/null ||
+               error "migrate failed rc = $?"
+       echo "done."
+
+       echo -n "Verifying test file is in pool after migrating..."
+       [ "$($LFS getstripe -p $file1)" = $pool ] ||
+               error "file was not migrated to pool $pool"
+       echo "done."
+
+       echo -n "Removing test file from pool '$pool'..."
+       $LFS migrate $file1 &> /dev/null ||
+               error "cannot remove from pool"
+       [ "$($LFS getstripe -p $file1)" ] &&
+               error "pool still set"
+       echo "done."
+
+       echo -n "Setting pool using --pool option..."
+       $LFS_MIGRATE -y -q --no-rsync --pool $pool $file1 &> /dev/null ||
+               error "migrate failed rc = $?"
+       echo "done."
+
+       # Clean up
+       rm -f $file1
+       if $create_pool; then
+               destroy_test_pools 2> /dev/null ||
+                       error "destroy test pools failed"
+       fi
+}
+run_test 56wb "check lfs_migrate pool support"
+
+test_56wc() {
+       local file1="$DIR/$tdir/file 1"
+
+       echo -n "Creating test dir..."
+       test_mkdir $DIR/$tdir &> /dev/null || error "cannot create dir"
+       $LFS setstripe -S 1M -c 1 "$DIR/$tdir" &> /dev/null ||
+               error "cannot set stripe"
+       echo "done"
+
+       echo -n "Setting initial stripe for test file..."
+       $LFS setstripe -S 512K -c 1 "$file1" &> /dev/null ||
+               error "cannot set stripe"
+       [ $($LFS getstripe -S "$file1") -eq 524288 ] ||
+               error "stripe size not set"
+       echo "done."
+
+       # File currently set to -S 512K -c 1
+
+       # Ensure -c and -S options are rejected when -R is set
+       echo -n "Verifying incompatible options are detected..."
+       $LFS_MIGRATE -y -R -c 1 "$file1" &> /dev/null &&
+               error "incompatible -c and -R options not detected"
+       $LFS_MIGRATE -y -R -S 1M "$file1" &> /dev/null &&
+               error "incompatible -S and -R options not detected"
+       echo "done."
+
+       # Ensure unrecognized options are passed through to 'lfs migrate'
+       echo -n "Verifying -S option is passed through to lfs migrate..."
+       $LFS_MIGRATE -y -S 1M "$file1" &> /dev/null ||
+               error "migration failed"
+       [ $($LFS getstripe -S "$file1") -eq 1048576 ] ||
+               error "file was not restriped"
+       echo "done."
+
+       # File currently set to -S 1M -c 1
+
+       # Ensure long options are supported
+       echo -n "Verifying long options supported..."
+       $LFS_MIGRATE -y --non-block "$file1" &> /dev/null ||
+               error "long option without argument not supported"
+       $LFS_MIGRATE -y --stripe-size 512K "$file1" &> /dev/null ||
+               error "long option with argument not supported"
+       [ $($LFS getstripe -S "$file1") -eq 524288 ] ||
+               error "file not restriped with --stripe-size option"
+       echo "done."
+
+       # File currently set to -S 512K -c 1
+
+       if [ "$OSTCOUNT" -gt 1 ]; then
+               echo -n "Verifying explicit stripe count can be set..."
+               $LFS_MIGRATE -y -c 2 "$file1" &> /dev/null ||
+                       error "migrate failed"
+               [ $($LFS getstripe -c "$file1") -eq 2 ] ||
+                       error "file not restriped to explicit count"
+               echo "done."
+       fi
+
+       # File currently set to -S 512K -c 1 or -S 512K -c 2
+
+       # Ensure parent striping is used if -R is set, and no stripe
+       # count or size is specified
+       echo -n "Setting stripe for parent directory..."
+       $LFS setstripe -S 1M -c 1 "$DIR/$tdir" &> /dev/null ||
+               error "cannot set stripe"
+       echo "done."
+
+       echo -n "Verifying restripe option uses parent stripe settings..."
+       $LFS_MIGRATE -y -R "$file1" &> /dev/null ||
+               error "migrate failed"
+       [ $($LFS getstripe -S "$file1") -eq 1048576 ] ||
+               error "file not restriped to parent settings"
+       [ $($LFS getstripe -c "$file1") -eq 1 ] ||
+               error "file not restriped to parent settings"
+       echo "done."
+
+       # File currently set to -S 1M -c 1
+
+       # Ensure striping is preserved if -R is not set, and no stripe
+       # count or size is specified
+       echo -n "Verifying striping size preserved when not specified..."
+       $LFS setstripe -S 2M -c 1 "$DIR/$tdir" &> /dev/null ||
+               error "cannot set stripe on parent directory"
+       $LFS_MIGRATE -y "$file1" &> /dev/null ||
+               error "migrate failed"
+       [ $($LFS getstripe -S "$file1") -eq 1048576 ] ||
+               error "file was restriped"
+       echo "done."
+
+       # Ensure file name properly detected when final option has no argument
+       echo -n "Verifying file name properly detected..."
+       $LFS_MIGRATE -y "$file1" &> /dev/null ||
+               error "file name interpreted as option argument"
+       echo "done."
+
+       # Clean up
+       rm -f "$file1"
+}
+run_test 56wc "check unrecognized options for lfs_migrate are passed through"
+
+test_56wd() {
+       [[ $OSTCOUNT -lt 2 ]] && skip_env "needs >= 2 OSTs" && return
+       local file1=$DIR/$tdir/file1
+
+       echo -n "Creating test dir..."
+       test_mkdir $DIR/$tdir || error "cannot create dir"
+       echo "done."
+
+       echo -n "Creating test file..."
+       touch $file1
+       echo "done."
+
+       # Ensure 'lfs migrate' will fail by using a non-existent option,
+       # and make sure rsync is not called to recover
+       echo -n "Make sure --no-rsync option works..."
+       $LFS_MIGRATE -y --no-rsync --invalid-opt $file1 2>&1 |
+               grep -q 'refusing to fall back to rsync' ||
+               error "rsync was called with --no-rsync set"
+       echo "done."
+
+       # Ensure rsync is called without trying 'lfs migrate' first
+       echo -n "Make sure --rsync option works..."
+       $LFS_MIGRATE -y --rsync --invalid-opt $file1 2>&1 |
+               grep -q 'falling back to rsync' &&
+               error "lfs migrate was called with --rsync set"
+       echo "done."
+
+       echo -n "Make sure --rsync and --no-rsync options are exclusive..."
+       $LFS_MIGRATE -y --rsync --no-rsync $file1 2>&1 |
+               grep -q 'at the same time' ||
+               error "--rsync and --no-rsync accepted concurrently"
+       echo "done."
+
+       # Clean up
+       rm -f $file1
+}
+run_test 56wd "check lfs_migrate --rsync and --no-rsync work"
+
 test_56x() {
        check_swap_layouts_support && return 0
        [[ $OSTCOUNT -lt 2 ]] && skip_env "needs >= 2 OSTs" && return
 test_56x() {
        check_swap_layouts_support && return 0
        [[ $OSTCOUNT -lt 2 ]] && skip_env "needs >= 2 OSTs" && return