1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-22 17:35:59 +03:00
lvm2/scripts/lvresize_fs_helper.sh
David Teigland 264827cb98 lvresize: add new options and defaults for fs handling
The new option "--fs String" for lvresize/lvreduce/lvextend
controls the handling of file systems before/after resizing
the LV.  --resizefs is the same as --fs resize.

The new option "--fsmode String" can be used to control
mounting and unmounting of the fs during resizing.

Possible --fs values:

checksize
  Only applies to reducing size; does nothing for extend.
  Check the fs size and reduce the LV if the fs is not using
  the affected space, i.e. the fs does not need to be shrunk.
  Fail the command without reducing the fs or LV if the fs is
  using the affected space.

resize
  Resize the fs using the fs-specific resize command.
  This may include mounting, unmounting, or running fsck.
  See --fsmode to control mounting behavior, and --nofsck to
  disable fsck.

resize_fsadm
  Use the old method of calling fsadm to handle the fs
  (deprecated.) Warning: this option does not prevent lvreduce
  from destroying file systems that are unmounted (or mounted
  if prompts are skipped.)

ignore
  Resize the LV without checking for or handling a file system.
  Warning: using ignore when reducing the LV size may destroy the
  file system.

Possible --fsmode values:

manage
  Mount or unmount the fs as needed to resize the fs,
  and attempt to restore the original mount state at the end.

nochange
  Do not mount or unmount the fs. If mounting or unmounting
  is required to resize the fs, then do not resize the fs or
  the LV and fail the command.

offline
  Unmount the fs if it is mounted, and resize the fs while it
  is unmounted. If mounting is required to resize the fs,
  then do not resize the fs or the LV and fail the command.

Notes on lvreduce:

When no --fs or --resizefs option is specified:
. lvextend default behavior is fs ignore.
. lvreduce default behavior is fs checksize
  (includes activating the LV.)

With the exception of --fs resize_fsadm|ignore, lvreduce requires
the recent libblkid fields FSLASTBLOCK and FSBLOCKSIZE.
FSLASTBLOCK*FSBLOCKSIZE is the last byte used by the fs on the LV,
which determines if reducing the fs is necessary.
2022-09-13 15:15:05 -05:00

467 lines
9.8 KiB
Bash
Executable File

#!/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 h -l help,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
;;
-h|--help)
usage
shift
exit 0
;;
--)
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