From 019232ab4eb516614ca66431341f264f120fe810 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Thu, 1 Sep 2022 14:12:08 -0500 Subject: lvresize: use script to call fs commands Intead of calling each fs command directly, call a helper script that will run those commands. --- lib/device/filesystem.c | 292 +++++++++++++------------- lib/device/filesystem.h | 15 +- lib/metadata/lv_manip.c | 94 ++------- scripts/Makefile.in | 2 +- scripts/lvresize_fs_helper.sh | 475 ++++++++++++++++++++++++++++++++++++++++++ test/shell/lvresize-fs.sh | 10 + 6 files changed, 656 insertions(+), 232 deletions(-) create mode 100755 scripts/lvresize_fs_helper.sh diff --git a/lib/device/filesystem.c b/lib/device/filesystem.c index 4bdb88863..3e22e98ec 100644 --- a/lib/device/filesystem.c +++ b/lib/device/filesystem.c @@ -263,221 +263,211 @@ int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv, return ret; } -#define FS_CMD_MAX_ARGS 6 +#define FS_CMD_MAX_ARGS 16 -int fs_fsck_command(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi) +int crypt_resize_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi, + uint64_t newsize_bytes_fs) { + char crypt_path[PATH_MAX]; + char newsize_str[16] = { 0 }; const char *argv[FS_CMD_MAX_ARGS + 4]; int args = 0; int status; - if (strncmp(fsi->fstype, "ext", 3)) { - log_error("fsck not supported for %s.", fsi->fstype); + if (dm_snprintf(newsize_str, sizeof(newsize_str), "%llu", (unsigned long long)newsize_bytes_fs) < 0) return_0; - } - /* - * ext234: e2fsck -f -p path - * TODO: replace -p with -y based on yes_ARG, or other? - */ + if (dm_snprintf(crypt_path, sizeof(crypt_path), "/dev/dm-%d", (int)MINOR(fsi->crypt_devt)) < 0) + return_0; - argv[0] = E2FSCK_PATH; /* defined by configure */ - argv[++args] = "-f"; - argv[++args] = "-p"; - argv[++args] = fsi->fs_dev_path; + argv[0] = "/usr/sbin/lvresize_fs_helper"; /* define in configure? */ + argv[++args] = "--cryptresize"; + argv[++args] = "--cryptpath"; + argv[++args] = crypt_path; + argv[++args] = "--newsizebytes"; + argv[++args] = newsize_str; argv[++args] = NULL; - log_print("Checking file system %s with %s on %s...", - fsi->fstype, E2FSCK_PATH, display_lvname(lv)); - if (!exec_cmd(cmd, argv, &status, 1)) { - log_error("e2fsck failed on %s.", display_lvname(lv)); + log_error("Failed to resize crypt dev with lvresize_fs_helper."); return 0; } - log_print("Checked file system %s on %s.", fsi->fstype, display_lvname(lv)); return 1; } -int fs_reduce_command(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi, - uint64_t newsize_bytes) +/* + * The helper script does the following steps for reduce: + * devpath = $cryptpath ? $cryptpath : $lvpath + * if needs_unmount + * umount $mountdir + * if needs_fsck + * e2fsck -f -p $devpath + * if needs_mount + * mount $devpath $tmpdir + * if $fstype == "ext" + * resize2fs $devpath $newsize_kb + * if needs_crypt + * cryptsetup resize --size $newsize_sectors $cryptpath + * + * Note: when a crypt layer is included, newsize_bytes_fs is smaller + * than newsize_bytes_lv because of the crypt header. + */ + +int fs_reduce_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi, + uint64_t newsize_bytes_fs, char *fsopt) { - char newsize_kb_str[16] = { 0 }; + char lv_path[PATH_MAX]; + char crypt_path[PATH_MAX]; + char newsize_str[16] = { 0 }; const char *argv[FS_CMD_MAX_ARGS + 4]; + char *devpath; int args = 0; int status; - if (!strncmp(fsi->fstype, "ext", 3)) { - if (dm_snprintf(newsize_kb_str, 16, "%lluk", (unsigned long long)(newsize_bytes/1024)) < 0) - return_0; - - /* - * ext234 shrink: resize2fs path newsize - */ - argv[0] = RESIZE2FS_PATH; /* defined by configure */ - argv[++args] = fsi->fs_dev_path; - argv[++args] = newsize_kb_str; - argv[++args] = NULL; + if (dm_snprintf(newsize_str, sizeof(newsize_str), "%llu", (unsigned long long)newsize_bytes_fs) < 0) + return_0; - } else { - log_error("fs reduce not supported for %s.", fsi->fstype); + if (dm_snprintf(lv_path, PATH_MAX, "%s%s/%s", lv->vg->cmd->dev_dir, lv->vg->name, lv->name) < 0) return_0; - } - log_print("Reducing file system %s on %s...", fsi->fstype, display_lvname(lv)); + argv[0] = "/usr/sbin/lvresize_fs_helper"; /* define in configure? */ + argv[++args] = "--fsreduce"; + argv[++args] = "--fstype"; + argv[++args] = fsi->fstype; + argv[++args] = "--lvpath"; + argv[++args] = lv_path; - if (!exec_cmd(cmd, argv, &status, 1)) { - log_error("Failed to reduce %s file system on %s.", fsi->fstype, display_lvname(lv)); - return 0; + if (newsize_bytes_fs) { + argv[++args] = "--newsizebytes"; + argv[++args] = newsize_str; } - - log_print("Reduced file system %s to %s (%llu bytes) on %s.", - fsi->fstype, display_size(cmd, newsize_bytes/512), - (unsigned long long)newsize_bytes, display_lvname(lv)); - return 1; -} - -int fs_extend_command(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi) -{ - const char *argv[FS_CMD_MAX_ARGS + 4]; - int args = 0; - int status; - - if (!strncmp(fsi->fstype, "ext", 3)) { - /* TODO: include -f if lvm command inclues -f ? */ - argv[0] = RESIZE2FS_PATH; /* defined by configure */ - argv[++args] = fsi->fs_dev_path; - argv[++args] = NULL; - - } else if (!strcmp(fsi->fstype, "xfs")) { - argv[0] = XFS_GROWFS_PATH; /* defined by configure */ - argv[++args] = fsi->fs_dev_path; - argv[++args] = NULL; - - } else { - log_error("Extend not supported for %s file system.", fsi->fstype); - return_0; + if (fsi->mounted) { + argv[++args] = "--mountdir"; + argv[++args] = fsi->mount_dir; } - log_print("Extending file system %s on %s...", fsi->fstype, display_lvname(lv)); + if (fsi->needs_unmount) + argv[++args] = "--unmount"; + if (fsi->needs_mount) + argv[++args] = "--mount"; + if (fsi->needs_fsck) + argv[++args] = "--fsck"; - if (!exec_cmd(cmd, argv, &status, 1)) { - log_error("Failed to extend %s file system on %s.", fsi->fstype, display_lvname(lv)); - return 0; + if (fsi->needs_crypt) { + if (dm_snprintf(crypt_path, sizeof(crypt_path), "/dev/dm-%d", (int)MINOR(fsi->crypt_devt)) < 0) + return_0; + argv[++args] = "--cryptresize"; + argv[++args] = "--cryptpath"; + argv[++args] = crypt_path; } - log_print("Extended file system %s on %s.", fsi->fstype, display_lvname(lv)); - return 1; -} - -int fs_mount_command(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi, - int reuse_mount_dir) -{ - char mountdir[PATH_MAX]; - const char *argv[FS_CMD_MAX_ARGS + 4]; - int args = 0; - int status; + /* + * --fs resize|resize_remount want the fs to be remounted after + * resizing if it was unmounted. (Not often applicable.) + */ + if (fsi->needs_unmount && (!strcmp(fsopt, "resize") || !strcmp(fsopt, "resize_remount"))) + argv[++args] = "--remount"; - if (reuse_mount_dir) { - if (!fsi->mount_dir[0]) { - log_error("Cannot remount fs without previous mount dir."); - return 0; - } - memcpy(mountdir, fsi->mount_dir, PATH_MAX); - } else { - if (dm_snprintf(mountdir, sizeof(mountdir), "/tmp/%s_XXXXXX", cmd->name) < 0) - return_0; - if (!mkdtemp(mountdir)) { - log_error("Failed to create temp dir for mount: %s", strerror(errno)); - return 0; - } - memcpy(fsi->mount_dir, mountdir, PATH_MAX); - fsi->temp_mount_dir = 1; - } - - argv[0] = MOUNT_PATH; /* defined by configure */ - argv[++args] = fsi->fs_dev_path; - argv[++args] = mountdir; argv[++args] = NULL; - log_print("Mounting %s.", display_lvname(lv)); + devpath = fsi->needs_crypt ? crypt_path : (char *)display_lvname(lv); + + log_print("Reducing file system %s to %s (%llu bytes) on %s...", + fsi->fstype, display_size(cmd, newsize_bytes_fs/512), + (unsigned long long)newsize_bytes_fs, devpath); if (!exec_cmd(cmd, argv, &status, 1)) { - log_error("Failed to mount file system on %s at %s.", display_lvname(lv), mountdir); + log_error("Failed to reduce file system with lvresize_fs_helper."); return 0; } - log_print("Mounted %s at %s dir %s.", display_lvname(lv), - reuse_mount_dir ? "original" : "temporary", mountdir); + log_print("Reduced file system %s on %s.", fsi->fstype, devpath); + return 1; } -int fs_unmount_command(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi) +/* + * The helper script does the following steps for extend: + * devpath = $cryptpath ? $cryptpath : $lvpath + * if needs_unmount + * umount $mountdir + * if needs_fsck + * e2fsck -f -p $devpath + * if needs_crypt + * cryptsetup resize $cryptpath + * if needs_mount + * mount $devpath $tmpdir + * if $fstype == "ext" + * resize2fs $devpath + * if $fstype == "xfs" + * xfs_growfs $devpath + * + * Note: when a crypt layer is included, newsize_bytes_fs is smaller + * than newsize_bytes_lv because of the crypt header. + */ + +int fs_extend_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi, + uint64_t newsize_bytes_fs, char *fsopt) { + char lv_path[PATH_MAX]; + char crypt_path[PATH_MAX]; const char *argv[FS_CMD_MAX_ARGS + 4]; + char *devpath; int args = 0; int status; - argv[0] = UMOUNT_PATH; /* defined by configure */ - argv[++args] = fsi->fs_dev_path; - argv[++args] = NULL; + if (dm_snprintf(lv_path, PATH_MAX, "%s%s/%s", lv->vg->cmd->dev_dir, lv->vg->name, lv->name) < 0) + return_0; - log_print("Unmounting %s.", display_lvname(lv)); + argv[0] = "/usr/sbin/lvresize_fs_helper"; /* define in configure? */ + argv[++args] = "--fsextend"; + argv[++args] = "--fstype"; + argv[++args] = fsi->fstype; + argv[++args] = "--lvpath"; + argv[++args] = lv_path; - if (!exec_cmd(cmd, argv, &status, 1)) { - log_error("Failed to unmount file system on %s.", display_lvname(lv)); - return 0; + if (fsi->mounted) { + argv[++args] = "--mountdir"; + argv[++args] = fsi->mount_dir; } - log_print("Unmounted %s.", display_lvname(lv)); + if (fsi->needs_unmount) + argv[++args] = "--unmount"; + if (fsi->needs_mount) + argv[++args] = "--mount"; + if (fsi->needs_fsck) + argv[++args] = "--fsck"; - if (fsi->temp_mount_dir) { - if (rmdir(fsi->mount_dir) < 0) - log_print("Error removing temp dir %s", fsi->mount_dir); - fsi->mount_dir[0] = '\0'; - fsi->temp_mount_dir = 0; + if (fsi->needs_crypt) { + if (dm_snprintf(crypt_path, sizeof(crypt_path), "/dev/dm-%d", (int)MINOR(fsi->crypt_devt)) < 0) + return_0; + argv[++args] = "--cryptresize"; + argv[++args] = "--cryptpath"; + argv[++args] = crypt_path; } - return 1; -} - -int crypt_resize_command(struct cmd_context *cmd, dev_t crypt_devt, uint64_t newsize_bytes) -{ - char crypt_path[PATH_MAX]; - const char *argv[FS_CMD_MAX_ARGS + 4]; - char size_str[16] = { 0 }; - int args = 0; - int status; - if (dm_snprintf(crypt_path, sizeof(crypt_path), "/dev/dm-%d", (int)MINOR(crypt_devt)) < 0) - return_0; - - if (dm_snprintf(size_str, sizeof(size_str), "%llu", (unsigned long long)newsize_bytes/512) < 0) - return_0; + /* + * --fs resize|resize_remount want the fs to be remounted after + * resizing if it was unmounted. (Not often applicable.) + */ + if (fsi->needs_unmount && (!strcmp(fsopt, "resize") || !strcmp(fsopt, "resize_remount"))) + argv[++args] = "--remount"; - argv[0] = CRYPTSETUP_PATH; /* defined by configure */ - argv[++args] = "resize"; - if (newsize_bytes) { - argv[++args] = "--size"; - argv[++args] = size_str; - } - argv[++args] = crypt_path; argv[++args] = NULL; - log_print("Resizing crypt device %s...", crypt_path); + devpath = fsi->needs_crypt ? crypt_path : (char *)display_lvname(lv); + + log_print("Extending file system %s to %s (%llu bytes) on %s...", + fsi->fstype, display_size(cmd, newsize_bytes_fs/512), + (unsigned long long)newsize_bytes_fs, devpath); if (!exec_cmd(cmd, argv, &status, 1)) { - log_error("Failed to cryptsetup resize %s to %s (%llu sectors)", - crypt_path, display_size(cmd, newsize_bytes/512), - (unsigned long long)newsize_bytes/512); + log_error("Failed to extend file system with lvresize_fs_helper."); return 0; } - if (newsize_bytes) - log_print("Resized crypt device %s to %s (%llu sectors)", - crypt_path, display_size(cmd, newsize_bytes/512), - (unsigned long long)newsize_bytes/512); - else - log_print("Resized crypt device %s.", crypt_path); + log_print("Extended file system %s on %s.", fsi->fstype, devpath); return 1; } diff --git a/lib/device/filesystem.h b/lib/device/filesystem.h index 1e83469cb..fcdfd8af0 100644 --- a/lib/device/filesystem.h +++ b/lib/device/filesystem.h @@ -41,14 +41,11 @@ struct fs_info { int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi, int include_mount); -int fs_fsck_command(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi); -int fs_reduce_command(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi, - uint64_t newsize_bytes); -int fs_extend_command(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi); -int fs_mount_command(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi, - int reuse_mount_dir); -int fs_unmount_command(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi); - -int crypt_resize_command(struct cmd_context *cmd, dev_t crypt_devt, uint64_t newsize_bytes); +int fs_extend_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi, + uint64_t newsize_bytes, char *fsopt); +int fs_reduce_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi, + uint64_t newsize_bytes, char *fsopt); +int crypt_resize_script(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info *fsi, + uint64_t newsize_bytes_fs); #endif diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index 91bc6bd0d..309fce061 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -6346,7 +6346,6 @@ static int _fs_reduce(struct cmd_context *cmd, struct logical_volume *lv, struct fs_info fsinfo2; uint64_t newsize_bytes_lv; uint64_t newsize_bytes_fs; - int mounted = 0, unmounted = 0; int ret = 0; memset(&fsinfo, 0, sizeof(fsinfo)); @@ -6365,8 +6364,8 @@ static int _fs_reduce(struct cmd_context *cmd, struct logical_volume *lv, newsize_bytes_fs = newsize_bytes_lv; /* - * If needs_crypt, then newsize_bytes passed to fs_reduce_command() and - * crypt_resize_command() needs to be decreased by the offset of crypt + * If needs_crypt, then newsize_bytes passed to fs_reduce_script() and + * crypt_resize_script() needs to be decreased by the offset of crypt * data on the LV (usually the size of the LUKS header which is usually * 2MB for LUKS1 and 16MB for LUKS2.) */ @@ -6391,7 +6390,7 @@ static int _fs_reduce(struct cmd_context *cmd, struct logical_volume *lv, * the LV size, so that the FS does not see an incorrect device size. */ if (!fsinfo.needs_reduce && fsinfo.needs_crypt && !test_mode()) { - ret = crypt_resize_command(cmd, fsinfo.crypt_devt, newsize_bytes_fs); + ret = crypt_resize_script(cmd, lv, &fsinfo, newsize_bytes_fs); goto out; } @@ -6425,31 +6424,9 @@ static int _fs_reduce(struct cmd_context *cmd, struct logical_volume *lv, */ unlock_vg(cmd, lv->vg, lv->vg->name); - if (fsinfo.needs_unmount) { - if (!fs_unmount_command(cmd, lv, &fsinfo)) - goto_out; - unmounted = 1; - } - - if (fsinfo.needs_fsck) { - if (!fs_fsck_command(cmd, lv, &fsinfo)) - goto_out; - } - - if (fsinfo.needs_mount) { - if (!fs_mount_command(cmd, lv, &fsinfo, 0)) - goto_out; - mounted = 1; - } - - if (!fs_reduce_command(cmd, lv, &fsinfo, newsize_bytes_fs)) + if (!fs_reduce_script(cmd, lv, &fsinfo, newsize_bytes_fs, lp->fsopt)) goto_out; - if (fsinfo.needs_crypt) { - if (!crypt_resize_command(cmd, fsinfo.crypt_devt, newsize_bytes_fs)) - goto_out; - } - if (!lock_vol(cmd, lv->vg->name, LCK_VG_WRITE, NULL)) { log_error("Failed to lock VG, cannot reduce LV."); ret = 0; @@ -6482,16 +6459,6 @@ static int _fs_reduce(struct cmd_context *cmd, struct logical_volume *lv, } ret = 1; - - /* - * put the fs back into the original mounted|unmounted state. - */ - if (!strcmp(lp->fsopt, "resize_remount") || !strcmp(lp->fsopt, "resize")) { - if (mounted && !fs_unmount_command(cmd, lv, &fsinfo)) - ret = 0; - if (unmounted && !fs_mount_command(cmd, lv, &fsinfo, 1)) - ret = 0; - } out: return ret; } @@ -6500,7 +6467,8 @@ static int _fs_extend(struct cmd_context *cmd, struct logical_volume *lv, struct lvresize_params *lp) { struct fs_info fsinfo; - int mounted = 0, unmounted = 0; + uint64_t newsize_bytes_lv; + uint64_t newsize_bytes_fs; int ret = 0; memset(&fsinfo, 0, sizeof(fsinfo)); @@ -6513,6 +6481,22 @@ static int _fs_extend(struct cmd_context *cmd, struct logical_volume *lv, goto_out; } + /* + * Note: here in the case of extend, newsize_bytes_lv/newsize_bytes_fs + * are only calculated and used for log messages. The extend commands + * do not use these values, they just extend to the new LV size that + * is visible to them. + */ + + /* extent_size units is SECTOR_SIZE (512) */ + newsize_bytes_lv = lp->extents * lv->vg->extent_size * SECTOR_SIZE; + newsize_bytes_fs = newsize_bytes_lv; + if (fsinfo.needs_crypt) { + newsize_bytes_fs -= fsinfo.crypt_offset_bytes; + log_print("File system size %llub is adjusted for crypt data offset %ub.", + (unsigned long long)newsize_bytes_fs, fsinfo.crypt_offset_bytes); + } + /* * Decide if fs should be extended based on the --fs option, * the fs type and the mount state. @@ -6550,42 +6534,10 @@ static int _fs_extend(struct cmd_context *cmd, struct logical_volume *lv, */ unlock_vg(cmd, lv->vg, lv->vg->name); - if (fsinfo.needs_unmount) { - if (!fs_unmount_command(cmd, lv, &fsinfo)) - goto_out; - unmounted = 1; - } - - if (fsinfo.needs_fsck) { - if (!fs_fsck_command(cmd, lv, &fsinfo)) - goto_out; - } - - if (fsinfo.needs_crypt) { - if (!crypt_resize_command(cmd, fsinfo.crypt_devt, 0)) - goto_out; - } - - if (fsinfo.needs_mount) { - if (!fs_mount_command(cmd, lv, &fsinfo, 0)) - goto_out; - mounted = 1; - } - - if (!fs_extend_command(cmd, lv, &fsinfo)) + if (!fs_extend_script(cmd, lv, &fsinfo, newsize_bytes_fs, lp->fsopt)) goto_out; ret = 1; - - /* - * put the fs back into the original mounted|unmounted state. - */ - if (!strcmp(lp->fsopt, "resize_remount") || !strcmp(lp->fsopt, "resize")) { - if (mounted && !fs_unmount_command(cmd, lv, &fsinfo)) - ret = 0; - if (unmounted && !fs_mount_command(cmd, lv, &fsinfo, 1)) - ret = 0; - } out: return ret; } diff --git a/scripts/Makefile.in b/scripts/Makefile.in index ebcea92f9..607df3c0a 100644 --- a/scripts/Makefile.in +++ b/scripts/Makefile.in @@ -21,7 +21,7 @@ ifeq ("@BUILD_DMEVENTD@", "yes") LDFLAGS += -Wl,-rpath-link,$(top_builddir)/daemons/dmeventd endif -LVM_SCRIPTS = lvmdump.sh +LVM_SCRIPTS = lvmdump.sh lvresize_fs_helper.sh DM_SCRIPTS = ifeq ("@FSADM@", "yes") 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 + diff --git a/test/shell/lvresize-fs.sh b/test/shell/lvresize-fs.sh index 41b97008f..53bd532f0 100644 --- a/test/shell/lvresize-fs.sh +++ b/test/shell/lvresize-fs.sh @@ -717,6 +717,7 @@ df --output=size "$mount_dir" |tee df1 # fs is 200M, reduced size is 216M, so no fs reduce is needed lvreduce -L216M $vg/$lv check lv_field $vg/$lv lv_size "216.00m" +ls -l $mount_dir/zeros1 df --output=size "$mount_dir" |tee df2 # fs size unchanged diff df1 df2 @@ -735,6 +736,7 @@ df --output=size "$mount_dir" |tee df1 # fs is 200M, reduced size is 200M, so no fs reduce is needed lvreduce -L200M $vg/$lv check lv_field $vg/$lv lv_size "200.00m" +ls -l $mount_dir/zeros1 df --output=size "$mount_dir" |tee df2 # fs size unchanged diff df1 df2 @@ -752,6 +754,7 @@ df --output=size "$mount_dir" |tee df1 # lvreduce runs resize2fs to shrink the fs lvreduce --yes --fs resize -L-200M $vg/$lv check lv_field $vg/$lv lv_size "256.00m" +ls -l $mount_dir/zeros1 df --output=size "$mount_dir" |tee df2 # fs size is changed not diff df1 df2 @@ -773,6 +776,8 @@ df --output=size "$mount_dir" |tee df1 not lvreduce --yes --fs resize -L-200M $vg/$lv check lv_field $vg/$lv lv_size "456.00m" mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir" +ls -l $mount_dir/zeros1 +ls -l $mount_dir/zeros2 df --output=size "$mount_dir" |tee df2 # fs size is unchanged diff df1 df2 @@ -795,6 +800,7 @@ umount "$mount_dir" lvreduce -L216M $vg/$lv check lv_field $vg/$lv lv_size "216.00m" mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir" +ls -l $mount_dir/zeros1 df --output=size "$mount_dir" |tee df2 # fs size unchanged diff df1 df2 @@ -815,6 +821,7 @@ umount "$mount_dir" lvreduce -L200M $vg/$lv check lv_field $vg/$lv lv_size "200.00m" mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir" +ls -l $mount_dir/zeros1 df --output=size "$mount_dir" |tee df2 # fs size unchanged diff df1 df2 @@ -834,6 +841,7 @@ umount "$mount_dir" lvreduce --fs resize -L-200M $vg/$lv check lv_field $vg/$lv lv_size "256.00m" mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir" +ls -l $mount_dir/zeros1 df --output=size "$mount_dir" |tee df2 # fs size is changed not diff df1 df2 @@ -854,6 +862,7 @@ umount "$mount_dir" not lvreduce --yes --fs resize -L-200M $vg/$lv check lv_field $vg/$lv lv_size "456.00m" mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir" +ls -l $mount_dir/zeros1 df --output=size "$mount_dir" |tee df2 # fs size is unchanged diff df1 df2 @@ -949,6 +958,7 @@ df --output=size "$mount_dir" |tee df1 # lvreduce runs resize2fs to shrink the fs lvreduce --yes --fs resize_fsadm -L-200M $vg/$lv check lv_field $vg/$lv lv_size "256.00m" +ls -l $mount_dir/zeros1 df --output=size "$mount_dir" |tee df2 # fs size is changed not diff df1 df2 -- cgit v1.2.1