Whamcloud - gitweb
LU-4293 utils: handle lfs migrate failure in lfs_migrate
[fs/lustre-release.git] / lustre / scripts / lfs_migrate
old mode 100644 (file)
new mode 100755 (executable)
index 63bc8b9..e9c8aae
@@ -17,10 +17,14 @@ set -e
 RSYNC=${RSYNC:-rsync}
 ECHO=echo
 LFS=${LFS:-lfs}
+LFS_SIZE_OPT="-s"
 
 usage() {
     cat -- <<USAGE 1>&2
-usage: lfs_migrate [-h] [-l] [-n] [-R] [-s] [-y] [file|dir ...]
+usage: lfs_migrate [-c <stripe_count>] [-h] [-l] [-n] [-q] [-R] [-s] [-y] [-0]
+                   [file|dir ...]
+    -c <stripe_count>
+       restripe file using the specified stripe count
     -h show this usage message
     -l migrate files with hard links (skip by default)
     -n only print the names of files to be migrated
@@ -28,32 +32,45 @@ usage: lfs_migrate [-h] [-l] [-n] [-R] [-s] [-y] [file|dir ...]
     -R restripe file using default directory striping
     -s skip file data comparison after migrate
     -y answer 'y' to usage question
+    -0 input file names on stdin are separated by a null character
+
+The -c <stripe_count> option may not be specified at the same time as
+the -R option.
 
 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/file
+e.g.: lfs_migrate /mnt/lustre/dir
       lfs find /test -O test-OST0004 -size +4G | lfs_migrate -y
 USAGE
     exit 1
 }
 
 OPT_CHECK=y
+OPT_STRIPE_COUNT=""
 
-while getopts "chlnqRsy" opt $*; do
+while getopts "c:hlnqRsy0" opt $*; do
     case $opt in
-       c) echo "'-c' option deprecated, checking enabled by default" 1>&2;;
+       c) OPT_STRIPE_COUNT=$OPTARG;;
        l) OPT_NLINK=y;;
        n) OPT_DRYRUN=n; OPT_YES=y;;
        q) ECHO=:;;
        R) OPT_RESTRIPE=y;;
        s) OPT_CHECK="";;
        y) OPT_YES=y;;
+       0) OPT_NULL=y;;
        h|\?) usage;;
     esac
 done
 shift $((OPTIND - 1))
 
+if [ "$OPT_STRIPE_COUNT" -a "$OPT_RESTRIPE" ]; then
+       echo ""
+       echo "$(basename $0) error: The -c <stripe_count> option may not" 1>&2
+       echo "be specified at the same time as the -R option." 1>&2
+       exit 1
+fi
+
 if [ -z "$OPT_YES" ]; then
        echo ""
        echo "lfs_migrate is currently NOT SAFE for moving in-use files." 1>&2
@@ -74,12 +91,23 @@ $RSYNC --help 2>&1 | grep -q acls && RSYNC_OPTS="$RSYNC_OPTS -A"
 # If rsync copies lustre xattrs in the future, then we can skip lfs (bug 22189)
 strings $(which $RSYNC) 2>&1 | grep -q lustre && LFS=:
 
+# rsync creates its temporary files with lenient permissions, even if
+# permissions on the original files are more strict. Tighten umask here
+# to avoid the brief window where unprivileged users might be able to
+# access the temporary file.
+umask 0077
+
+# This is needed for 1.8 Interoperability and can be removed in the future
+$LFS getstripe --help 2>&1 | grep -q stripe-size && LFS_SIZE_OPT="-S"
+
 lfs_migrate() {
-       while read OLDNAME; do
+       local RSYNC_MODE=false
+
+       while IFS='' read -d '' OLDNAME; do
                $ECHO -n "$OLDNAME: "
 
                # avoid duplicate stat if possible
-               TYPE_LINK=($(stat -c "%h %F" "$OLDNAME" || true))
+               TYPE_LINK=($(LANG=C stat -c "%h %F" "$OLDNAME" || true))
 
                # skip non-regular files, since they don't have any objects
                # and there is no point in trying to migrate them.
@@ -104,7 +132,6 @@ lfs_migrate() {
                        continue
                fi
 
-
                if [ "$OPT_RESTRIPE" ]; then
                        UNLINK=""
                else
@@ -112,17 +139,36 @@ lfs_migrate() {
                # (i.e. before the file data, so that it preserves striping)
                # then we don't need to do this getstripe/mktemp stuff.
                        UNLINK="-u"
-                       COUNT=$($LFS getstripe -c "$OLDNAME" 2> /dev/null)
-                       SIZE=$($LFS getstripe -S "$OLDNAME" 2> /dev/null)
+
+                       [ "$OPT_STRIPE_COUNT" ] && COUNT=$OPT_STRIPE_COUNT ||
+                               COUNT=$($LFS getstripe -c "$OLDNAME" \
+                                       2> /dev/null)
+                       SIZE=$($LFS getstripe $LFS_SIZE_OPT "$OLDNAME" \
+                              2> /dev/null)
+
                        [ -z "$COUNT" -o -z "$SIZE" ] && UNLINK=""
+                       SIZE=${LFS_SIZE_OPT}${SIZE}
                fi
+
+               # first try to migrate inside lustre
+               # if failed go back to old rsync mode
+               if [[ $RSYNC_MODE == false ]]; then
+                       if $LFS migrate -c${COUNT} ${SIZE} "$OLDNAME"; then
+                               $ECHO "done"
+                               continue
+                       else
+                               echo "falling back to rsync-based migration"
+                               RSYNC_MODE=true
+                       fi
+               fi
+
                NEWNAME=$(mktemp $UNLINK "$OLDNAME.tmp.XXXXXX")
                if [ $? -ne 0 -o -z "$NEWNAME" ]; then
                        echo -e "\r$OLDNAME: can't make temp file, skipped" 1>&2
                        continue
                fi
 
-               [ "$UNLINK" ] && $LFS setstripe -c${COUNT} -S${SIZE} "$NEWNAME"
+               [ "$UNLINK" ] && $LFS setstripe -c${COUNT} ${SIZE} "$NEWNAME"
 
                # we use --inplace, since we created our own temp file already
                if ! $RSYNC -a --inplace $RSYNC_OPTS "$OLDNAME" "$NEWNAME";then
@@ -145,13 +191,17 @@ lfs_migrate() {
 }
 
 if [ "$#" -eq 0 ]; then
-       lfs_migrate
+       if [ "$OPT_NULL" ]; then
+               lfs_migrate
+       else
+               tr '\n' '\0' | lfs_migrate
+       fi
 else
        while [ "$1" ]; do
                if [ -d "$1" ]; then
-                       lfs find "$1" -type f | lfs_migrate
+                       lfs find "$1" -type f -print0 | lfs_migrate
                else
-                       echo $1 | lfs_migrate
+                       echo -en "$1\0" | lfs_migrate
                fi
                shift
        done