From: Andreas Dilger Date: Fri, 4 Jun 2010 17:54:07 +0000 (-0600) Subject: b=22481 Add "lfs_migrate" script from manual into lustre/scripts and RPMs X-Git-Tag: v1_10_0_44~17 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=1c3bb7cd682d2f4d26d9f04f5a5774bffa6df1e3 b=22481 Add "lfs_migrate" script from manual into lustre/scripts and RPMs Add enhanced lfs_migrate script from manual into lustre/scripts directory and in RPM packages. It does a "poor man's" migration of files from their current OST layout to a new OST layout as chosen by the MDS. It is currently not safe to use for files that are being written to. It will result in the current file becoming an open-unlinked file, and the migrated file will be used for any subsequent opens. Any writes to either the old or migrated file will in clients seeing different data, and writes to the old file will be lost when it is closed. There is no direct control of object allocation within the script, it depends on external control to manage space. Use "lfs find" to select appropriate files to migrate from full OSTs. "lctl --deactivate" is needed on the MDS to deactivate OSTs if trying to empty an OST completely, otherwise QOS will tend to migrate files to empty OSTs. i=brian.murrell i=nathan.rutman --- diff --git a/lustre/scripts/Makefile.am b/lustre/scripts/Makefile.am index 1baab1a..a3df324 100644 --- a/lustre/scripts/Makefile.am +++ b/lustre/scripts/Makefile.am @@ -41,7 +41,7 @@ genscripts = lustre_config lc_modprobe lc_net lc_hb lc_cluman lustre_createcsv \ lc_md lc_lvm lustre_start sbin_SCRIPTS = $(genscripts) $(sbinscripts) -bin_SCRIPTS = lustre_req_history +bin_SCRIPTS = lustre_req_history lfs_migrate EXTRA_DIST = license-status maketags.sh version_tag.pl lc_common \ $(addsuffix .in,$(genscripts)) lc_mon $(sbinscripts) \ diff --git a/lustre/scripts/lfs_migrate b/lustre/scripts/lfs_migrate new file mode 100644 index 0000000..776fbe6 --- /dev/null +++ b/lustre/scripts/lfs_migrate @@ -0,0 +1,148 @@ +#!/bin/bash +# set -x +set -e + +# lfs_migrate: a simple tool to copy and check files. +# +# To avoid allocating objects on one or more OSTs, they should be +# deactivated on the MDS via "lctl --device {device_number} deactivate", +# where {device_number} is from the output of "lctl dl" on the MDS. +# +# To guard against corruption, the file is compared after migration +# to verify the copy is correct and the file has not been modified. +# This is not a protection against the file being open by another +# process, but it would catch the worst cases of in-use files, but +# to be 100% safe the administrator needs to ensure this is safe. + +RSYNC=${RSYNC:-rsync} +ECHO=echo +LFS=${LFS:-lfs} + +usage() { + echo "usage: lfs_migrate [-c|-s] [-h] [-l] [-n] [-y] [file|dir ...]" 1>&2 + echo " -c compare file data after migrate (default)" 1>&2 + echo " -s skip file data comparison after migrate" 1>&2 + echo " -h show this usage message" 1>&2 + echo " -l migrate files with hard links (skip by default)" 1>&2 + echo " -n only print the names of files to be migrated" 1>&2 + echo " -y answer 'y' to usage question" 1>&2 + echo " if no file or directory is given, file list is read from stdin" + echo "" + echo "e.g.: lfs_migrate -c /mnt/lustre/file" + echo " lfs find /scratch -O lustre-OST0004 -size +4G | lfs_migrate -y" + exit 1 +} + +OPT_CHECK=y + +while getopts "chlnqsy" opt $*; do + case $opt in + c) OPT_CHECK=y;; + l) OPT_NLINK=y;; + n) OPT_DRYRUN=n; OPT_YES=y;; + q) ECHO=:;; + s) OPT_CHECK="";; + y) OPT_YES=y;; + h|\?) usage;; + esac +done +shift $((OPTIND - 1)) + +if [ -z "$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 "" 1>&2 + echo "If emptying OST(s) that are not disabled on the MDS, new" 1>&2 + echo "files may use them. To prevent MDS allocating any files on" 1>&2 + echo "OSTNNNN run 'lctl --device %{fsname}-OSTNNNN-osc deactivate'" 1>&2 + echo "on the MDS." 1>&2 + echo -n "Continue? (y/n) " + read CHECK + [ "$CHECK" != "y" -a "$CHECK" != "yes" ] && exit 1 +fi + +# if rsync has --xattr support, then try to copy the xattrs. +$RSYNC --help 2>&1 | grep -q xattr && RSYNC_OPTS="$RSYNC_OPTS -X" +$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=: + +lfs_migrate() { + while read OLDNAME; do + $ECHO -n "$OLDNAME: " + + # avoid duplicate stat if possible + TYPE_LINK=($(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. + if [ "${TYPE_LINK[1]}" != "regular" ]; then + echo -e "not a regular file, skipped" + continue + fi + + if [ -z "$OPT_NLINK" -a ${TYPE_LINK[0]} -gt 1 ]; then + echo -e "multiple hard links, skipped" + continue + fi + + # working out write perms is hard, let the shell do it + if [ ! -w "$OLDNAME" ]; then + echo -e "no write permission, skipped" + continue + fi + + if [ "$OPT_DRYRUN" ]; then + echo -e "dry run, skipped" + continue + fi + + + # if rsync copies Lustre xattrs properly in the future + # (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) + [ -z "$COUNT" -o -z "$SIZE" ] && UNLINK="" + 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" + + # we use --inplace, since we created our own temp file already + if ! $RSYNC -a --inplace $RSYNC_OPTS "$OLDNAME" "$NEWNAME";then + echo -e "\r$OLDNAME: copy error, exiting" 1>&2 + rm -f "$NEWNAME" + exit 4 + fi + + if [ "$OPT_CHECK" ] && ! cmp "$OLDNAME" "$NEWNAME"; then + echo -e "\r$NEWNAME: compare failed, exiting" 1>&2 + exit 8 + fi + + if ! mv "$NEWNAME" "$OLDNAME"; then + echo -e "\r$OLDNAME: rename error, exiting" 1>&2 + exit 12 + fi + $ECHO "done" + done +} + +if [ "$#" -eq 0 ]; then + lfs_migrate +else + while [ "$1" ]; do + if [ -d "$1" ]; then + lfs find "$1" -type f | lfs_migrate + else + echo $1 | lfs_migrate + fi + shift + done +fi