diff options
Diffstat (limited to 'scripts/lvresize_fs_helper.sh')
-rwxr-xr-x | scripts/lvresize_fs_helper.sh | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/scripts/lvresize_fs_helper.sh b/scripts/lvresize_fs_helper.sh new file mode 100755 index 000000000..94eb4c775 --- /dev/null +++ b/scripts/lvresize_fs_helper.sh @@ -0,0 +1,475 @@ +#!/bin/bash +# +# Copyright (C) 2022 Red Hat, Inc. All rights reserved. +# +# This file is part of LVM2. +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions +# of the GNU General Public License v.2. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +errorexit() { + echo "$1" >&2 + exit 1 +} + +logmsg() { + echo "$1" + logger "${SCRIPTNAME}: $1" +} + +# Set to 1 while the fs is temporarily mounted on $TMPDIR +TMP_MOUNT_DONE=0 +# Set to 1 if the fs resize command fails +RESIZEFS_FAILED=0 + +fsextend() { + if [ "$DO_UNMOUNT" -eq 1 ]; then + logmsg "unmount ${MOUNTDIR}" + umount "$MOUNTDIR" + if [ $? -eq 0 ]; then + logmsg "unmount done" + else + logmsg "unmount failed" + exit 1 + fi + fi + + if [ "$DO_FSCK" -eq 1 ]; then + logmsg "e2fsck ${DEVPATH}" + e2fsck -f -p "$DEVPATH" + if [ $? -eq 0 ]; then + logmsg "e2fsck done" + else + logmsg "e2fsck failed" + exit 1 + fi + fi + + if [ "$DO_CRYPTRESIZE" -eq 1 ]; then + logmsg "cryptsetup resize ${DEVPATH}" + cryptsetup resize "$DEVPATH" + if [ $? -eq 0 ]; then + logmsg "cryptsetup done" + else + logmsg "cryptsetup failed" + exit 1 + fi + fi + + if [ "$DO_MOUNT" -eq 1 ]; then + logmsg "mount ${DEVPATH} ${TMPDIR}" + mount -t "$FSTYPE" "$DEVPATH" "$TMPDIR" + if [ $? -eq 0 ]; then + logmsg "mount done" + TMP_MOUNT_DONE=1 + else + logmsg "mount failed" + exit 1 + fi + fi + + if [[ "$FSTYPE" == "ext"* ]]; then + logmsg "resize2fs ${DEVPATH}" + resize2fs "$DEVPATH" + if [ $? -eq 0 ]; then + logmsg "resize2fs done" + else + logmsg "resize2fs failed" + RESIZEFS_FAILED=1 + fi + elif [[ "$FSTYPE" == "xfs" ]]; then + logmsg "xfs_growfs ${DEVPATH}" + xfs_growfs "$DEVPATH" + if [ $? -eq 0 ]; then + logmsg "xfs_growfs done" + else + logmsg "xfs_growfs failed" + RESIZEFS_FAILED=1 + fi + fi + + # If the fs was temporarily mounted, now unmount it. + if [ $TMP_MOUNT_DONE -eq 1 ]; then + logmsg "cleanup unmount ${TMPDIR}" + umount "$TMPDIR" + if [ $? -eq 0 ]; then + logmsg "cleanup unmount done" + TMP_MOUNT_DONE=0 + rmdir "$TMPDIR" + else + logmsg "cleanup unmount failed" + exit 1 + fi + fi + + # If the fs was temporarily unmounted, now remount it. + # Not considered a command failure if this fails. + if [[ $DO_UNMOUNT -eq 1 && $REMOUNT -eq 1 ]]; then + logmsg "remount ${DEVPATH} ${MOUNTDIR}" + mount -t "$FSTYPE" "$DEVPATH" "$MOUNTDIR" + if [ $? -eq 0 ]; then + logmsg "remount done" + else + logmsg "remount failed" + fi + fi + + if [ $RESIZEFS_FAILED -eq 1 ]; then + logmsg "File system extend failed." + exit 1 + fi + + exit 0 +} + +fsreduce() { + if [ "$DO_UNMOUNT" -eq 1 ]; then + logmsg "unmount ${MOUNTDIR}" + umount "$MOUNTDIR" + if [ $? -eq 0 ]; then + logmsg "unmount done" + else + logmsg "unmount failed" + exit 1 + fi + fi + + if [ "$DO_FSCK" -eq 1 ]; then + logmsg "e2fsck ${DEVPATH}" + e2fsck -f -p "$DEVPATH" + if [ $? -eq 0 ]; then + logmsg "e2fsck done" + else + logmsg "e2fsck failed" + exit 1 + fi + fi + + if [ "$DO_MOUNT" -eq 1 ]; then + logmsg "mount ${DEVPATH} ${TMPDIR}" + mount -t "$FSTYPE" "$DEVPATH" "$TMPDIR" + if [ $? -eq 0 ]; then + logmsg "mount done" + TMP_MOUNT_DONE=1 + else + logmsg "mount failed" + exit 1 + fi + fi + + if [[ "$FSTYPE" == "ext"* ]]; then + NEWSIZEKB=$(($NEWSIZEBYTES/1024)) + logmsg "resize2fs ${DEVPATH} ${NEWSIZEKB}k" + resize2fs "$DEVPATH" "$NEWSIZEKB"k + if [ $? -eq 0 ]; then + logmsg "resize2fs done" + else + logmsg "resize2fs failed" + # will exit after cleanup unmount + RESIZEFS_FAILED=1 + fi + fi + + # If the fs was temporarily mounted, now unmount it. + if [ $TMP_MOUNT_DONE -eq 1 ]; then + logmsg "cleanup unmount ${TMPDIR}" + umount "$TMPDIR" + if [ $? -eq 0 ]; then + logmsg "cleanup unmount done" + TMP_MOUNT_DONE=0 + rmdir "$TMPDIR" + else + logmsg "cleanup unmount failed" + exit 1 + fi + fi + + if [ $RESIZEFS_FAILED -eq 1 ]; then + logmsg "File system reduce failed." + exit 1 + fi + + if [ "$DO_CRYPTRESIZE" -eq 1 ]; then + NEWSIZESECTORS=$(($NEWSIZEBYTES/512)) + logmsg "cryptsetup resize ${NEWSIZESECTORS} sectors ${DEVPATH}" + cryptsetup resize --size "$NEWSIZESECTORS" "$DEVPATH" + if [ $? -eq 0 ]; then + logmsg "cryptsetup done" + else + logmsg "cryptsetup failed" + exit 1 + fi + fi + + # If the fs was temporarily unmounted, now remount it. + # Not considered a command failure if this fails. + if [[ $DO_UNMOUNT -eq 1 && $REMOUNT -eq 1 ]]; then + logmsg "remount ${DEVPATH} ${MOUNTDIR}" + mount -t "$FSTYPE" "$DEVPATH" "$MOUNTDIR" + if [ $? -eq 0 ]; then + logmsg "remount done" + else + logmsg "remount failed" + fi + fi + + exit 0 +} + +cryptresize() { + NEWSIZESECTORS=$(($NEWSIZEBYTES/512)) + logmsg "cryptsetup resize ${NEWSIZESECTORS} sectors ${DEVPATH}" + cryptresize resize --size "$NEWSIZESECTORS" "$DEVPATH" + if [ $? -eq 0 ]; then + logmsg "cryptsetup done" + else + logmsg "cryptsetup failed" + exit 1 + fi + + exit 0 +} + +usage() { + echo "${SCRIPTNAME}: helper script called by lvresize to resize file systems." + echo "" + echo "${SCRIPTNAME} --fsextend --fstype name --lvpath path" + echo " [ --mountdir path ]" + echo " [ --mount ]" + echo " [ --unmount ]" + echo " [ --remount ]" + echo " [ --fsck ]" + echo " [ --cryptresize ]" + echo " [ --cryptpath path ]" + echo "" + echo "${SCRIPTNAME} --fsreduce --fstype name --lvpath path" + echo " [ --newsizebytes num ]" + echo " [ --mountdir path ]" + echo " [ --mount ]" + echo " [ --unmount ]" + echo " [ --remount ]" + echo " [ --fsck ]" + echo " [ --cryptresize ]" + echo " [ --cryptpath path ]" + echo "" + echo "${SCRIPTNAME} --cryptresize --cryptpath path --newsizebytes num" + echo "" + echo "Options:" + echo " --fsextend" + echo " Extend the file system." + echo " --fsreduce" + echo " Reduce the file system." + echo " --fstype name" + echo " The type of file system (ext*, xfs)." + echo " --lvpath path" + echo " The path to the LV being resized." + echo " --mountdir path" + echo " The file system is currently mounted here." + echo " --mount" + echo " Mount the file system on a temporary directory before resizing." + echo " --unmount" + echo " Unmount the file system before resizing." + echo " --remount" + echo " Remount the file system after resizing if unmounted." + echo " --fsck" + echo " Run fsck on the file system before resizing (only with ext*)." + echo " --newsizebytes num" + echo " The new size of the file system." + echo " --cryptresize" + echo " Resize the crypt device between the LV and file system." + echo " --cryptpath path" + echo " The path to the crypt device." + echo "" +} + +# +# BEGIN SCRIPT +# +PATH="/sbin:/usr/sbin:/bin:/usr/sbin:$PATH" +SCRIPTNAME=$(basename "$0") + +# These are the only commands that this script will run. +# Each is enabled (1) by the corresponding command options: +# --fsextend, --fsreduce, --cryptresize, --mount, --unmount, --fsck +DO_FSEXTEND=0 +DO_FSREDUCE=0 +DO_CRYPTRESIZE=0 +DO_MOUNT=0 +DO_UNMOUNT=0 +DO_FSCK=0 + +# --remount: attempt to remount the fs if it was originally +# mounted and the script unmounted it. +REMOUNT=0 + +if [ "$UID" != 0 ] && [ "$EUID" != 0 ]; then + errorexit "${SCRIPTNAME} must be run as root." +fi + +GETOPT="getopt" + +OPTIONS=$("$GETOPT" -o hv -l help,debug,fsextend,fsreduce,cryptresize,mount,unmount,remount,fsck,fstype:,lvpath:,newsizebytes:,mountdir:,cryptpath: -n "${SCRIPTNAME}" -- "$@") +eval set -- "$OPTIONS" + +while true +do + case $1 in + --fsextend) + DO_FSEXTEND=1 + shift + ;; + --fsreduce) + DO_FSREDUCE=1 + shift + ;; + --cryptresize) + DO_CRYPTRESIZE=1 + shift + ;; + --mount) + DO_MOUNT=1 + shift + ;; + --unmount) + DO_UNMOUNT=1 + shift + ;; + --fsck) + DO_FSCK=1 + shift + ;; + --remount) + REMOUNT=1 + shift + ;; + --fstype) + FSTYPE=$2; + shift; shift + ;; + --lvpath) + LVPATH=$2; + shift; shift + ;; + --newsizebytes) + NEWSIZEBYTES=$2; + shift; shift + ;; + --mountdir) + MOUNTDIR=$2; + shift; shift + ;; + --cryptpath) + CRYPTPATH=$2; + shift; shift + ;; + --debug) + DEBUG=1 + set -x + shift + ;; + -h|--help) + usage + shift + exit 0 + ;; + -v) + VERBOSE=1 + shift + ;; + --) + shift + break + ;; + *) + errorexit "Unknown option \"$1\." + exit 1 + ;; + esac +done + +# +# Input arg checking +# + +# There are three top level commands: --fsextend, --fsreduce, --cryptresize. +if [[ "$DO_FSEXTEND" -eq 0 && "$DO_FSREDUCE" -eq 0 && "$DO_CRYPTRESIZE" -eq 0 ]]; then + errorexit "Missing --fsextend|--fsreduce|--cryptresize." +fi + +if [[ "$DO_FSEXTEND" -eq 1 || "$DO_FSREDUCE" -eq 1 ]]; then + case "$FSTYPE" in + ext[234]) ;; + "xfs") ;; + *) errorexit "Cannot resize --fstype \"$FSTYPE\"." + esac + + if [ -z "$LVPATH" ]; then + errorexit "Missing required --lvpath." + fi +fi + +if [[ "$DO_CRYPTRESIZE" -eq 1 && -z "$CRYPTPATH" ]]; then + errorexit "Missing required --cryptpath for --cryptresize." +fi + +if [ "$DO_CRYPTRESIZE" -eq 1 ]; then + DEVPATH=$CRYPTPATH +else + DEVPATH=$LVPATH +fi + +if [ -z "$DEVPATH" ]; then + errorexit "Missing path to device." +fi + +if [ ! -e "$DEVPATH" ]; then + errorexit "Device does not exist \"$DEVPATH\"." +fi + +if [[ "$DO_UNMOUNT" -eq 1 && -z "$MOUNTDIR" ]]; then + errorexit "Missing required --mountdir for --unmount." +fi + +if [[ "$DO_FSREDUCE" -eq 1 && "$FSTYPE" == "xfs" ]]; then + errorexit "Cannot reduce xfs." +fi + +if [[ "$DO_FSCK" -eq 1 && "$FSTYPE" == "xfs" ]]; then + errorexit "Cannot use --fsck with xfs." +fi + +if [ "$DO_MOUNT" -eq 1 ]; then + TMPDIR=$(mktemp --suffix _lvresize_$$ -d -p /tmp) + if [ ! -e "$TMPDIR" ]; then + errorexit "Failed to create temp dir." + fi + # In case the script terminates without doing cleanup + function finish { + if [ "$TMP_MOUNT_DONE" -eq 1 ]; then + logmsg "exit unmount ${TMPDIR}" + umount "$TMPDIR" + rmdir "$TMPDIR" + fi + } + trap finish EXIT +fi + +# +# Main program function: +# - the two main functions are fsextend and fsreduce. +# - one special case function is cryptresize. +# + +if [ "$DO_FSEXTEND" -eq 1 ]; then + fsextend +elif [ "$DO_FSREDUCE" -eq 1 ]; then + fsreduce +elif [ "$DO_CRYPTRESIZE" -eq 1 ]; then + cryptresize +fi + |