summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2022-06-14 15:20:21 -0500
committerDavid Teigland <teigland@redhat.com>2022-08-10 14:16:08 -0500
commit4d8a36316ff2793a75fc401c5b2c6bc86127cafc (patch)
treebfaca50079d4402bf14b03fa455e4d45151e8a08
parent51be3b22d38fe14d228e08594e8e9e4fc23baeba (diff)
downloadlvm2-dev-dct-lvresize-5.tar.gz
lvresize: add new options and defaults for fs handlingdev-dct-lvresize-5
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. Possible --fs values: checksize Only used when reducing the size, does nothing when exending. 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_remount | resize Resize the fs if needed. Mounts or unmounts the fs as required (avoids mounting/unmounting when possible.) Attempts to restore the original mount state when finished. resize_keepmount Resize the fs if needed, only if it can be done without changing the current mount state. Fail the command without resizing the fs or LV if an fs resize requires mounting or unmounting. resize_unmount Resize the fs if needed, only while unmounted. Unmount the fs if needed. Fail the command without resizing the fs or LV if an fs resize is needed that requires the the fs to be mounted. resize_fsadm Use the old method of calling fsadm to do handle the fs (deprecated). ignore Resize the LV without checking for or handling a file system. 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.
-rw-r--r--configure.ac24
-rw-r--r--include/configure.h.in7
-rw-r--r--lib/Makefile.in1
-rw-r--r--lib/device/dev-type.c111
-rw-r--r--lib/device/dev-type.h3
-rw-r--r--lib/device/filesystem.c442
-rw-r--r--lib/device/filesystem.h54
-rw-r--r--lib/metadata/lv_manip.c776
-rw-r--r--lib/metadata/metadata-exported.h4
-rw-r--r--lib/metadata/metadata.c4
-rw-r--r--lib/metadata/metadata.h2
-rwxr-xr-xscripts/fsadm.sh2
-rw-r--r--test/shell/fsadm-crypt-fsresize.sh612
-rw-r--r--test/shell/fsadm-crypt.sh130
-rw-r--r--test/shell/fsadm.sh36
-rw-r--r--test/shell/hints.sh4
-rw-r--r--test/shell/lvresize-fs.sh1120
-rw-r--r--test/shell/lvresize-full.sh7
-rw-r--r--test/shell/lvresize-mirror.sh2
-rw-r--r--test/shell/lvresize-rounding.sh10
-rw-r--r--test/shell/relative-sign-options.sh16
-rw-r--r--tools/args.h24
-rw-r--r--tools/command-lines.in12
-rw-r--r--tools/lvresize.c61
24 files changed, 3279 insertions, 185 deletions
diff --git a/configure.ac b/configure.ac
index ba02f1f9b..3aa6b1064 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1713,6 +1713,24 @@ AC_DEFINE_UNQUOTED(FSADM_PATH, ["$FSADM_PATH"], [Path to fsadm binary.])
LVMIMPORTVDO_PATH="$SBINDIR/lvm_import_vdo"
AC_DEFINE_UNQUOTED(LVMIMPORTVDO_PATH, ["$LVMIMPORTVDO_PATH"], [Path to lvm_import_vdo script.])
+MOUNT_PATH="/usr/bin/mount"
+AC_DEFINE_UNQUOTED(MOUNT_PATH, ["$MOUNT_PATH"], [Path to mount binary.])
+
+UMOUNT_PATH="/usr/bin/umount"
+AC_DEFINE_UNQUOTED(UMOUNT_PATH, ["$UMOUNT_PATH"], [Path to umount binary.])
+
+E2FSCK_PATH="$SBINDIR/e2fsck"
+AC_DEFINE_UNQUOTED(E2FSCK_PATH, ["$E2FSCK_PATH"], [Path to e2fsck binary.])
+
+RESIZE2FS_PATH="$SBINDIR/resize2fs"
+AC_DEFINE_UNQUOTED(RESIZE2FS_PATH, ["$RESIZE2FS_PATH"], [Path to resize2fs binary.])
+
+XFS_GROWFS_PATH="$SBINDIR/xfs_growfs"
+AC_DEFINE_UNQUOTED(XFS_GROWFS_PATH, ["$XFS_GROWFS_PATH"], [Path to xfs_growfs binary.])
+
+CRYPTSETUP_PATH="$SBINDIR/cryptsetup"
+AC_DEFINE_UNQUOTED(CRYPTSETUP_PATH, ["$CRYPTSETUP_PATH"], [Path to cryptsetup binary.])
+
################################################################################
dnl -- dmeventd pidfile and executable path
if test "$BUILD_DMEVENTD" = yes; then
@@ -1882,6 +1900,12 @@ AC_SUBST(DM_LIB_PATCHLEVEL)
AC_SUBST(ELDFLAGS)
AC_SUBST(FSADM)
AC_SUBST(FSADM_PATH)
+AC_SUBST(MOUNT_PATH)
+AC_SUBST(UMOUNT_PATH)
+AC_SUBST(E2FSCK_PATH)
+AC_SUBST(RESIZE2FS_PATH)
+AC_SUBST(XFS_GROWFS_PATH)
+AC_SUBST(CRYPTSETUP_PATH)
AC_SUBST(BLKDEACTIVATE)
AC_SUBST(HAVE_LIBDL)
AC_SUBST(HAVE_REALTIME)
diff --git a/include/configure.h.in b/include/configure.h.in
index e0d971bbf..58da11a02 100644
--- a/include/configure.h.in
+++ b/include/configure.h.in
@@ -132,8 +132,13 @@
/* Define to 1 to include the LVM editline shell. */
#undef EDITLINE_SUPPORT
-/* Path to fsadm binary. */
+/* Paths to binaries. */
#undef FSADM_PATH
+#undef MOUNT_PATH
+#undef UMOUNT_PATH
+#undef E2FSCK_PATH
+#undef RESIZE2FS_PATH
+#undef XFS_GROWFS_PATH
/* Define to use GNU versioning in the shared library. */
#undef GNU_SYMVER
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 3ab5cb2f1..3380b28fb 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -40,6 +40,7 @@ SOURCES =\
device/dev-luks.c \
device/dev-dasd.c \
device/dev-lvm1-pool.c \
+ device/filesystem.c \
device/online.c \
device/parse_vpd.c \
display/display.c \
diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c
index 939eb4aeb..aa8e2c4a3 100644
--- a/lib/device/dev-type.c
+++ b/lib/device/dev-type.c
@@ -26,6 +26,11 @@
#ifdef BLKID_WIPING_SUPPORT
#include <blkid.h>
+/*
+ * FIXME: recent addition to blkid.h copied here.
+ * Remove this and require a recent libblkid version from configure.
+ */
+#define BLKID_SUBLKS_FSINFO (1 << 11) /* read and define fs properties from superblock */
#endif
#ifdef UDEV_SYNC_SUPPORT
@@ -838,6 +843,102 @@ int get_fs_block_size(const char *pathname, uint32_t *fs_block_size)
return 0;
}
}
+
+int get_fs_type(const char *pathname, char *fstype)
+{
+ char *str = NULL;
+
+ if ((str = blkid_get_tag_value(NULL, "TYPE", pathname))) {
+ strncpy(fstype, str, FSTYPE_MAX);
+ free(str);
+ log_debug("Found blkid TYPE %s on %s", str, pathname);
+ return 1;
+ } else {
+ log_debug("No blkid TYPE for fs on %s", pathname);
+ return 0;
+ }
+}
+
+int fs_get_blkid(const char *pathname, struct fs_info *fsi)
+{
+ blkid_probe probe = NULL;
+ const char *str;
+ size_t len;
+ uint64_t fslastblock = 0;
+ unsigned int fsblocksize = 0;
+ int no_block_size = 0, no_fslastblock = 0, no_fsblocksize = 0;
+ int rc;
+
+ if (!(probe = blkid_new_probe_from_filename(pathname))) {
+ log_error("Failed libblkid probe setup for %s", pathname);
+ return 0;
+ }
+
+ blkid_probe_enable_superblocks(probe, 1);
+ blkid_probe_set_superblocks_flags(probe,
+ BLKID_SUBLKS_LABEL | BLKID_SUBLKS_LABELRAW |
+ BLKID_SUBLKS_UUID | BLKID_SUBLKS_UUIDRAW |
+ BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE |
+ BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION |
+ BLKID_SUBLKS_MAGIC | BLKID_SUBLKS_FSINFO);
+ rc = blkid_do_safeprobe(probe);
+ if (rc < 0) {
+ log_error("Failed libblkid probe for %s", pathname);
+ blkid_free_probe(probe);
+ return 0;
+ } else if (rc == 1) {
+ /* no file system on the device */
+ log_print("No file system found on %s.", pathname);
+ fsi->nofs = 1;
+ blkid_free_probe(probe);
+ return 1;
+ }
+
+ if (!blkid_probe_lookup_value(probe, "TYPE", &str, &len) && len)
+ strncpy(fsi->fstype, str, sizeof(fsi->fstype)-1);
+ else {
+ /* any difference from blkid_do_safeprobe rc=1? */
+ log_print("No file system type on %s.", pathname);
+ fsi->nofs = 1;
+ blkid_free_probe(probe);
+ return 1;
+ }
+
+ if (!blkid_probe_lookup_value(probe, "BLOCK_SIZE", &str, &len) && len)
+ fsi->block_size_bytes = atoi(str);
+ else
+ no_block_size = 1;
+
+ if (!blkid_probe_lookup_value(probe, "FSLASTBLOCK", &str, &len) && len)
+ fslastblock = strtoull(str, NULL, 0);
+ else
+ no_fslastblock = 1;
+
+ if (!blkid_probe_lookup_value(probe, "FSBLOCKSIZE", &str, &len) && len)
+ fsblocksize = (unsigned int)atoi(str);
+ else
+ no_fsblocksize = 1;
+
+ blkid_free_probe(probe);
+
+ /* We don't expect to get this info for luks */
+ if (strcmp(fsi->fstype, "crypto_LUKS") && (no_block_size || no_fslastblock || no_fsblocksize)) {
+ log_print("Missing libblkid %s%s%sfor %s",
+ no_block_size ? "BLOCK_SIZE " : "",
+ no_fslastblock ? "FSLASTBLOCK " : "",
+ no_fsblocksize ? "FSBLOCKSIZE " : "",
+ pathname);
+ }
+
+ if (fslastblock && fsblocksize)
+ fsi->fs_last_byte = fslastblock * fsblocksize;
+
+ log_debug("libblkid TYPE %s BLOCK_SIZE %d FSLASTBLOCK %llu FSBLOCKSIZE %u fs_last_byte %llu",
+ fsi->fstype, fsi->block_size_bytes, (unsigned long long)fslastblock, fsblocksize,
+ (unsigned long long)fsi->fs_last_byte);
+ return 1;
+}
+
#else
int get_fs_block_size(const char *pathname, uint32_t *fs_block_size)
{
@@ -845,6 +946,16 @@ int get_fs_block_size(const char *pathname, uint32_t *fs_block_size)
*fs_block_size = 0;
return 0;
}
+int get_fs_type(const char *pathname, char *fstype)
+{
+ log_debug("Disabled blkid TYPE for fs.");
+ return 0;
+}
+int fs_get_blkid(const char *pathname, struct fs_info *fsi)
+{
+ log_debug("Disabled blkid for fs info.");
+ return 0;
+}
#endif
#ifdef BLKID_WIPING_SUPPORT
diff --git a/lib/device/dev-type.h b/lib/device/dev-type.h
index 17c997641..33157d577 100644
--- a/lib/device/dev-type.h
+++ b/lib/device/dev-type.h
@@ -18,6 +18,7 @@
#include "lib/device/device.h"
#include "lib/display/display.h"
#include "lib/label/label.h"
+#include "lib/device/filesystem.h"
#define NUMBER_OF_MAJORS 4096
@@ -102,6 +103,8 @@ int dev_is_nvme(struct dev_types *dt, struct device *dev);
int dev_is_lv(struct device *dev);
int get_fs_block_size(const char *pathname, uint32_t *fs_block_size);
+int get_fs_type(const char *pathname, char *fstype);
+int fs_get_blkid(const char *pathname, struct fs_info *fsi);
int dev_is_used_by_active_lv(struct cmd_context *cmd, struct device *dev, int *used_by_lv_count,
char **used_by_dm_name, char **used_by_vg_uuid, char **used_by_lv_uuid);
diff --git a/lib/device/filesystem.c b/lib/device/filesystem.c
new file mode 100644
index 000000000..81a71a30d
--- /dev/null
+++ b/lib/device/filesystem.c
@@ -0,0 +1,442 @@
+/*
+ * 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 Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser 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
+ */
+
+#include "base/memory/zalloc.h"
+#include "lib/misc/lib.h"
+#include "lib/commands/toolcontext.h"
+#include "lib/device/device.h"
+#include "lib/device/dev-type.h"
+#include "lib/misc/lvm-exec.h"
+
+#include <dirent.h>
+#include <mntent.h>
+#include <sys/ioctl.h>
+
+/* LUKS header is usually 2MB for LUKS1 and 16MB for LUKS2 */
+
+static uint32_t _get_luks_header_bytes(struct logical_volume *lv, char *lv_path, char *crypt_path)
+{
+ uint64_t lv_size = 0;
+ uint64_t crypt_size = 0;
+ int fd;
+
+ if ((fd = open(lv_path, O_RDONLY)) < 0)
+ goto_out;
+
+ if (ioctl(fd, BLKGETSIZE64, &lv_size) < 0) {
+ close(fd);
+ goto_out;
+ }
+ close(fd);
+
+ if ((fd = open(crypt_path, O_RDONLY)) < 0)
+ goto_out;
+
+ if (ioctl(fd, BLKGETSIZE64, &crypt_size) < 0) {
+ close(fd);
+ goto_out;
+ }
+ close(fd);
+
+ if (lv_size <= crypt_size)
+ goto_out;
+
+ return (uint32_t)(lv_size - crypt_size);
+out:
+ log_error("Failed to get LUKS header size for %s on %s.", crypt_path, lv_path);
+ return 0;
+}
+
+/*
+ * Set the path of the dm-crypt device, i.e. /dev/dm-N, that is using the LV.
+ */
+static int _get_crypt_path(dev_t lv_devt, char *lv_path, char *crypt_path)
+{
+ char holders_path[PATH_MAX];
+ char *holder_name;
+ DIR *dr;
+ struct stat st;
+ struct dirent *de;
+ int ret = 0;
+
+ if (dm_snprintf(holders_path, sizeof(holders_path), "%sdev/block/%d:%d/holders",
+ dm_sysfs_dir(), (int)MAJOR(lv_devt), (int)MINOR(lv_devt)) < 0)
+ return_0;
+
+ /* If the crypt dev is not active, there will be no LV holder. */
+ if (stat(holders_path, &st)) {
+ log_error("Missing %s for %s", crypt_path, lv_path);
+ return 0;
+ }
+
+ if (!(dr = opendir(holders_path))) {
+ log_error("Cannot open %s", holders_path);
+ return 0;
+ }
+
+ while ((de = readdir(dr))) {
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+ continue;
+
+ holder_name = de->d_name;
+
+ if (strncmp(holder_name, "dm", 2)) {
+ log_error("Unrecognized holder %s of %s", holder_name, lv_path);
+ ret = 0;
+ break;
+ }
+
+ /* We could read the holder's dm uuid to verify it's a crypt dev. */
+
+ if (dm_snprintf(crypt_path, PATH_MAX, "/dev/%s", holder_name) < 0) {
+ ret = 0;
+ stack;
+ break;
+ }
+ ret = 1;
+ break;
+ }
+ closedir(dr);
+ if (ret)
+ log_debug("Found holder %s of %s.", crypt_path, lv_path);
+ else
+ log_debug("No holder in %s", holders_path);
+ return ret;
+}
+
+int fs_get_info(struct cmd_context *cmd, struct logical_volume *lv,
+ struct fs_info *fsi, int include_mount)
+{
+ char lv_path[PATH_MAX];
+ char crypt_path[PATH_MAX];
+ struct stat st_lv;
+ struct stat st_crypt;
+ struct stat st_top;
+ struct stat stme;
+ struct fs_info info;
+ FILE *fme = NULL;
+ struct mntent *me;
+ int ret;
+
+ if (dm_snprintf(lv_path, PATH_MAX, "%s%s/%s", lv->vg->cmd->dev_dir,
+ lv->vg->name, lv->name) < 0) {
+ log_error("Couldn't create LV path for %s.", display_lvname(lv));
+ return 0;
+ }
+
+ if (stat(lv_path, &st_lv) < 0) {
+ log_error("Failed to get LV path %s", lv_path);
+ return 0;
+ }
+
+ memset(&info, 0, sizeof(info));
+
+ if (!fs_get_blkid(lv_path, &info)) {
+ log_error("No file system info from blkid for %s", display_lvname(lv));
+ return 0;
+ }
+
+ if (fsi->nofs)
+ return 1;
+
+ /*
+ * If there's a LUKS dm-crypt layer over the LV, then
+ * return fs info from that layer, setting needs_crypt
+ * to indicate a crypt layer between the fs and LV.
+ */
+ if (!strcmp(info.fstype, "crypto_LUKS")) {
+ if (!_get_crypt_path(st_lv.st_rdev, lv_path, crypt_path)) {
+ log_error("Cannot find active LUKS dm-crypt device using %s.",
+ display_lvname(lv));
+ return 0;
+ }
+
+ if (stat(crypt_path, &st_crypt) < 0) {
+ log_error("Failed to get crypt path %s", crypt_path);
+ return 0;
+ }
+
+ memset(&info, 0, sizeof(info));
+
+ log_print("File system found on crypt device %s on LV %s.",
+ crypt_path, display_lvname(lv));
+
+ if (!fs_get_blkid(crypt_path, &info)) {
+ log_error("No file system info from blkid for dm-crypt device %s on LV %s.",
+ crypt_path, display_lvname(lv));
+ return 0;
+ }
+ *fsi = info;
+ fsi->needs_crypt = 1;
+ fsi->crypt_devt = st_crypt.st_rdev;
+ memcpy(fsi->fs_dev_path, crypt_path, PATH_MAX);
+ st_top = st_crypt;
+
+ if (!(fsi->luks_header_bytes = _get_luks_header_bytes(lv, lv_path, crypt_path)))
+ return_0;
+ } else {
+ *fsi = info;
+ memcpy(fsi->fs_dev_path, lv_path, PATH_MAX);
+ st_top = st_lv;
+ }
+
+ if (!include_mount)
+ return 1;
+
+ if (!(fme = setmntent("/etc/mtab", "r")))
+ return_0;
+
+ ret = 1;
+
+ while ((me = getmntent(fme))) {
+ if (strcmp(me->mnt_type, fsi->fstype))
+ continue;
+ if (me->mnt_dir[0] != '/')
+ continue;
+ if (me->mnt_fsname[0] != '/')
+ continue;
+ if (stat(me->mnt_dir, &stme) < 0)
+ continue;
+ if (stme.st_dev != st_top.st_rdev)
+ continue;
+
+ log_debug("fs_get_info %s is mounted \"%s\"", fsi->fs_dev_path, me->mnt_dir);
+ fsi->mounted = 1;
+ strncpy(fsi->mount_dir, me->mnt_dir, PATH_MAX-1);
+ }
+ endmntent(fme);
+
+ fsi->unmounted = !fsi->mounted;
+ return ret;
+}
+
+#define FS_CMD_MAX_ARGS 6
+
+int fs_fsck_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)) {
+ log_error("fsck not supported for %s.", fsi->fstype);
+ return_0;
+ }
+
+ /*
+ * ext234: e2fsck -f -p path
+ * TODO: replace -p with -y based on yes_ARG, or other?
+ */
+
+ argv[0] = E2FSCK_PATH; /* defined by configure */
+ argv[++args] = "-f";
+ argv[++args] = "-p";
+ argv[++args] = fsi->fs_dev_path;
+ 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));
+ 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)
+{
+ char newsize_kb_str[16] = { 0 };
+ const char *argv[FS_CMD_MAX_ARGS + 4];
+ 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;
+
+ } else {
+ log_error("fs reduce not supported for %s.", fsi->fstype);
+ return_0;
+ }
+
+ log_print("Reducing file system %s on %s...", fsi->fstype, display_lvname(lv));
+
+ if (!exec_cmd(cmd, argv, &status, 1)) {
+ log_error("Failed to reduce %s file system on %s.", fsi->fstype, display_lvname(lv));
+ return 0;
+ }
+
+ 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;
+ }
+
+ log_print("Extending file system %s on %s...", fsi->fstype, display_lvname(lv));
+
+ if (!exec_cmd(cmd, argv, &status, 1)) {
+ log_error("Failed to extend %s file system on %s.", fsi->fstype, display_lvname(lv));
+ return 0;
+ }
+
+ 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;
+
+ 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));
+
+ if (!exec_cmd(cmd, argv, &status, 1)) {
+ log_error("Failed to mount file system on %s at %s.", display_lvname(lv), mountdir);
+ return 0;
+ }
+
+ log_print("Mounted %s at %s dir %s.", display_lvname(lv),
+ reuse_mount_dir ? "original" : "temporary", mountdir);
+ return 1;
+}
+
+int fs_unmount_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;
+
+ argv[0] = UMOUNT_PATH; /* defined by configure */
+ argv[++args] = fsi->fs_dev_path;
+ argv[++args] = NULL;
+
+ log_print("Unmounting %s.", display_lvname(lv));
+
+ if (!exec_cmd(cmd, argv, &status, 1)) {
+ log_error("Failed to unmount file system on %s.", display_lvname(lv));
+ return 0;
+ }
+
+ log_print("Unmounted %s.", display_lvname(lv));
+
+ 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;
+ }
+ 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;
+
+ 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);
+
+ 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);
+ 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);
+
+ return 1;
+}
+
diff --git a/lib/device/filesystem.h b/lib/device/filesystem.h
new file mode 100644
index 000000000..6be4cc8f9
--- /dev/null
+++ b/lib/device/filesystem.h
@@ -0,0 +1,54 @@
+/*
+ * 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 Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser 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
+ */
+
+#ifndef _FILESYSTEM_H
+#define _FILESYSTEM_H
+
+#define FSTYPE_MAX 16
+
+struct fs_info {
+ char fstype[FSTYPE_MAX];
+ char mount_dir[PATH_MAX];
+ char fs_dev_path[PATH_MAX]; /* usually lv dev, can be crypt dev */
+ unsigned int block_size_bytes; /* 512 or 4k */
+ uint64_t fs_last_byte; /* last byte on the device used by the fs */
+ uint32_t luks_header_bytes; /* size of luks header when needs_crypt=1 */
+ dev_t crypt_devt; /* dm-crypt device between the LV and FS */
+
+ unsigned nofs:1;
+ unsigned unmounted:1;
+ unsigned mounted:1;
+ unsigned temp_mount_dir:1;
+ /* for resizing */
+ unsigned needs_reduce:1;
+ unsigned needs_extend:1;
+ unsigned needs_fsck:1;
+ unsigned needs_unmount:1;
+ unsigned needs_mount:1;
+ unsigned needs_crypt:1;
+};
+
+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);
+
+#endif
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 22f8324e2..ace416aa2 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -31,6 +31,7 @@
#include "lib/locking/lvmlockd.h"
#include "lib/label/label.h"
#include "lib/misc/lvm-signal.h"
+#include "lib/device/filesystem.h"
#ifdef HAVE_BLKZEROOUT
#include <sys/ioctl.h>
@@ -4946,13 +4947,6 @@ static int _lv_reduce_confirmation(struct logical_volume *lv,
return 0;
}
- if (lv_is_vdo(lv) && !info.exists) {
- log_error("Logical volume %s must be activated "
- "before reducing device size.",
- display_lvname(lv));
- return 0;
- }
-
if (!info.exists)
return 1;
@@ -5933,7 +5927,7 @@ static void _setup_params_for_extend_metadata(struct logical_volume *lv,
lp->percent = PERCENT_NONE;
lp->segtype = mseg->segtype;
lp->mirrors = seg_is_mirrored(mseg) ? lv_mirror_count(lv) : 0;
- lp->resizefs = 0;
+ lp->fsopt[0] = '\0';
lp->stripes = lp->mirrors ? mseg->area_count / lp->mirrors : 0;
lp->stripe_size = mseg->stripe_size;
}
@@ -5974,6 +5968,627 @@ static int _lv_resize_check_used(struct logical_volume *lv)
return 1;
}
+/*
+ * --fs checksize: check fs size and allow the lv to reduce if the fs is not
+ * using the affected space, i.e. the fs does not need to be
+ * resized. fail the command without reducing the fs or lv if
+ * the fs is using the affected space.
+ *
+ * --fs resize_remount: resize the fs, mounting/unmounting the fs as needed,
+ * but avoiding mounting/unmounted when possible.
+ *
+ * --fs resize_keepmount: resize the fs without changing the current
+ * mount/unmount state. fail the command without reducing the
+ * fs or lv if the fs resize would require mounting or unmounting.
+ *
+ * --fs resize_unmount: resize the fs only while it's unmounted ("offline"),
+ * unmounting the fs if needed. fail the commandn without
+ * reducing the fs or lv if the fs resize would require having
+ * the fs mounted.
+ *
+ * --fs resize_fsadm: old method using fsadm script to do everything
+ *
+ * --fs resize: equivalent to resize_remount.
+ */
+static int _fs_reduce_allow(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvresize_params *lp, uint64_t newsize_bytes_lv,
+ uint64_t newsize_bytes_fs, struct fs_info *fsi)
+{
+ const char *fs_reduce_cmd = "";
+ const char *cmp_desc = "";
+ int equal = 0, smaller = 0, larger = 0;
+ int is_ext_fstype = 0;
+ int confirm_mount_change = 0;
+
+ /*
+ * Allow reducing the LV for other fs types if the fs is not using
+ * space that's being reduced.
+ */
+ if (!strcmp(fsi->fstype, "ext2") ||
+ !strcmp(fsi->fstype, "ext3") ||
+ !strcmp(fsi->fstype, "ext4") ||
+ !strcmp(fsi->fstype, "xfs")) {
+ log_debug("Found fs %s last_byte %llu newsize_bytes_fs %llu",
+ fsi->fstype,
+ (unsigned long long)fsi->fs_last_byte,
+ (unsigned long long)newsize_bytes_fs);
+ if (!strncmp(fsi->fstype, "ext", 3)) {
+ is_ext_fstype = 1;
+ fs_reduce_cmd = " resize2fs";
+ }
+ }
+
+ if (!fsi->mounted)
+ log_print("File system %s%s found on %s.",
+ fsi->fstype, fsi->needs_crypt ? "+crypto_LUKS" : "",
+ display_lvname(lv));
+ else
+ log_print("File system %s%s found on %s mounted at %s.",
+ fsi->fstype, fsi->needs_crypt ? "+crypto_LUKS" : "",
+ display_lvname(lv), fsi->mount_dir);
+
+ if (!fsi->fs_last_byte) {
+ log_error("File system size unknown: update libblkid for FSLASTBLOCK, or see --fs resize_fsadm.");
+ return 0;
+ }
+
+ if ((equal = (fsi->fs_last_byte == newsize_bytes_fs)))
+ cmp_desc = "equal to";
+ else if ((smaller = (fsi->fs_last_byte < newsize_bytes_fs)))
+ cmp_desc = "smaller than";
+ else if ((larger = (fsi->fs_last_byte > newsize_bytes_fs)))
+ cmp_desc = "larger than";
+
+ log_print("File system size (%s) is %s the requested size (%s).",
+ display_size(cmd, fsi->fs_last_byte/512), cmp_desc,
+ display_size(cmd, newsize_bytes_fs/512));
+
+ /*
+ * FS reduce is not needed, it's not using the affected space.
+ */
+ if (smaller || equal) {
+ log_print("File system reduce is not needed, skipping.");
+ fsi->needs_reduce = 0;
+ return 1;
+ }
+
+ /*
+ * FS reduce is required, but checksize does not allow it.
+ */
+ if (!strcmp(lp->fsopt, "checksize")) {
+ if (is_ext_fstype)
+ log_error("File system reduce is required (see resize2fs or --resizefs.)");
+ else
+ log_error("File system reduce is required and not supported (%s).", fsi->fstype);
+ return 0;
+ }
+
+ /*
+ * FS reduce required, ext* supports it, xfs does not.
+ */
+ if (is_ext_fstype) {
+ log_print("File system reduce is required using resize2fs.");
+ } else {
+ log_error("File system reduce is required and not supported (%s).", fsi->fstype);
+ return 0;
+ }
+
+ /*
+ * Set fstype-specific requirements for running fs resize command.
+ * ext2,3,4 require the fs to be unmounted to shrink with resize2fs,
+ * and they require e2fsck to be run first, unless resize2fs -f is used.
+ */
+ if (is_ext_fstype) {
+ /* it's traditional to run fsck before shrink */
+ if (!lp->nofsck)
+ fsi->needs_fsck = 1;
+
+ /* ext2,3,4 require fs to be unmounted to shrink */
+ if (fsi->mounted)
+ fsi->needs_unmount = 1;
+
+ fsi->needs_reduce = 1;
+ } else {
+ /*
+ * Shouldn't reach here since no other fs types get this far.
+ * A future fs supporting shrink may require the fs to be
+ * mounted or unmounted to run the fs shrink command.
+ * set fsi->needs_unmount or fs->needs_mount according to
+ * the fs-specific shrink command's requirement.
+ */
+ log_error("File system %s: fs reduce not implemented.", fsi->fstype);
+ return 0;
+ }
+
+ /*
+ * FS reduce may require mounting or unmounting, check the fsopt value
+ * from the user, and the current mount state to decide if fs resize
+ * can be done.
+ */
+ if (!strcmp(lp->fsopt, "resize_keepmount")) {
+ /* can't mount|unmount to run fs resize */
+ if (fsi->needs_mount) {
+ log_error("File system needs to be mounted to reduce fs (see resize_remount).");
+ return 0;
+ }
+ if (fsi->needs_unmount) {
+ log_error("File system needs to be unmounted to reduce fs (see resize_remount).");
+ return 0;
+ }
+ } else if (!strcmp(lp->fsopt, "resize_unmount")) {
+ /* we can unmount if needed to run fs resize */
+ if (fsi->needs_mount) {
+ log_error("File system needs to be mounted to reduce fs (see resize_remount).");
+ return 0;
+ }
+ } else if (!strcmp(lp->fsopt, "resize_remount")) {
+ /* we can mount|unmount as needed to run fs resize */
+ } else if (!strcmp(lp->fsopt, "resize")) {
+ /* equivalent to resize_remount, but confirm mount change */
+ if (fsi->needs_mount || fsi->needs_unmount)
+ confirm_mount_change = 1;
+ } else {
+ log_error("Unknown file system resize option: %s", lp->fsopt);
+ return 0;
+ }
+
+ /*
+ * If future file systems can be reduced while mounted, then suppress
+ * needs_fsck here if the fs is already mounted.
+ */
+
+ if (fsi->needs_unmount)
+ log_print("File system unmount is needed for reduce.");
+ if (fsi->needs_fsck)
+ log_print("File system fsck will be run before reduce.");
+ if (fsi->needs_mount)
+ log_print("File system mount is needed for reduce.");
+ if (fsi->needs_crypt)
+ log_print("cryptsetup resize is needed for reduce.");
+
+ /*
+ * Use a confirmation prompt because mount|unmount is needed, and
+ * the generic "resize" option was used (i.e. the user did not give
+ * specific direction about how to handle mounting|unmounting such as
+ * resize_unmount, resize_remount, resize_keepmount, so ask them.)
+ */
+ if (!lp->yes && confirm_mount_change) {
+ if (yes_no_prompt("Continue with %s file system reduce steps:%s%s%s%s%s? [y/n]:",
+ fsi->fstype,
+ fsi->needs_unmount ? " unmount," : "",
+ fsi->needs_fsck ? " fsck," : "",
+ fsi->needs_mount ? " mount," : "",
+ fsi->needs_crypt ? " cryptsetup," : "",
+ fsi->needs_reduce ? fs_reduce_cmd : "") == 'n') {
+ log_error("File system not reduced.");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int _fs_extend_allow(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvresize_params *lp, struct fs_info *fsi)
+{
+ const char *fs_extend_cmd = "";
+ int is_ext_fstype = 0;
+ int confirm_mount_change = 0;
+
+ if (!strcmp(fsi->fstype, "ext2") ||
+ !strcmp(fsi->fstype, "ext3") ||
+ !strcmp(fsi->fstype, "ext4") ||
+ !strcmp(fsi->fstype, "xfs")) {
+ log_debug("Found fs %s last_byte %llu",
+ fsi->fstype, (unsigned long long)fsi->fs_last_byte);
+ if (!strncmp(fsi->fstype, "ext", 3))
+ is_ext_fstype = 1;
+ } else {
+ log_error("File system extend is not supported (%s).", fsi->fstype);
+ return 0;
+ }
+
+ if (!fsi->mounted)
+ log_print("File system %s%s found on %s.",
+ fsi->fstype, fsi->needs_crypt ? "+crypto_LUKS" : "",
+ display_lvname(lv));
+ else
+ log_print("File system %s%s found on %s mounted at %s.",
+ fsi->fstype, fsi->needs_crypt ? "+crypto_LUKS" : "",
+ display_lvname(lv), fsi->mount_dir);
+
+ /*
+ * FS extend may require mounting or unmounting, check the fsopt value
+ * from the user, and the current mount state to decide if fs extend
+ * can be done.
+ */
+
+ if (is_ext_fstype) {
+ fs_extend_cmd = " resize2fs";
+
+ /*
+ * ext* can be extended while it's mounted or unmounted. If
+ * the fs is unmounted, it's traditional to run fsck before
+ * running the fs extend.
+ *
+ * resize_keepmount: don't change mount condition.
+ * if mounted: fs_extend
+ * if unmounted: fsck, fs_extend
+ *
+ * resize_unmount: extend offline, so unmount first if mounted.
+ * if mounted: unmount, fsck, fs_extend
+ * if unmounted: fsck, fs_extend
+ *
+ * resize_remount|resize: do any mount or unmount that's necessary,
+ * avoiding unnecessary mounting/unmounting.
+ * if mounted: fs_extend
+ * if unmounted: fsck, fs_extend
+ */
+ if (!strcmp(lp->fsopt, "resize_keepmount")) {
+ if (fsi->mounted)
+ fsi->needs_extend = 1;
+ else if (fsi->unmounted) {
+ fsi->needs_fsck = 1;
+ fsi->needs_extend = 1;
+ }
+ } else if (!strcmp(lp->fsopt, "resize_unmount")) {
+ if (fsi->mounted) {
+ fsi->needs_unmount = 1;
+ fsi->needs_fsck = 1;
+ fsi->needs_extend = 1;
+ } else if (fsi->unmounted) {
+ fsi->needs_fsck = 1;
+ fsi->needs_extend = 1;
+ }
+ } else if (!strcmp(lp->fsopt, "resize_remount") || !strcmp(lp->fsopt, "resize")) {
+ if (fsi->mounted)
+ fsi->needs_extend = 1;
+ else if (fsi->unmounted) {
+ fsi->needs_fsck = 1;
+ fsi->needs_extend = 1;
+ }
+ }
+
+ if (lp->nofsck)
+ fsi->needs_fsck = 0;
+
+ } else if (!strcmp(fsi->fstype, "xfs")) {
+ fs_extend_cmd = " xfs_growfs";
+
+ /*
+ * xfs must be mounted to extend.
+ *
+ * resize_keepmount: don't change mount condition.
+ * if mounted: fs_extend
+ * if unmounted: fail
+ *
+ * resize_unmount: extend offline, so unmount first if mounted.
+ * if mounted: fail
+ * if unmounted: fail
+ *
+ * resize_remount|resize: do any mount or unmount that's necessary,
+ * avoiding unnecessary mounting/unmounting.
+ * if mounted: fs_extend
+ * if unmounted: mount, fs_extend
+ */
+ if (!strcmp(lp->fsopt, "resize_keepmount")) {
+ if (fsi->mounted)
+ fsi->needs_extend = 1;
+ else if (fsi->unmounted) {
+ log_error("File system must be mounted to extend (see resize_remount).");
+ return 0;
+ }
+ } else if (!strcmp(lp->fsopt, "resize_unmount")) {
+ log_error("File system must be mounted to extend (see resize_remount).");
+ return 0;
+ } else if (!strcmp(lp->fsopt, "resize_remount") || !strcmp(lp->fsopt, "resize")) {
+ if (fsi->mounted)
+ fsi->needs_extend = 1;
+ else if (fsi->unmounted) {
+ fsi->needs_mount = 1;
+ fsi->needs_extend = 1;
+ }
+ }
+
+ } else {
+ /* shouldn't reach here */
+ log_error("File system type %s not handled.", fsi->fstype);
+ return 0;
+ }
+
+ /*
+ * Skip needs_fsck if the fs is mounted and we can extend the fs while
+ * it's mounted.
+ */
+ if (fsi->mounted && !fsi->needs_unmount && fsi->needs_fsck) {
+ log_print("File system fsck skipped for extending mounted fs.");
+ fsi->needs_fsck = 0;
+ }
+
+ if (fsi->needs_unmount)
+ log_print("File system unmount is needed for extend.");
+ if (fsi->needs_fsck)
+ log_print("File system fsck will be run before extend.");
+ if (fsi->needs_mount)
+ log_print("File system mount is needed for extend.");
+ if (fsi->needs_crypt)
+ log_print("cryptsetup resize is needed for extend.");
+
+ /*
+ * Use a confirmation prompt because mount|unmount is needed, and
+ * the generic "resize" option was used (i.e. the user did not give
+ * specific direction about how to handle mounting|unmounting such
+ * as resize_umount, resize_remount, resize_keepmount, so ask them.)
+ */
+ if (!strcmp(lp->fsopt, "resize") && (fsi->needs_mount || fsi->needs_unmount))
+ confirm_mount_change = 1;
+
+ if (!lp->yes && confirm_mount_change) {
+ if (yes_no_prompt("Continue with %s file system extend steps:%s%s%s%s%s? [y/n]:",
+ fsi->fstype,
+ fsi->needs_unmount ? " unmount," : "",
+ fsi->needs_fsck ? " fsck," : "",
+ fsi->needs_mount ? " mount," : "",
+ fsi->needs_crypt ? " cryptsetup," : "",
+ fsi->needs_extend ? fs_extend_cmd : "") == 'n') {
+ log_error("File system not extended.");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int _fs_reduce(struct cmd_context *cmd, struct logical_volume *lv,
+ struct lvresize_params *lp)
+{
+ struct fs_info fsinfo;
+ 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));
+ memset(&fsinfo2, 0, sizeof(fsinfo));
+
+ if (!fs_get_info(cmd, lv, &fsinfo, 1))
+ goto_out;
+
+ if (fsinfo.nofs) {
+ ret = 1;
+ goto_out;
+ }
+
+ /* 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 needs_crypt, then newsize_bytes passed to fs_reduce_command() and
+ * crypt_resize_command() needs to be decreased by the size of the luks
+ * header (LUKS1 usually 2MB, LUKS2 usually 16MB.)
+ */
+ if (fsinfo.needs_crypt) {
+ newsize_bytes_fs -= fsinfo.luks_header_bytes;
+ log_print("File system size %llub is adjusted for LUKS header size %ub.",
+ (unsigned long long)newsize_bytes_fs, fsinfo.luks_header_bytes);
+ }
+
+ /*
+ * Based on the --fs command option, the fs type, the last block used,
+ * and the mount state, determine if LV reduce is allowed. If not
+ * returns 0 and lvreduce should fail. If allowed, returns 1 and sets
+ * fsinfo.needs_* for any steps that are required to reduce the LV.
+ */
+ if (!_fs_reduce_allow(cmd, lv, lp, newsize_bytes_lv, newsize_bytes_fs, &fsinfo))
+ goto_out;
+
+ /*
+ * Uncommon special case in which the FS does not need to be shrunk,
+ * but the crypt dev over the LV should be shrunk to correspond with
+ * 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);
+ goto out;
+ }
+
+ /*
+ * fs reduce is not needed to reduce the LV.
+ */
+ if (!fsinfo.needs_reduce) {
+ ret = 1;
+ goto_out;
+ }
+
+ if (test_mode()) {
+ if (fsinfo.needs_unmount)
+ log_print("Skip unmount in test mode.");
+ if (fsinfo.needs_fsck)
+ log_print("Skip fsck in test mode.");
+ if (fsinfo.needs_mount)
+ log_print("Skip mount in test mode.");
+ if (fsinfo.needs_crypt)
+ log_print("Skip cryptsetup in test mode.");
+ log_print("Skip fs reduce in test mode.");
+ ret = 1;
+ goto out;
+ }
+
+ /*
+ * mounting, unmounting, fsck, and shrink command can all take a long
+ * time to run, and this lvm command should not block other lvm
+ * commands from running during that time, so release the vg lock
+ * around the long-running steps, and reacquire after.
+ */
+ 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))
+ 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;
+ goto out;
+ }
+
+ /*
+ * Check that the vg wasn't changed while it was unlocked.
+ * (can_use_one_scan: check just one mda in the vg for changes)
+ */
+ cmd->can_use_one_scan = 1;
+ if (scan_text_mismatch(cmd, lv->vg->name, NULL)) {
+ log_error("VG was changed during fs operations, cannot reduce LV.");
+ ret = 0;
+ goto out;
+ }
+
+ /*
+ * Re-check the fs last block which should now be less than the
+ * requested (reduced) LV size.
+ */
+ if (!fs_get_info(cmd, lv, &fsinfo2, 0))
+ goto_out;
+
+ if (fsinfo.fs_last_byte && (fsinfo2.fs_last_byte > newsize_bytes_fs)) {
+ log_error("File system last byte %llu is greater than new size %llu bytes.",
+ (unsigned long long)fsinfo2.fs_last_byte,
+ (unsigned long long)newsize_bytes_fs);
+ 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;
+}
+
+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;
+ int ret = 0;
+
+ memset(&fsinfo, 0, sizeof(fsinfo));
+
+ if (!fs_get_info(cmd, lv, &fsinfo, 1))
+ goto_out;
+
+ if (fsinfo.nofs) {
+ ret = 1;
+ goto_out;
+ }
+
+ /*
+ * Decide if fs should be extended based on the --fs option,
+ * the fs type and the mount state.
+ */
+ if (!_fs_extend_allow(cmd, lv, lp, &fsinfo))
+ goto_out;
+
+ /*
+ * fs extend is not needed
+ */
+ if (!fsinfo.needs_extend) {
+ ret = 1;
+ goto_out;
+ }
+
+ if (test_mode()) {
+ if (fsinfo.needs_unmount)
+ log_print("Skip unmount in test mode.");
+ if (fsinfo.needs_fsck)
+ log_print("Skip fsck in test mode.");
+ if (fsinfo.needs_mount)
+ log_print("Skip mount in test mode.");
+ if (fsinfo.needs_crypt)
+ log_print("Skip cryptsetup in test mode.");
+ log_print("Skip fs extend in test mode.");
+ ret = 1;
+ goto out;
+ }
+
+ /*
+ * mounting, unmounting and extend command can all take a long
+ * time to run, and this lvm command should not block other lvm
+ * commands from running during that time, so release the vg
+ * lock around the long-running steps.
+ */
+ 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))
+ 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;
+}
+
int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
struct lvresize_params *lp)
{
@@ -6019,26 +6634,6 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
}
/*
- * resizefs applies to the LV command arg, not to the top LV or lower
- * resizable LV.
- */
- if (lp->resizefs) {
- if (!lv_is_active(lv)) {
- log_error("Logical volume %s must be activated before resizing filesystem.",
- display_lvname(lv));
- return 0;
- }
- /* types of LVs that can hold a file system */
- if (!(lv_is_linear(lv) || lv_is_striped(lv) || lv_is_raid(lv) ||
- lv_is_mirror(lv) || lv_is_thin_volume(lv) || lv_is_vdo(lv) ||
- lv_is_cache(lv) || lv_is_writecache(lv))) {
- log_print_unless_silent("Ignoring --resizefs for LV type %s.",
- seg ? seg->segtype->name : "unknown");
- lp->resizefs = 0;
- }
- }
-
- /*
* Figure out which LVs are going to be extended, and set params
* to the requested extents/size for each. Some LVs are extended
* only by extending an underlying LV. Extending some top level
@@ -6197,10 +6792,6 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
if (!_lv_resize_check_type(lv_main, lp))
return_0;
-
- if (is_reduce && !main_size_matches && !lp->resizefs &&
- !_lv_reduce_confirmation(lv, lp))
- return_0;
}
/*
@@ -6265,46 +6856,105 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
* So active temporarily pool LV (with on disk metadata) then use
* suspend and resume and deactivate pool LV, instead of searching for
* an active thin volume.
+ *
+ * FIXME: why are thin pools activated where other LV types return
+ * error if inactive?
*/
if (lv_is_thin_pool(lv_top) && !lv_is_active(lv_top)) {
- if (!activation()) {
- log_error("Cannot resize %s without using device-mapper kernel driver.",
- display_lvname(lv_top));
- return_0;
+ if (!activation()) {
+ log_error("Cannot activate to resize %s without using device-mapper kernel driver.",
+ display_lvname(lv_top));
+ return 0;
}
if (!activate_lv(cmd, lv_top)) {
log_error("Failed to activate %s.", display_lvname(lv_top));
- return_0;
+ return 0;
}
activated = 1;
}
/*
+ * Disable fsopt checksize for lvextend.
+ */
+ if (is_extend && !strcmp(lp->fsopt, "checksize"))
+ lp->fsopt[0] = '\0';
+
+ /*
+ * Disable fsopt if LV type cannot hold a file system.
+ */
+ if (lp->fsopt[0] &&
+ !(lv_is_linear(lv) || lv_is_striped(lv) || lv_is_raid(lv) ||
+ lv_is_mirror(lv) || lv_is_thin_volume(lv) || lv_is_vdo(lv) ||
+ lv_is_cache(lv) || lv_is_writecache(lv))) {
+ log_print_unless_silent("Ignoring fs resizing options for LV type %s.",
+ seg ? seg->segtype->name : "unknown");
+ lp->fsopt[0] = '\0';
+ }
+
+ /*
+ * Any fs option requires the LV already be active.
+ * (not sure why the command doesn't activate)
+ */
+ if (lp->fsopt[0] && !lv_is_active(lv_top)) {
+ log_error("Logical volume %s must be active for file system %s.",
+ display_lvname(lv_top), lp->fsopt);
+ return 0;
+ }
+
+ /*
+ * Return an error without resizing the LV if the user requested
+ * a file system resize when no file system exists on the LV.
+ * (fs checksize does not require a fs to exist.)
+ */
+ if (lp->fsopt[0] && strcmp(lp->fsopt, "checksize") && lp->user_set_fs) {
+ char lv_path[PATH_MAX];
+ char fstype[FSTYPE_MAX];
+
+ if (dm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s", cmd->dev_dir,
+ lv_top->vg->name, lv_top->name) < 0) {
+ log_error("Couldn't create LV path for %s.", display_lvname(lv_top));
+ return 0;
+ }
+ if (!get_fs_type(lv_path, fstype)) {
+ log_error("File system not found for --resizefs or --fs options.");
+ return 0;
+ }
+ }
+
+ /*
+ * Warn and confirm if checksize has been disabled for reduce.
+ */
+ if (is_reduce && !lp->fsopt[0] && !_lv_reduce_confirmation(lv_top, lp))
+ return_0;
+
+ /*
* If the LV is locked due to being active, this lock call is a no-op.
* Otherwise, this acquires a transient lock on the lv (not PERSISTENT)
*/
if (!lockd_lv_resize(cmd, lv_top, "ex", 0, lp))
goto_out;
- /*
- * Check the file system, and shrink the fs before reducing lv.
- * TODO: libblkid fs type, fs last_block, mount state,
- * unlock vg, mount|unmount if needed, fork fs shrink,
- * lock vg, rescan devs, recheck fs type last_block.
- * (at end mount|unmount if needed to restore initial state.)
- */
- if (lp->resizefs && !lp->nofsck &&
+ /* Part of old approach to fs handling using fsadm. */
+ if (!strcmp(lp->fsopt, "resize_fsadm") && !lp->nofsck &&
!_fsadm_cmd(FSADM_CMD_CHECK, lv_top, 0, lp->yes, lp->force, &status)) {
if (status != FSADM_CHECK_FAILS_FOR_MOUNTED) {
log_error("Filesystem check failed.");
goto out;
}
- /* some filesystems support online resize */
}
- if (lp->resizefs && is_reduce &&
- !_fsadm_cmd(FSADM_CMD_RESIZE, lv_top, lp->extents, lp->yes, lp->force, NULL)) {
- log_error("Filesystem resize failed.");
- goto out;
+
+ if (is_reduce && lp->fsopt[0]) {
+ if (!strcmp(lp->fsopt, "resize_fsadm")) {
+ /* Old approach to fs handling using fsadm. */
+ if (!_fsadm_cmd(FSADM_CMD_RESIZE, lv_top, lp->extents, lp->yes, lp->force, NULL)) {
+ log_error("Filesystem resize failed.");
+ goto out;
+ }
+ } else {
+ /* New approach to fs handling using fs info. */
+ if (!_fs_reduce(cmd, lv_top, lp))
+ goto_out;
+ }
}
/*
@@ -6376,16 +7026,22 @@ int lv_resize(struct cmd_context *cmd, struct logical_volume *lv,
stack;
}
- /*
- * Extend the file system.
- * TODO: libblkid fs type, mount state,
- * unlock vg, mount|unmount if needed, fork fs grow,
- * mount|unmount if needed to restore initial state.
- */
- if (lp->resizefs && is_extend &&
- !_fsadm_cmd(FSADM_CMD_RESIZE, lv_top, lp->extents, lp->yes, lp->force, NULL)) {
- log_warn("Filesystem resize failed.");
- goto out;
+ if (is_extend && lp->fsopt[0]) {
+ if (!strcmp(lp->fsopt, "resize_fsadm")) {
+ /* Old approach to fs handling using fsadm. */
+ if (!_fsadm_cmd(FSADM_CMD_RESIZE, lv_top, lp->extents, lp->yes, lp->force, NULL)) {
+ log_error("File system extend error.");
+ lp->extend_fs_error = 1;
+ goto out;
+ }
+ } else {
+ /* New approach to fs handling using fs info. */
+ if (!_fs_extend(cmd, lv_top, lp)) {
+ log_error("File system extend error.");
+ lp->extend_fs_error = 1;
+ goto out;
+ }
+ }
}
ret = 1;
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 4fb6ad93a..21dd39646 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -674,8 +674,9 @@ struct lvresize_params {
int force;
int nosync;
int nofsck;
- int resizefs;
int use_policies;
+ int user_set_fs;
+ char fsopt[32]; /* set by --resizefs|--fs, empty for --fs ignore */
const struct segment_type *segtype;
unsigned mirrors;
@@ -695,6 +696,7 @@ struct lvresize_params {
int approx_alloc;
int extents_are_pes; /* Is 'extents' counting PEs or LEs? */
int size_changed; /* Was there actually a size change */
+ int extend_fs_error; /* FS extend error after LV extend success */
const char *lockopt;
char *lockd_lv_refresh_path; /* set during resize to use for refresh at the end */
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 95f25eef8..30b2c1779 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -4533,7 +4533,7 @@ void vg_write_commit_bad_mdas(struct cmd_context *cmd, struct volume_group *vg)
* reread metadata.
*/
-static bool _scan_text_mismatch(struct cmd_context *cmd, const char *vgname, const char *vgid)
+bool scan_text_mismatch(struct cmd_context *cmd, const char *vgname, const char *vgid)
{
DM_LIST_INIT(mda_list);
struct mda_list *mdal, *safe;
@@ -4706,7 +4706,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
* probably unnecessary; all commands could likely just check a single mda.
*/
- if (lvmcache_scan_mismatch(cmd, vgname, vgid) || _scan_text_mismatch(cmd, vgname, vgid)) {
+ if (lvmcache_scan_mismatch(cmd, vgname, vgid) || scan_text_mismatch(cmd, vgname, vgid)) {
log_debug_metadata("Rescanning devices for %s %s", vgname, writing ? "rw" : "");
if (writing)
lvmcache_label_rescan_vg_rw(cmd, vgname, vgid);
diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h
index 6c39ff845..5cebe9508 100644
--- a/lib/metadata/metadata.h
+++ b/lib/metadata/metadata.h
@@ -538,5 +538,7 @@ void set_pv_devices(struct format_instance *fid, struct volume_group *vg);
int get_visible_lvs_using_pv(struct cmd_context *cmd, struct volume_group *vg, struct device *dev,
struct dm_list *lvs_list);
+bool scan_text_mismatch(struct cmd_context *cmd, const char *vgname, const char *vgid);
+
#endif
diff --git a/scripts/fsadm.sh b/scripts/fsadm.sh
index 9ae422f55..d22c7d0a6 100755
--- a/scripts/fsadm.sh
+++ b/scripts/fsadm.sh
@@ -164,7 +164,7 @@ cleanup() {
export _FSADM_YES _FSADM_EXTOFF
unset FSADM_RUNNING
test -n "${LVM_BINARY-}" && PATH=$_SAVEPATH
- dry exec "$LVM" lvresize $VERB $FORCE -r -L"${NEWSIZE_ORIG}b" "$VOLUME_ORIG"
+ dry exec "$LVM" lvresize $VERB $FORCE $YES --fs resize_fsadm -L"${NEWSIZE_ORIG}b" "$VOLUME_ORIG"
fi
# error exit status for break
diff --git a/test/shell/fsadm-crypt-fsresize.sh b/test/shell/fsadm-crypt-fsresize.sh
new file mode 100644
index 000000000..009350800
--- /dev/null
+++ b/test/shell/fsadm-crypt-fsresize.sh
@@ -0,0 +1,612 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2017 Red Hat, Inc. All rights reserved.
+#
+# 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
+
+test_description='Exercise fsadm filesystem resize on crypt devices'
+
+SKIP_WITH_LVMPOLLD=1
+
+# FIXME: cannot use brd (ramdisk) - lsblk is NOT listing it
+# so lsblk usage should be replaced
+export LVM_TEST_PREFER_BRD=0
+
+. lib/inittest
+
+aux prepare_vg 1 300
+
+# set to "skip" to avoid testing given fs and test warning result
+# i.e. check_reiserfs=skip
+check_ext2=
+check_ext3=
+check_xfs=
+check_reiserfs=
+check_cryptsetup=
+DROP_SYMLINK=
+
+CRYPT_NAME="$PREFIX-tcrypt"
+CRYPT_DEV="$DM_DEV_DIR/mapper/$CRYPT_NAME"
+
+CRYPT_NAME2="$PREFIX-tcrypt2"
+CRYPT_DEV2="$DM_DEV_DIR/mapper/$CRYPT_NAME2"
+
+CRYPT_NAME_PLAIN="$PREFIX-tcryptp"
+CRYPT_DEV_PLAIN="$DM_DEV_DIR/mapper/$CRYPT_NAME_PLAIN"
+
+FORMAT_PARAMS="-i1"
+PWD1="93R4P4pIqAH8"
+PWD2="mymJeD8ivEhE"
+PWD3="ocMakf3fAcQO"
+SKIP_DETACHED=
+
+if which cryptsetup ; then
+ # use older format luks1 - otherwise the test would need to pass password everywhere...
+ case $(cryptsetup --version) in
+ "cryptsetup 2"*) FORMAT_PARAMS="$FORMAT_PARAMS --type luks1" ;;
+ esac
+else
+ check_cryptsetup=${check_cryptsetup:-cryptsetup}
+fi
+
+which mkfs.ext2 || check_ext2=${check_ext2:-mkfs.ext2}
+which mkfs.ext3 || check_ext3=${check_ext3:-mkfs.ext3}
+which fsck.ext3 || check_ext3=${check_ext3:-fsck.ext3}
+which mkfs.xfs || check_xfs=${check_xfs:-mkfs.xfs}
+which xfs_check || {
+ which xfs_repair || check_xfs=${check_xfs:-xfs_repair}
+}
+grep xfs /proc/filesystems || check_xfs=${check_xfs:-no_xfs}
+
+which mkfs.reiserfs || check_reiserfs=${check_reiserfs:-mkfs.reiserfs}
+which reiserfsck || check_reiserfs=${check_reiserfs:-reiserfsck}
+modprobe reiserfs || true
+grep reiserfs /proc/filesystems || check_reiserfs=${check_reiserfs:-no_reiserfs}
+
+vg_lv=$vg/$lv1
+vg_lv2=$vg/${lv1}bar
+vg_lv3=$vg/${lv1}plain
+dev_vg_lv="$DM_DEV_DIR/$vg_lv"
+dev_vg_lv2="$DM_DEV_DIR/$vg_lv2"
+dev_vg_lv3="$DM_DEV_DIR/$vg_lv3"
+mount_dir="mnt"
+
+test ! -d "$mount_dir" && mkdir "$mount_dir"
+
+crypt_close() {
+ aux udev_wait
+ cryptsetup remove "$1"
+ if [ "$?" -eq 0 -a -n "$DROP_SYMLINK" ]; then
+ rm -f "$DM_DEV_DIR/mapper/$1"
+ fi
+}
+
+cleanup_mounted_and_teardown()
+{
+ umount "$mount_dir" || true
+ crypt_close $CRYPT_NAME > /dev/null 2>&1 || true
+ crypt_close $CRYPT_NAME2 > /dev/null 2>&1 || true
+ crypt_close $CRYPT_NAME_PLAIN > /dev/null 2>&1 || true
+ aux teardown
+}
+
+fscheck_ext3()
+{
+ fsck.ext3 -p -F -f "$1"
+}
+
+fscheck_xfs()
+{
+ if which xfs_repair ; then
+ xfs_repair -n "$1"
+ else
+ xfs_check "$1"
+ fi
+}
+
+fscheck_reiserfs()
+{
+ reiserfsck --check -p -f "$1" </dev/null
+}
+
+check_missing()
+{
+ local t
+ eval "t=\$check_$1"
+ test -z "$t" && return 0
+ test "$t" = skip && return 1
+ echo "WARNING: fsadm test skipped $1 tests, $t tool is missing."
+ # trick to get test listed with warning
+ # should false;
+ return 1
+}
+
+get_crypt_kname() {
+ lsblk -r -n -o KNAME,NAME | grep "$1" | cut -d ' ' -f 1
+}
+
+
+# $1 device
+# $2 pass
+crypt_format() {
+ echo "$2" | cryptsetup luksFormat $FORMAT_PARAMS "$1"
+}
+
+
+# $1 device
+# $2 pass
+# $3 name
+crypt_open() {
+ local kname=
+ echo "$2" | cryptsetup luksOpen "$1" "$3"
+ test -L "$DM_DEV_DIR/mapper/$3" || {
+ kname=$(get_crypt_kname $3)
+ ln -s "/dev/$kname" "$DM_DEV_DIR/mapper/$3"
+ DROP_SYMLINK=1
+ }
+}
+
+# $1 data device
+# $2 pass
+# $3 name
+# $4 header
+crypt_open_detached() {
+ local kname=
+ echo "$2" | cryptsetup luksOpen --header "$4" "$1" "$3" || return $?
+ test -L "$DM_DEV_DIR/mapper/$3" || {
+ kname=$(get_crypt_kname $3)
+ ln -s "/dev/$kname" "$DM_DEV_DIR/mapper/$3"
+ DROP_SYMLINK=1
+ }
+}
+
+# $1 device
+# $2 pass
+# $3 name
+crypt_open_plain() {
+ local kname=
+ echo "$2" | cryptsetup create "$3" "$1"
+ test -L "$DM_DEV_DIR/mapper/$3" || {
+ kname=$(get_crypt_kname $3)
+ ln -s "/dev/$kname" "$DM_DEV_DIR/mapper/$3"
+ DROP_SYMLINK=1
+ }
+}
+
+# $1 device
+# $2 type
+create_crypt_device()
+{
+ crypt_format "$dev_vg_lv" $PWD1
+ crypt_open "$dev_vg_lv" $PWD1 "$CRYPT_NAME"
+
+ crypt_format "$dev_vg_lv2" $PWD2
+
+ if crypt_open_detached "$dev_vg_lv3" "$PWD2" "$PREFIX-test" "$dev_vg_lv2"; then
+ crypt_close "$PREFIX-test"
+ else
+ SKIP_DETACHED=1
+ fi
+}
+
+which lsblk > /dev/null || skip
+check_missing cryptsetup || skip
+
+vgchange -s 128k
+lvcreate -n $lv1 -L25M $vg
+lvcreate -n ${lv1}bar -L35M $vg
+lvcreate -n ${lv1}plain -L35M $vg
+create_crypt_device
+trap 'cleanup_mounted_and_teardown' EXIT
+
+
+# $1 LVM backend (vg/lv name)
+# $2 LVM backend device (/dev/vg/lv)
+# $3 active dm-crypt device (/dev/mapper/some_name )
+test_ext2_resize() {
+ mkfs.ext2 -b4096 -j "$3"
+
+ fsadm --lvresize resize $1 30M
+ # Fails - not enough space for 4M fs
+ not fsadm -y --lvresize resize "$2" 4M
+ lvresize -L+10M --fs resize $1
+ lvreduce -L10M --fs resize $1
+
+ fscheck_ext3 "$3"
+ mount "$3" "$mount_dir"
+ not fsadm -y --lvresize resize $1 4M
+ echo n | not lvresize -L4M --fs resize -n $1
+ lvresize -L+20M --fs resize -n $1
+ umount "$mount_dir"
+ fscheck_ext3 "$3"
+}
+
+test_ext2_small_shrink() {
+ mkfs.ext2 "$3"
+
+ lvresize -L-1 --fs resize $1
+ lvresize -L-1 --fs resize $1
+
+ fscheck_ext3 "$3"
+}
+
+test_ext3_resize() {
+ mkfs.ext3 -b4096 -j "$3"
+
+ fsadm --lvresize resize $1 30M
+ # Fails - not enough space for 4M fs
+ not fsadm -y --lvresize resize "$2" 4M
+ lvresize -L+10M --fs resize $1
+ lvreduce -L10M --fs resize $1
+
+ fscheck_ext3 "$3"
+ mount "$3" "$mount_dir"
+ lvresize -L+10M --fs resize $1
+
+ not fsadm -y --lvresize resize $1 4M
+ echo n | not lvresize -L4M --fs resize -n $1
+ lvresize -L+20M --fs resize -n $1
+ lvresize -L-10M --fs resize -y $1
+ umount "$mount_dir"
+}
+
+test_ext3_small_shrink() {
+ mkfs.ext3 "$3"
+
+ lvresize -L-1 --fs resize $1
+ lvresize -L-1 --fs resize $1
+
+ fscheck_ext3 "$3"
+}
+
+test_xfs_resize() {
+ mkfs.xfs -l internal,size=1536b -f "$3"
+
+ fsadm --lvresize resize $1 30M
+ # Fails - not enough space for 4M fs
+ lvresize -L+10M -y --fs resize $1
+ not lvreduce -L10M --fs resize $1
+
+ fscheck_xfs "$3"
+ mount "$3" "$mount_dir"
+ lvresize -L+10M -y --fs resize -n $1
+ umount "$mount_dir"
+ fscheck_xfs "$3"
+}
+
+test_xfs_small_shrink() {
+ mkfs.xfs -l internal,size=1536b -f "$3"
+
+ not lvresize -L-1 --fs resize $1
+ fscheck_xfs "$3"
+}
+
+test_reiserfs_resize() {
+ mkfs.reiserfs -s 513 -f "$3"
+
+ fsadm --lvresize resize $1 30M
+ lvresize -L+10M --fs resize $1
+ fsadm --lvresize -y resize $1 10M
+
+ fscheck_reiserfs "$3"
+ mount "$3" "$mount_dir"
+
+ fsadm -y --lvresize resize $1 30M
+ umount "$mount_dir"
+ fscheck_reiserfs "$3"
+}
+
+test_reiserfs_small_shrink() {
+ mkfs.reiserfs -s 513 -f "$3"
+
+ lvresize -y -L-1 --fs resize $1
+ lvresize -y -L-1 --fs resize $1
+
+ fscheck_reiserfs "$3"
+}
+
+# $1 LVM backend (vg/lv name)
+# $2 LVM backend device (/dev/vg/lv)
+# $3 active dm-crypt device (/dev/mapper/some_name )
+# $4 active dm-crypt name ( some_name )
+test_ext2_inactive() {
+ crypt_open "$2" $PWD2 "$4"
+ mkfs.ext2 -b4096 -j "$3"
+ crypt_close "$4"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+
+ crypt_open "$2" $PWD2 "$4"
+ fscheck_ext3 "$3"
+ crypt_close "$4"
+}
+
+test_ext3_inactive() {
+ crypt_open "$2" $PWD2 "$4"
+ mkfs.ext3 -b4096 -j "$3"
+ crypt_close "$4"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+
+ crypt_open "$2" $PWD2 "$4"
+ fscheck_ext3 "$3"
+ crypt_close "$4"
+}
+
+test_xfs_inactive() {
+ crypt_open "$2" $PWD2 "$4"
+ mkfs.xfs -l internal,size=1536b -f "$3"
+ crypt_close "$4"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+
+ crypt_open "$2" $PWD2 "$4"
+ fscheck_xfs "$3"
+ crypt_close "$4"
+}
+
+test_reiserfs_inactive() {
+ crypt_open "$2" $PWD2 "$4"
+ mkfs.reiserfs -s 513 -f "$3"
+ crypt_close "$4"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+
+ crypt_open "$2" $PWD2 "$4"
+ fscheck_reiserfs "$3"
+ crypt_close "$4"
+}
+
+# $1 LVM backend (vg/lv name)
+# $2 LVM backend device (/dev/vg/lv)
+# $3 active dm-crypt device (/dev/mapper/some_name )
+# $4 active dm-crypt name ( some_name )
+test_ext2_plain() {
+ mkfs.ext2 -b4096 -j "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ fscheck_ext3 "$3"
+
+ fsadm --cryptresize resize $3 30M
+ fsadm --cryptresize resize $3 35M
+ fscheck_ext3 "$3"
+
+ mount "$3" "$mount_dir"
+ not fsadm -y --cryptresize resize $3 4M
+ umount "$mount_dir"
+ fscheck_ext3 "$3"
+
+ crypt_close "$4"
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ crypt_open_plain "$2" $PWD3 "$4"
+ fscheck_ext3 "$3"
+}
+
+test_ext3_plain() {
+ mkfs.ext3 -b4096 -j "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ fscheck_ext3 "$3"
+
+ fsadm --cryptresize resize $3 30M
+ fsadm --cryptresize resize $3 35M
+ fscheck_ext3 "$3"
+
+ mount "$3" "$mount_dir"
+ not fsadm -y --cryptresize resize $3 4M
+ umount "$mount_dir"
+ fscheck_ext3 "$3"
+
+ crypt_close "$4"
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ crypt_open_plain "$2" $PWD3 "$4"
+ fscheck_ext3 "$3"
+}
+
+test_xfs_plain() {
+ mkfs.xfs -l internal,size=1536b -f "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ fscheck_xfs "$3"
+
+ lvresize -f -L+10M $1
+ fsadm --cryptresize resize $3 40M
+ # no shrink support in xfs
+ not fsadm --cryptresize resize $3 35M
+ fscheck_xfs "$3"
+
+ crypt_close "$4"
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ crypt_open_plain "$2" $PWD3 "$4"
+ fscheck_xfs "$3"
+
+ lvresize -f -L35M $1
+}
+
+test_reiserfs_plain() {
+ mkfs.reiserfs -s 513 -f "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L-10M --fs resize $1
+ fscheck_reiserfs "$3"
+
+ fsadm -y --cryptresize resize $3 30M
+ fsadm -y --cryptresize resize $3 35M
+ fscheck_reiserfs "$3"
+
+ crypt_close "$4"
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ crypt_open_plain "$2" $PWD3 "$4"
+ fscheck_reiserfs "$3"
+}
+
+# $1 LVM header backend (vg/lv name)
+# $2 LVM hedaer backend device (/dev/vg/lv)
+# $3 active dm-crypt device (/dev/mapper/some_name )
+# $4 active dm-crypt name ( some_name )a
+test_ext2_detached() {
+ mkfs.ext2 -b4096 -j "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ fscheck_ext3 "$3"
+}
+
+test_ext3_detached() {
+ mkfs.ext3 -b4096 -j "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ fscheck_ext3 "$3"
+}
+
+test_xfs_detached() {
+ mkfs.xfs -l internal,size=1536b -f "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+
+ fscheck_xfs "$3"
+}
+
+test_reiserfs_detached() {
+ mkfs.reiserfs -s 513 -f "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+
+ fscheck_reiserfs "$3"
+}
+
+if check_missing ext2; then
+ test_ext2_resize "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ test_ext2_inactive "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+
+ crypt_open_plain "$dev_vg_lv3" $PWD3 "$CRYPT_NAME_PLAIN"
+ test_ext2_plain "$vg_lv3" "$dev_vg_lv3" "$CRYPT_DEV_PLAIN" "$CRYPT_NAME_PLAIN"
+ crypt_close "$CRYPT_NAME_PLAIN"
+
+ lvresize --fs ignore -y -L100M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+ test_ext2_small_shrink "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ if [ -z "$SKIP_DETACHED" ]; then
+ crypt_open_detached "$dev_vg_lv3" $PWD2 "$CRYPT_NAME2" "$dev_vg_lv2"
+ test_ext2_detached "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+ crypt_close "$CRYPT_NAME2"
+ fi
+fi
+
+if check_missing ext3; then
+ test_ext3_resize "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ test_ext3_inactive "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+
+ crypt_open_plain "$dev_vg_lv3" $PWD3 "$CRYPT_NAME_PLAIN"
+ test_ext3_plain "$vg_lv3" "$dev_vg_lv3" "$CRYPT_DEV_PLAIN" "$CRYPT_NAME_PLAIN"
+ crypt_close "$CRYPT_NAME_PLAIN"
+
+ lvresize --fs ignore -y -L100M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+ test_ext3_small_shrink "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ if [ -z "$SKIP_DETACHED" ]; then
+ crypt_open_detached "$dev_vg_lv3" $PWD2 "$CRYPT_NAME2" "$dev_vg_lv2"
+ test_ext3_detached "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+ crypt_close "$CRYPT_NAME2"
+ fi
+fi
+
+if check_missing xfs; then
+ test_xfs_resize "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ test_xfs_inactive "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+
+ crypt_open_plain "$dev_vg_lv3" $PWD3 "$CRYPT_NAME_PLAIN"
+ test_xfs_plain "$vg_lv3" "$dev_vg_lv3" "$CRYPT_DEV_PLAIN" "$CRYPT_NAME_PLAIN"
+ crypt_close "$CRYPT_NAME_PLAIN"
+
+ lvresize --fs ignore -y -L100M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+ test_xfs_small_shrink "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ if [ -z "$SKIP_DETACHED" ]; then
+ crypt_open_detached "$dev_vg_lv3" $PWD2 "$CRYPT_NAME2" "$dev_vg_lv2"
+ test_xfs_detached "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+ crypt_close "$CRYPT_NAME2"
+ fi
+fi
+
+if check_missing reiserfs; then
+ test_reiserfs_resize "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ test_reiserfs_inactive "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+
+ crypt_open_plain "$dev_vg_lv3" $PWD3 "$CRYPT_NAME_PLAIN"
+ test_reiserfs_plain "$vg_lv3" "$dev_vg_lv3" "$CRYPT_DEV_PLAIN" "$CRYPT_NAME_PLAIN"
+ crypt_close "$CRYPT_NAME_PLAIN"
+
+ lvresize --fs ignore -y -L100M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+ test_reiserfs_small_shrink "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ if [ -z "$SKIP_DETACHED" ]; then
+ crypt_open_detached "$dev_vg_lv3" $PWD2 "$CRYPT_NAME2" "$dev_vg_lv2"
+ test_reiserfs_detached "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+ crypt_close "$CRYPT_NAME2"
+ fi
+fi
+
+crypt_close "$CRYPT_NAME"
+
+vgremove -ff $vg
diff --git a/test/shell/fsadm-crypt.sh b/test/shell/fsadm-crypt.sh
index 2004db957..aefa722f1 100644
--- a/test/shell/fsadm-crypt.sh
+++ b/test/shell/fsadm-crypt.sh
@@ -215,14 +215,14 @@ test_ext2_resize() {
fsadm --lvresize resize $1 30M
# Fails - not enough space for 4M fs
not fsadm -y --lvresize resize "$2" 4M
- lvresize -L+10M -r $1
- lvreduce -L10M -r $1
+ lvresize -L+10M --fs resize_fsadm $1
+ lvreduce -L10M --fs resize_fsadm $1
fscheck_ext3 "$3"
mount "$3" "$mount_dir"
not fsadm -y --lvresize resize $1 4M
- echo n | not lvresize -L4M -r -n $1
- lvresize -L+20M -r -n $1
+ echo n | not lvresize -L4M --fs resize_fsadm -n $1
+ lvresize -L+20M --fs resize_fsadm -n $1
umount "$mount_dir"
fscheck_ext3 "$3"
}
@@ -230,8 +230,8 @@ test_ext2_resize() {
test_ext2_small_shrink() {
mkfs.ext2 "$3"
- lvresize -L-1 -r $1
- lvresize -L-1 -r $1
+ lvresize -L-1 --fs resize_fsadm $1
+ lvresize -L-1 --fs resize_fsadm $1
fscheck_ext3 "$3"
}
@@ -242,25 +242,25 @@ test_ext3_resize() {
fsadm --lvresize resize $1 30M
# Fails - not enough space for 4M fs
not fsadm -y --lvresize resize "$2" 4M
- lvresize -L+10M -r $1
- lvreduce -L10M -r $1
+ lvresize -L+10M --fs resize_fsadm $1
+ lvreduce -L10M --fs resize_fsadm $1
fscheck_ext3 "$3"
mount "$3" "$mount_dir"
- lvresize -L+10M -r $1
+ lvresize -L+10M --fs resize_fsadm $1
not fsadm -y --lvresize resize $1 4M
- echo n | not lvresize -L4M -r -n $1
- lvresize -L+20M -r -n $1
- lvresize -L-10M -r -y $1
+ echo n | not lvresize -L4M --fs resize_fsadm -n $1
+ lvresize -L+20M --fs resize_fsadm -n $1
+ lvresize -L-10M --fs resize_fsadm -y $1
umount "$mount_dir"
}
test_ext3_small_shrink() {
mkfs.ext3 "$3"
- lvresize -L-1 -r $1
- lvresize -L-1 -r $1
+ lvresize -L-1 --fs resize_fsadm $1
+ lvresize -L-1 --fs resize_fsadm $1
fscheck_ext3 "$3"
}
@@ -270,12 +270,12 @@ test_xfs_resize() {
fsadm --lvresize resize $1 30M
# Fails - not enough space for 4M fs
- lvresize -L+10M -r $1
- not lvreduce -L10M -r $1
+ lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
fscheck_xfs "$3"
mount "$3" "$mount_dir"
- lvresize -L+10M -r -n $1
+ lvresize -L+10M --fs resize_fsadm -n $1
umount "$mount_dir"
fscheck_xfs "$3"
}
@@ -283,7 +283,7 @@ test_xfs_resize() {
test_xfs_small_shrink() {
mkfs.xfs -l internal,size=1536b -f "$3"
- not lvresize -L-1 -r $1
+ not lvresize -L-1 --fs resize_fsadm $1
fscheck_xfs "$3"
}
@@ -291,7 +291,7 @@ test_reiserfs_resize() {
mkfs.reiserfs -s 513 -f "$3"
fsadm --lvresize resize $1 30M
- lvresize -L+10M -r $1
+ lvresize -L+10M --fs resize_fsadm $1
fsadm --lvresize -y resize $1 10M
fscheck_reiserfs "$3"
@@ -305,8 +305,8 @@ test_reiserfs_resize() {
test_reiserfs_small_shrink() {
mkfs.reiserfs -s 513 -f "$3"
- lvresize -y -L-1 -r $1
- lvresize -y -L-1 -r $1
+ lvresize -y -L-1 --fs resize_fsadm $1
+ lvresize -y -L-1 --fs resize_fsadm $1
fscheck_reiserfs "$3"
}
@@ -321,8 +321,8 @@ test_ext2_inactive() {
crypt_close "$4"
not fsadm --lvresize resize $1 30M
- not lvresize -L+10M -r $1
- not lvreduce -L10M -r $1
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
crypt_open "$2" $PWD2 "$4"
fscheck_ext3 "$3"
@@ -335,8 +335,8 @@ test_ext3_inactive() {
crypt_close "$4"
not fsadm --lvresize resize $1 30M
- not lvresize -L+10M -r $1
- not lvreduce -L10M -r $1
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
crypt_open "$2" $PWD2 "$4"
fscheck_ext3 "$3"
@@ -349,8 +349,8 @@ test_xfs_inactive() {
crypt_close "$4"
not fsadm --lvresize resize $1 30M
- not lvresize -L+10M -r $1
- not lvreduce -L10M -r $1
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
crypt_open "$2" $PWD2 "$4"
fscheck_xfs "$3"
@@ -363,8 +363,8 @@ test_reiserfs_inactive() {
crypt_close "$4"
not fsadm --lvresize resize $1 30M
- not lvresize -L+10M -r $1
- not lvreduce -L10M -r $1
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
crypt_open "$2" $PWD2 "$4"
fscheck_reiserfs "$3"
@@ -379,8 +379,8 @@ test_ext2_plain() {
mkfs.ext2 -b4096 -j "$3"
not fsadm --lvresize resize $1 30M
- not lvresize -L+10M -r $1
- not lvreduce -L10M -r $1
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
fscheck_ext3 "$3"
fsadm --cryptresize resize $3 30M
@@ -394,8 +394,8 @@ test_ext2_plain() {
crypt_close "$4"
not fsadm --lvresize resize $1 30M
- not lvresize -L+10M -r $1
- not lvreduce -L10M -r $1
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
crypt_open_plain "$2" $PWD3 "$4"
fscheck_ext3 "$3"
}
@@ -404,8 +404,8 @@ test_ext3_plain() {
mkfs.ext3 -b4096 -j "$3"
not fsadm --lvresize resize $1 30M
- not lvresize -L+10M -r $1
- not lvreduce -L10M -r $1
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
fscheck_ext3 "$3"
fsadm --cryptresize resize $3 30M
@@ -419,8 +419,8 @@ test_ext3_plain() {
crypt_close "$4"
not fsadm --lvresize resize $1 30M
- not lvresize -L+10M -r $1
- not lvreduce -L10M -r $1
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
crypt_open_plain "$2" $PWD3 "$4"
fscheck_ext3 "$3"
}
@@ -429,8 +429,8 @@ test_xfs_plain() {
mkfs.xfs -l internal,size=1536b -f "$3"
not fsadm --lvresize resize $1 30M
- not lvresize -L+10M -r $1
- not lvreduce -L10M -r $1
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
fscheck_xfs "$3"
lvresize -f -L+10M $1
@@ -441,8 +441,8 @@ test_xfs_plain() {
crypt_close "$4"
not fsadm --lvresize resize $1 30M
- not lvresize -L+10M -r $1
- not lvreduce -L10M -r $1
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
crypt_open_plain "$2" $PWD3 "$4"
fscheck_xfs "$3"
@@ -453,8 +453,8 @@ test_reiserfs_plain() {
mkfs.reiserfs -s 513 -f "$3"
not fsadm --lvresize resize $1 30M
- not lvresize -L+10M -r $1
- not lvreduce -L-10M -r $1
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L-10M --fs resize_fsadm $1
fscheck_reiserfs "$3"
fsadm -y --cryptresize resize $3 30M
@@ -463,8 +463,8 @@ test_reiserfs_plain() {
crypt_close "$4"
not fsadm --lvresize resize $1 30M
- not lvresize -L+10M -r $1
- not lvreduce -L10M -r $1
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
crypt_open_plain "$2" $PWD3 "$4"
fscheck_reiserfs "$3"
}
@@ -477,8 +477,8 @@ test_ext2_detached() {
mkfs.ext2 -b4096 -j "$3"
not fsadm --lvresize resize $1 30M
- not lvresize -L+10M -r $1
- not lvreduce -L10M -r $1
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
fscheck_ext3 "$3"
}
@@ -486,8 +486,8 @@ test_ext3_detached() {
mkfs.ext3 -b4096 -j "$3"
not fsadm --lvresize resize $1 30M
- not lvresize -L+10M -r $1
- not lvreduce -L10M -r $1
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
fscheck_ext3 "$3"
}
@@ -495,8 +495,8 @@ test_xfs_detached() {
mkfs.xfs -l internal,size=1536b -f "$3"
not fsadm --lvresize resize $1 30M
- not lvresize -L+10M -r $1
- not lvreduce -L10M -r $1
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
fscheck_xfs "$3"
}
@@ -505,15 +505,15 @@ test_reiserfs_detached() {
mkfs.reiserfs -s 513 -f "$3"
not fsadm --lvresize resize $1 30M
- not lvresize -L+10M -r $1
- not lvreduce -L10M -r $1
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
fscheck_reiserfs "$3"
}
if check_missing ext2; then
test_ext2_resize "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
- lvresize -f -L25M $vg_lv
+ lvresize --fs ignore -y -L25M $vg_lv
cryptsetup resize $CRYPT_NAME
test_ext2_inactive "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
@@ -522,10 +522,10 @@ if check_missing ext2; then
test_ext2_plain "$vg_lv3" "$dev_vg_lv3" "$CRYPT_DEV_PLAIN" "$CRYPT_NAME_PLAIN"
crypt_close "$CRYPT_NAME_PLAIN"
- lvresize -f -L100M $vg_lv
+ lvresize --fs ignore -y -L100M $vg_lv
cryptsetup resize $CRYPT_NAME
test_ext2_small_shrink "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
- lvresize -f -L25M $vg_lv
+ lvresize --fs ignore -y -L25M $vg_lv
cryptsetup resize $CRYPT_NAME
if [ -z "$SKIP_DETACHED" ]; then
@@ -537,7 +537,7 @@ fi
if check_missing ext3; then
test_ext3_resize "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
- lvresize -f -L25M $vg_lv
+ lvresize --fs ignore -y -L25M $vg_lv
cryptsetup resize $CRYPT_NAME
test_ext3_inactive "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
@@ -546,10 +546,10 @@ if check_missing ext3; then
test_ext3_plain "$vg_lv3" "$dev_vg_lv3" "$CRYPT_DEV_PLAIN" "$CRYPT_NAME_PLAIN"
crypt_close "$CRYPT_NAME_PLAIN"
- lvresize -f -L100M $vg_lv
+ lvresize --fs ignore -y -L100M $vg_lv
cryptsetup resize $CRYPT_NAME
test_ext3_small_shrink "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
- lvresize -f -L25M $vg_lv
+ lvresize --fs ignore -y -L25M $vg_lv
cryptsetup resize $CRYPT_NAME
if [ -z "$SKIP_DETACHED" ]; then
@@ -561,7 +561,7 @@ fi
if check_missing xfs; then
test_xfs_resize "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
- lvresize -f -L25M $vg_lv
+ lvresize --fs ignore -y -L25M $vg_lv
cryptsetup resize $CRYPT_NAME
test_xfs_inactive "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
@@ -570,10 +570,10 @@ if check_missing xfs; then
test_xfs_plain "$vg_lv3" "$dev_vg_lv3" "$CRYPT_DEV_PLAIN" "$CRYPT_NAME_PLAIN"
crypt_close "$CRYPT_NAME_PLAIN"
- lvresize -f -L100M $vg_lv
+ lvresize --fs ignore -y -L100M $vg_lv
cryptsetup resize $CRYPT_NAME
test_xfs_small_shrink "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
- lvresize -f -L25M $vg_lv
+ lvresize --fs ignore -y -L25M $vg_lv
cryptsetup resize $CRYPT_NAME
if [ -z "$SKIP_DETACHED" ]; then
@@ -585,7 +585,7 @@ fi
if check_missing reiserfs; then
test_reiserfs_resize "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
- lvresize -f -L25M $vg_lv
+ lvresize --fs ignore -y -L25M $vg_lv
cryptsetup resize $CRYPT_NAME
test_reiserfs_inactive "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
@@ -594,10 +594,10 @@ if check_missing reiserfs; then
test_reiserfs_plain "$vg_lv3" "$dev_vg_lv3" "$CRYPT_DEV_PLAIN" "$CRYPT_NAME_PLAIN"
crypt_close "$CRYPT_NAME_PLAIN"
- lvresize -f -L100M $vg_lv
+ lvresize --fs ignore -y -L100M $vg_lv
cryptsetup resize $CRYPT_NAME
test_reiserfs_small_shrink "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
- lvresize -f -L25M $vg_lv
+ lvresize --fs ignore -y -L25M $vg_lv
cryptsetup resize $CRYPT_NAME
if [ -z "$SKIP_DETACHED" ]; then
diff --git a/test/shell/fsadm.sh b/test/shell/fsadm.sh
index c5b3774c2..a7b3cdf2f 100644
--- a/test/shell/fsadm.sh
+++ b/test/shell/fsadm.sh
@@ -113,18 +113,18 @@ if check_missing ext2; then
fsadm --lvresize resize $vg_lv 30M
# Fails - not enough space for 4M fs
not fsadm -y --lvresize resize "$dev_vg_lv" 4M
- lvresize -L+10M -r $vg_lv
- lvreduce -L10M -r $vg_lv
+ lvresize -L+10M --fs resize_fsadm $vg_lv
+ lvreduce -L10M --fs resize_fsadm $vg_lv
fscheck_ext3
mount "$dev_vg_lv" "$mount_dir"
not fsadm -y --lvresize resize $vg_lv 4M
- echo n | not lvresize -L4M -r -n $vg_lv
- lvresize -L+20M -r -n $vg_lv
+ echo n | not lvresize -L4M --fs resize_fsadm -n $vg_lv
+ lvresize -L+20M --fs resize_fsadm -n $vg_lv
umount "$mount_dir"
fscheck_ext3
- lvresize -f -L20M $vg_lv
+ lvresize --fs ignore -y -L20M $vg_lv
if which debugfs ; then
mkfs.ext2 -b4096 -j "$dev_vg_lv"
@@ -145,7 +145,7 @@ if check_missing ext2; then
mount "$dev_vg_lv" "$mount_dir"
fsadm -v -y --lvresize resize $vg_lv 10M
- lvresize -L+10M -y -r -n $vg_lv
+ lvresize -L+10M -y --fs resize_fsadm -n $vg_lv
umount "$mount_dir" 2>/dev/null || true
fscheck_ext3
fi
@@ -158,24 +158,24 @@ if check_missing ext3; then
fsadm --lvresize resize $vg_lv 30M
# Fails - not enough space for 4M fs
not fsadm -y --lvresize resize "$dev_vg_lv" 4M
- lvresize -L+10M -r $vg_lv
- lvreduce -L10M -r $vg_lv
+ lvresize -L+10M --fs resize_fsadm $vg_lv
+ lvreduce -L10M --fs resize_fsadm $vg_lv
fscheck_ext3
mount "$dev_vg_lv" "$mount_dir"
- lvresize -L+10M -r $vg_lv
+ lvresize -L+10M --fs resize_fsadm $vg_lv
mount "$dev_vg_lv2" "$mount_space_dir"
fsadm --lvresize -e -y resize $vg_lv2 25M
not fsadm -y --lvresize resize $vg_lv 4M
echo n | not lvresize -L4M -r -n $vg_lv
- lvresize -L+20M -r -n $vg_lv
- lvresize -L-10M -r -y $vg_lv
+ lvresize -L+20M --fs resize_fsadm -n $vg_lv
+ lvresize -L-10M --fs resize_fsadm -y $vg_lv
umount "$mount_dir"
umount "$mount_space_dir"
fscheck_ext3
- lvresize -f -L20M $vg_lv
+ lvresize --fs ignore -y -L20M $vg_lv
fi
if check_missing xfs; then
@@ -183,23 +183,23 @@ if check_missing xfs; then
fsadm --lvresize resize $vg_lv 30M
# Fails - not enough space for 4M fs
- lvresize -L+10M -r $vg_lv
- not lvreduce -L10M -r $vg_lv
+ lvresize -L+10M --fs resize_fsadm $vg_lv
+ not lvreduce -L10M --fs resize_fsadm $vg_lv
fscheck_xfs
mount "$dev_vg_lv" "$mount_dir"
- lvresize -L+10M -r -n $vg_lv
+ lvresize -L+10M --fs resize_fsadm -n $vg_lv
umount "$mount_dir"
fscheck_xfs
- lvresize -f -L20M $vg_lv
+ lvresize --fs ignore -y -L20M $vg_lv
fi
if check_missing reiserfs; then
mkfs.reiserfs -s 513 -f "$dev_vg_lv"
fsadm --lvresize resize $vg_lv 30M
- lvresize -L+10M -r $vg_lv
+ lvresize -L+10M --fs resize_fsadm $vg_lv
fsadm --lvresize -y resize $vg_lv 10M
fscheck_reiserfs
@@ -209,7 +209,7 @@ if check_missing reiserfs; then
umount "$mount_dir"
fscheck_reiserfs
- lvresize -f -L20M $vg_lv
+ lvresize --fs ignore -y -L20M $vg_lv
fi
vgremove -ff $vg
diff --git a/test/shell/hints.sh b/test/shell/hints.sh
index 506c005dd..68e61153d 100644
--- a/test/shell/hints.sh
+++ b/test/shell/hints.sh
@@ -264,8 +264,8 @@ lvcreate -l1 -n $lv2 $vg1
lvcreate -l1 -an -n $lv3 $vg1
lvchange -an $vg1
lvremove $vg1/$lv3
-lvresize -l+1 $vg1/$lv2
-lvresize -l-1 $vg1/$lv2
+lvresize --fs ignore -l+1 $vg1/$lv2
+lvresize --fs ignore -l-1 $vg1/$lv2
lvdisplay
pvdisplay
vgdisplay
diff --git a/test/shell/lvresize-fs.sh b/test/shell/lvresize-fs.sh
new file mode 100644
index 000000000..8a0be0cec
--- /dev/null
+++ b/test/shell/lvresize-fs.sh
@@ -0,0 +1,1120 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2007-2016 Red Hat, Inc. All rights reserved.
+#
+# 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
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 3 256
+
+# Test combinations of the following:
+# lvreduce / lvextend
+# no fs / ext4 / xfs
+# each --fs opt / no --fs opt / --resizefs
+# active / inactive
+# mounted / unmounted
+# fs size less than, equal to or greater than reduced lv size
+
+mount_dir="mnt"
+mkdir -p "$mount_dir"
+
+
+#
+# lvextend, no fs
+#
+
+# lvextend, no fs, active, no --fs
+lvcreate -n $lv -L 256M $vg
+aux wipefs_a "$DM_DEV_DIR/$vg/$lv"
+lvextend -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, no fs, inactive, no --fs
+lvcreate -n $lv -L 256M $vg
+aux wipefs_a "$DM_DEV_DIR/$vg/$lv"
+lvchange -an $vg/$lv
+lvextend -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+lvremove $vg/$lv
+
+# lvextend, no fs, active, --fs resize fails with no fs found
+lvcreate -n $lv -L 256M $vg
+aux wipefs_a "$DM_DEV_DIR/$vg/$lv"
+not lvextend -L+200M --fs resize $vg/$lv
+check lv_field $vg/$lv lv_size "256.00m"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, no fs, inactive, --fs resize error requires active lv
+lvcreate -n $lv -L 256M $vg
+aux wipefs_a "$DM_DEV_DIR/$vg/$lv"
+lvchange -an $vg/$lv
+not lvextend -L+200M --fs resize $vg/$lv
+check lv_field $vg/$lv lv_size "256.00m"
+lvremove $vg/$lv
+
+#
+# lvextend, ext4
+#
+
+# lvextend, ext4, active, mounted, no --fs setting is same as --fs ignore
+lvcreate -n $lv -L 256M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+lvextend -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+# with no --fs used, the fs size should be the same
+df --output=size "$mount_dir" |tee df2
+diff df1 df2
+resize2fs "$DM_DEV_DIR/$vg/$lv"
+df --output=size "$mount_dir" |tee df3
+not diff df2 df3
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, ext4, inactive, --fs ignore
+lvcreate -n $lv -L 256M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+lvchange -an $vg/$lv
+lvextend --fs ignore -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+lvremove $vg/$lv
+
+# lvextend, ext4, active, mounted, --fs ignore
+lvcreate -n $lv -L 256M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+lvextend --fs ignore -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, ext4, active, mounted, --fs resize
+lvcreate -n $lv -L 256M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+lvextend --fs resize -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, ext4, active, mounted, --resizefs (same as --fs resize)
+lvcreate -n $lv -L 256M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+lvextend --resizefs -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, ext4, active, mounted, --fs resize_remount (same as --fs resize)
+lvcreate -n $lv -L 256M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+lvextend --fs resize_remount -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, ext4, active, mounted, --fs resize_unmount
+lvcreate -n $lv -L 256M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+lvextend --fs resize_unmount -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+# resize_unmount leaves fs unmounted
+df -a | tee dfa
+not grep "$mount_dir" dfa
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, ext4, active, mounted, --fs resize_keepmount
+lvcreate -n $lv -L 256M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+lvextend --fs resize_keepmount -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, ext4, active, mounted, --fs resize_fsadm
+lvcreate -n $lv -L 256M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+lvextend --fs resize_fsadm -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, ext4, active, unmounted, --fs resize_keepmount
+lvcreate -n $lv -L 256M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvextend --fs resize_keepmount -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, ext4, active, unmounted, --fs resize
+lvcreate -n $lv -L 256M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvextend --fs resize -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, ext4, active, unmounted, --fs resize_fsadm
+lvcreate -n $lv -L 256M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvextend --fs resize_fsadm -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+
+#
+# lvextend, xfs
+#
+
+# lvextend, xfs, active, mounted, no --fs setting is same as --fs ignore
+lvcreate -n $lv -L 256M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+lvextend -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+# with no --fs used, the fs size should be the same
+df --output=size "$mount_dir" |tee df2
+diff df1 df2
+xfs_growfs "$DM_DEV_DIR/$vg/$lv"
+df --output=size "$mount_dir" |tee df3
+not diff df2 df3
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, xfs, inactive, --fs ignore
+lvcreate -n $lv -L 256M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+lvchange -an $vg/$lv
+lvextend --fs ignore -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+lvremove $vg/$lv
+
+# lvextend, xfs, active, mounted, --fs ignore
+lvcreate -n $lv -L 256M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+lvextend --fs ignore -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, xfs, active, mounted, --fs resize
+lvcreate -n $lv -L 256M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+lvextend --fs resize -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, xfs, active, mounted, --resizefs (same as --fs resize)
+lvcreate -n $lv -L 256M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+lvextend --resizefs -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, xfs, active, mounted, --fs resize_remount (same as --fs resize)
+lvcreate -n $lv -L 256M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+lvextend --fs resize_remount -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, xfs, active, mounted, --fs resize_unmount
+lvcreate -n $lv -L 256M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+# xfs_growfs requires the fs to be mounted, so extending the lv is
+# succeeds, then the xfs extend fails because it cannot be done unmounted
+not lvextend --fs resize_unmount -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df -a | tee dfa
+grep "$mount_dir" dfa
+df --output=size "$mount_dir" |tee df2
+# fs not extended so fs size not changed
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, xfs, active, mounted, --fs resize_keepmount
+lvcreate -n $lv -L 256M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+lvextend --fs resize_keepmount -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, xfs, active, mounted, --fs resize_fsadm
+lvcreate -n $lv -L 256M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+lvextend --fs resize_fsadm -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, xfs, active, unmounted, --fs resize_keepmount
+lvcreate -n $lv -L 256M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+# xfs_growfs requires the fs to be mounted to grow, so resize_keepmount
+# with an unmounted fs fails
+not lvextend --fs resize_keepmount -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs not extended so fs size not changed
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, xfs, active, unmounted, --fs resize
+lvcreate -n $lv -L 256M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+# --yes needed because mount changes are required and plain "resize"
+# fsopt did not specify if the user wants to change mount state
+lvextend --yes --fs resize -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvextend, xfs, active, unmounted, --fs resize_fsadm
+lvcreate -n $lv -L 256M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvextend --fs resize_fsadm -L+200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=200 conv=fdatasync
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+
+#
+# lvreduce, no fs
+#
+
+# lvreduce, no fs, active, no --fs setting is same as --fs checksize
+lvcreate -n $lv -L 456M $vg
+aux wipefs_a "$DM_DEV_DIR/$vg/$lv"
+lvreduce -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "256.00m"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, no fs, inactive, no --fs setting is same as --fs checksize
+lvcreate -n $lv -L 456M $vg
+aux wipefs_a "$DM_DEV_DIR/$vg/$lv"
+lvchange -an $vg/$lv
+# lv must be active to do checksize, which is the default with no --fs setting
+not lvreduce -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, no fs, active, --fs resize requires fs to be found
+lvcreate -n $lv -L 456M $vg
+aux wipefs_a "$DM_DEV_DIR/$vg/$lv"
+not lvreduce -L-200M --fs resize $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, no fs, inactive, --fs ignore
+lvcreate -n $lv -L 456M $vg
+aux wipefs_a "$DM_DEV_DIR/$vg/$lv"
+lvchange -an $vg/$lv
+lvreduce -L-200M --fs ignore $vg/$lv
+check lv_field $vg/$lv lv_size "256.00m"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+
+#
+# lvreduce, ext4, no --fs setting and the equivalent --fs checksize
+# i.e. fs is not resized
+#
+
+# lvreduce, ext4, active, mounted, no --fs setting is same as --fs checksize
+# fs smaller than the reduced size
+lvcreate -n $lv -L 200M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+lvextend -L+256M $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=128 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+# fs is 200M, reduced size is 216M, so no fs reduce is needed
+# todo: check that resize2fs was not run?
+lvreduce -L216M $vg/$lv
+check lv_field $vg/$lv lv_size "216.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, mounted, no --fs setting is same as --fs checksize
+# fs equal to the reduced size
+lvcreate -n $lv -L 200M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+lvextend -L+256M $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=128 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+# fs is 200M, reduced size is 200M, so no fs reduce is needed
+# todo: check that resize2fs was not run?
+lvreduce -L200M $vg/$lv
+check lv_field $vg/$lv lv_size "200.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, mounted, no --fs setting is same as --fs checksize
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=100 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+# lvreduce fails because fs needs to be reduced and checksize does not resize
+not lvreduce -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, mounted, no --fs setting is same as --fs checksize
+# fs larger than the reduced size, fs is using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=300 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+# lvreduce fails because fs needs to be reduced and checksize does not resize
+not lvreduce -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# repeat lvreduce tests with unmounted instead of mounted fs
+
+# lvreduce, ext4, active, unmounted, no --fs setting is same as --fs checksize
+# fs smaller than the reduced size
+lvcreate -n $lv -L 200M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+lvextend -L+256M $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=128 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+# 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"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, unmounted, no --fs setting is same as --fs checksize
+# fs equal to the reduced size
+lvcreate -n $lv -L 200M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+lvextend -L+256M $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=128 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+# 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"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, unmounted, no --fs setting is same as --fs checksize
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=100 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+# lvreduce fails because fs needs to be reduced and checksize does not resize
+not lvreduce -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, unmounted, no --fs setting is same as --fs checksize
+# fs larger than the reduced size, fs is using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=300 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+# lvreduce fails because fs needs to be reduced and checksize does not resize
+not lvreduce -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# repeat a couple prev lvreduce that had no --fs setting,
+# now using --fs checksize to verify it's the same as using no --fs set
+
+# lvreduce, ext4, active, mounted, --fs checksize (same as no --fs set)
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=100 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+# lvreduce fails because fs needs to be reduced and checksize does not resize
+not lvreduce --fs checksize -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, unmounted, --fs checksize (same as no --fs set)
+# fs smaller than the reduced size
+lvcreate -n $lv -L 200M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+lvextend -L+256M $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=128 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+# fs is 200M, reduced size is 216M, so no fs reduce is needed
+lvreduce --fs checksize -L216M $vg/$lv
+check lv_field $vg/$lv lv_size "216.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce with inactive and no --fs setting fails because
+# default behavior is fs checksize which requires active lv
+
+# lvreduce, ext4, inactive, no --fs setting same as --fs checksize
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=100 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+lvchange -an $vg/$lv
+# lvreduce fails because default is --fs checksize which requires active lv
+not lvreduce -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+lvremove $vg/$lv
+
+#
+# lvreduce, ext4, --fs resize*
+#
+
+# lvreduce, ext4, active, mounted, --fs resize
+# fs smaller than the reduced size
+lvcreate -n $lv -L 200M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+lvextend -L+256M $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=128 conv=fdatasync
+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"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, mounted, --fs resize
+# fs equal to the reduced size
+lvcreate -n $lv -L 200M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+lvextend -L+256M $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=128 conv=fdatasync
+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"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, mounted, --fs resize
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=100 conv=fdatasync
+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"
+df --output=size "$mount_dir" |tee df2
+# fs size is changed
+not diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, mounted, --fs resize
+# fs larger than the reduced size, fs is using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=100 conv=fdatasync
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=300 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+# lvreduce runs resize2fs to shrink the fs but resize2fs fails
+# the fs is not remounted after resize2fs fails because the
+# resize failure might leave the fs in an unknown state
+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"
+df --output=size "$mount_dir" |tee df2
+# fs size is unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# repeat with unmounted instead of mounted
+
+# lvreduce, ext4, active, unmounted, --fs resize
+# fs smaller than the reduced size
+lvcreate -n $lv -L 200M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+lvextend -L+256M $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=128 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+# 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"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, unmounted, --fs resize
+# fs equal to the reduced size
+lvcreate -n $lv -L 200M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+lvextend -L+256M $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=128 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+# 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"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, unmounted, --fs resize
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=100 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+# lvreduce runs resize2fs to shrink the fs
+lvreduce --fs resize -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "256.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size is changed
+not diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, unmounted, --fs resize
+# fs larger than the reduced size, fs is using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=100 conv=fdatasync
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=300 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+# lvreduce runs resize2fs to shrink the fs but resize2fs fails
+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"
+df --output=size "$mount_dir" |tee df2
+# fs size is unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# repeat resizes that shrink the fs, replacing --fs resize with
+# --fs resize_keepmount | resize_unmount | resize_fsadm
+# while mounted and unmounted
+
+# lvreduce, ext4, active, mounted, --fs resize_keepmount
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=100 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+# lvreduce needs to unmount to run resize2fs but keepmount doesn't let it
+not lvreduce --fs resize_keepmount -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size is unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, unmounted, --fs resize_keepmount
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=100 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+# lvreduce runs resize2fs to shrink the fs
+lvreduce --fs resize_keepmount -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "256.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size is changed
+not diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, mounted, --fs resize_unmount
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=100 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+# lvreduce runs resize2fs to shrink the fs
+# resize_unmount leaves the fs unmounted
+lvreduce --fs resize_unmount -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "256.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size is changed
+not diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, unmounted, --fs resize_unmount
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=100 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+# lvreduce runs resize2fs to shrink the fs
+lvreduce --fs resize_unmount -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "256.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size is changed
+not diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, mounted, --fs resize_fsadm
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=100 conv=fdatasync
+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"
+df --output=size "$mount_dir" |tee df2
+# fs size is changed
+not diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, ext4, active, unmounted, --fs resize_fsadm
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=100 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+# lvreduce runs resize2fs to shrink the fs
+lvreduce --fs resize_fsadm -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "256.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size is changed
+not diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+#
+# lvreduce, xfs (xfs does not support shrinking)
+#
+
+# lvreduce, xfs, active, mounted, no --fs setting is same as --fs checksize
+# fs smaller than the reduced size
+lvcreate -n $lv -L 200M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+lvextend -L+256M $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=128 conv=fdatasync
+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"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, xfs, active, mounted, no --fs setting is same as --fs checksize
+# fs equal to the reduced size
+lvcreate -n $lv -L 200M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+lvextend -L+256M $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=128 conv=fdatasync
+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"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, xfs, active, mounted, no --fs setting is same as --fs checksize
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=100 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+# lvreduce fails because fs needs to be reduced
+not lvreduce -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, xfs, active, unmounted, no --fs setting is same as --fs checksize
+# fs smaller than the reduced size
+lvcreate -n $lv -L 200M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+lvextend -L+256M $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=128 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+# 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"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, xfs, active, mounted, --fs resize
+# fs smaller than the reduced size
+lvcreate -n $lv -L 200M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+lvextend -L+256M $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=128 conv=fdatasync
+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"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, xfs, active, mounted, --fs resize
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=100 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+# lvreduce fails because xfs cannot shrink
+not lvreduce --yes --fs resize -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+# lvreduce, xfs, active, unmounted, --fs resize*
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 456M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=100 conv=fdatasync
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+# lvreduce fails because xfs cannot shrink
+not lvreduce --yes --fs resize -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+not lvreduce --yes --fs resize_remount -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+not lvreduce --yes --fs resize_keepmount -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+not lvreduce --yes --fs resize_unmount -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+not lvreduce --yes --fs resize_fsadm -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+not lvreduce --yes --resizefs -L-200M $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+vgremove -ff $vg
diff --git a/test/shell/lvresize-full.sh b/test/shell/lvresize-full.sh
index 1ad9f32b1..fe39f45df 100644
--- a/test/shell/lvresize-full.sh
+++ b/test/shell/lvresize-full.sh
@@ -69,7 +69,10 @@ grep -v "20000 blocks" out
# Also check it fails when the user 'resize' volume without
# resizing fs and then retries with '-r'.
-lvreduce -f -l50%VG $vg/$lv1
-fail lvresize -r -f -l50%VG $vg/$lv1
+# The first lvreduce intentionally ignores the fs and intentionally
+# corrupts the fs so that the second lvresize will fail when it runs
+# fsck.
+lvreduce -f --fs ignore -l50%VG $vg/$lv1
+fail lvresize -r -f -l20%VG $vg/$lv1
lvremove -ff $vg
diff --git a/test/shell/lvresize-mirror.sh b/test/shell/lvresize-mirror.sh
index 61e4491bd..ee23f7f24 100644
--- a/test/shell/lvresize-mirror.sh
+++ b/test/shell/lvresize-mirror.sh
@@ -29,7 +29,7 @@ for deactivate in true false; do
check mirror_images_contiguous $vg $lv1
# reduce 2-way mirror
- lvreduce -f -l-2 $vg/$lv1
+ lvreduce -f --fs ignore -l-2 $vg/$lv1
check mirror $vg $lv1 "$dev3"
# extend 2-way mirror (cling if not contiguous)
diff --git a/test/shell/lvresize-rounding.sh b/test/shell/lvresize-rounding.sh
index 0cdce558f..c2251eb06 100644
--- a/test/shell/lvresize-rounding.sh
+++ b/test/shell/lvresize-rounding.sh
@@ -52,7 +52,7 @@ lvcreate -an -Zn -l1 -n $lv1 -i3 $vg
lvextend -l+100%FREE -i3 $vg/$lv1
check vg_field $vg vg_free_count 2
-lvreduce -f -l50%LV $vg/$lv1
+lvreduce -f --fs ignore -l50%LV $vg/$lv1
vgremove -f $vg
vgcreate $SHARED -s 4M $vg "$dev1" "$dev2" "$dev3"
@@ -72,21 +72,21 @@ lvextend -l+100%FREE $vg/lv
check vg_field $vg vg_free_count 0
# Rounds up and should reduce just by 3 extents
-lvreduce -f -l-4 $vg/lv
+lvreduce -f --fs ignore -l-4 $vg/lv
check vg_field $vg vg_free_count 3
# Should round up to 15 extents
lvextend -f -l+1 $vg/lv
check vg_field $vg vg_free_count 0
-lvreduce -f -l-4 $vg/lv
+lvreduce -f --fs ignore -l-4 $vg/lv
check vg_field $vg vg_free_count 3
lvextend -l90%VG $vg/lv
check vg_field $vg vg_free_count 0
-not lvreduce -f -l-10%LV $vg/lv
+not lvreduce -f --fs ignore -l-10%LV $vg/lv
check vg_field $vg vg_free_count 0
-lvreduce -f -l-20%LV $vg/lv
+lvreduce -f --fs ignore -l-20%LV $vg/lv
check vg_field $vg vg_free_count 3
diff --git a/test/shell/relative-sign-options.sh b/test/shell/relative-sign-options.sh
index ac6fe53b0..6be75259a 100644
--- a/test/shell/relative-sign-options.sh
+++ b/test/shell/relative-sign-options.sh
@@ -34,8 +34,8 @@ lvresize -y -l8 $vg/$lv1
lvresize -y -L16 $vg/$lv1
lvresize -y -l+1 $vg/$lv1
lvresize -y -L+1 $vg/$lv1
-lvresize -y -l-1 $vg/$lv1
-lvresize -y -L-1 $vg/$lv1
+lvresize -y --fs ignore -l-1 $vg/$lv1
+lvresize -y --fs ignore -L-1 $vg/$lv1
lvcreate -an -n $lv2 -l4 $vg
lvextend -y -l8 $vg/$lv2
@@ -46,12 +46,12 @@ not lvextend -y -l-1 $vg/$lv2
not lvextend -y -L-1 $vg/$lv2
lvcreate -an -n $lv3 -l64 $vg
-lvreduce -y -l32 $vg/$lv3
-lvreduce -y -L8 $vg/$lv3
-lvreduce -y -l-1 $vg/$lv3
-lvreduce -y -L-1 $vg/$lv3
-not lvreduce -y -l+1 $vg/$lv3
-not lvreduce -y -L+1 $vg/$lv3
+lvreduce -y --fs ignore -l32 $vg/$lv3
+lvreduce -y --fs ignore -L8 $vg/$lv3
+lvreduce -y --fs ignore -l-1 $vg/$lv3
+lvreduce -y --fs ignore -L-1 $vg/$lv3
+not lvreduce -y --fs ignore -l+1 $vg/$lv3
+not lvreduce -y --fs ignore -L+1 $vg/$lv3
# relative with percent extents
diff --git a/tools/args.h b/tools/args.h
index 2f94d4535..a8136d681 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -301,6 +301,27 @@ arg(foreign_ARG, '\0', "foreign", 0, 0, 0,
"Report/display foreign VGs that would otherwise be skipped.\n"
"See \\fBlvmsystemid\\fP(7) for more information about foreign VGs.\n")
+arg(fs_ARG, '\0', "fs", string_VAL, 0, 0,
+ "File system handling when resizing an LV.\n"
+ "\\fBchecksize\\fP: Only when reducing size, does nothing when extending.\n"
+ "Check the fs size and reduce the LV if the fs is not using the affected\n"
+ "space, i.e. the fs does not need to be shrunk. Fail the command without\n"
+ "reducing the fs or LV if the fs is using the affected space.\n"
+ "\\fBresize_remount\\fP: Resize the fs if needed. Mounts or unmounts the fs as\n"
+ "required (avoids mounting/unmounting when possible.)\n"
+ "Attempts to restore the original mount state when finished.\n"
+ "\\fBresize_keepmount\\fP: Resize the fs if needed, only if it can be done without\n"
+ "changing the current mount state. Fail the command without\n"
+ "resizing the fs or LV if an fs resize requires mounting or unmounting\n"
+ "\\fBresize_unmount\\fP: Resize the fs if needed, only while unmounted. Unmount the\n"
+ "fs if needed. Fail the command without resizing the fs\n"
+ "or LV if an fs resize is needed that requires the the fs to be mounted\n"
+ "\\fBresize\\fP: Equivalent to resize_remount.\n"
+ "\\fBresize_fsadm\\fP: Use the old method of calling fsadm to do handle the fs\n"
+ "(deprecated).\n"
+ "\\fBignore\\fP: Resize the LV without checking for or handling a file system.\n"
+ "WARNING: using ignore when reducing the LV size may cause data loss.\n")
+
arg(handlemissingpvs_ARG, '\0', "handlemissingpvs", 0, 0, 0,
"Allows a polling operation to continue when PVs are missing,\n"
"e.g. for repairs due to faulty devices.\n")
@@ -1447,7 +1468,8 @@ arg(readahead_ARG, 'r', "readahead", readahead_VAL, 0, 0,
"\\fBnone\\fP is equivalent to zero.\n")
arg(resizefs_ARG, 'r', "resizefs", 0, 0, 0,
- "Resize underlying filesystem together with the LV using \\fBfsadm\\fP(8).\n")
+ "Resize the file system on the LV.\n"
+ "Equivalent to --fs resize_remount. See --fs for more options.\n")
/* Not used */
arg(reset_ARG, 'R', "reset", 0, 0, 0, NULL)
diff --git a/tools/command-lines.in b/tools/command-lines.in
index dd033630b..13400e6f4 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -1379,7 +1379,7 @@ lvextend --size PSizeMB LV
OO: --alloc Alloc, --autobackup Bool, --force, --mirrors Number,
--nofsck, --nosync, --noudevsync, --reportformat ReportFmt, --resizefs,
--stripes Number, --stripesize SizeKB, --poolmetadatasize PSizeMB,
---type SegType
+--type SegType, --fs String
OP: PV ...
ID: lvextend_size
DESC: Extend an LV by a specified size.
@@ -1388,7 +1388,7 @@ lvextend LV PV ...
OO: --alloc Alloc, --autobackup Bool, --force, --mirrors Number,
--nofsck, --nosync, --noudevsync,
--reportformat ReportFmt, --resizefs, --stripes Number, --stripesize SizeKB,
---type SegType
+--type SegType, --fs String
ID: lvextend_pv
DESC: Extend an LV by specified PV extents.
@@ -1405,7 +1405,7 @@ lvextend --usepolicies LV_snapshot_thinpool_vdopool
OO: --alloc Alloc, --autobackup Bool, --force, --mirrors Number,
--nofsck, --nosync, --noudevsync,
--reportformat ReportFmt, --resizefs,
---type SegType
+--type SegType, --fs String
OP: PV ...
ID: lvextend_policy
DESC: Extend an LV according to a predefined policy.
@@ -1454,7 +1454,7 @@ DESC: Remove the devices file entry for the given PVID.
lvreduce --size NSizeMB LV
OO: --autobackup Bool, --force, --nofsck, --noudevsync,
---reportformat ReportFmt, --resizefs
+--reportformat ReportFmt, --resizefs, --fs String
ID: lvreduce_size
---
@@ -1484,7 +1484,7 @@ lvresize --size SSizeMB LV
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync, --reportformat ReportFmt, --resizefs,
--stripes Number, --stripesize SizeKB, --poolmetadatasize PSizeMB,
---type SegType
+--type SegType, --fs String
OP: PV ...
ID: lvresize_size
DESC: Resize an LV by a specified size.
@@ -1493,7 +1493,7 @@ lvresize LV PV ...
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync,
--reportformat ReportFmt, --resizefs, --stripes Number, --stripesize SizeKB,
---type SegType
+--type SegType, --fs String
ID: lvresize_pv
DESC: Resize an LV by specified PV extents.
diff --git a/tools/lvresize.c b/tools/lvresize.c
index a7148e52c..3c0ae7737 100644
--- a/tools/lvresize.c
+++ b/tools/lvresize.c
@@ -19,6 +19,7 @@ static int _lvresize_params(struct cmd_context *cmd, struct lvresize_params *lp)
{
const char *type_str = arg_str_value(cmd, type_ARG, NULL);
int only_linear = 0;
+ int set_fsopt = 0;
int set_extents_and_size = 0;
memset(lp, 0, sizeof(struct lvresize_params));
@@ -54,35 +55,31 @@ static int _lvresize_params(struct cmd_context *cmd, struct lvresize_params *lp)
lp->percent = PERCENT_PVS;
lp->sign = SIGN_PLUS;
lp->poolmetadata_size = 0;
- lp->resizefs = arg_is_set(cmd, resizefs_ARG);
- lp->nofsck = arg_is_set(cmd, nofsck_ARG);
+ set_fsopt = 1;
break;
case lvextend_size_CMD:
lp->resize = LV_EXTEND;
- lp->resizefs = arg_is_set(cmd, resizefs_ARG);
- lp->nofsck = arg_is_set(cmd, nofsck_ARG);
if ((lp->poolmetadata_size = arg_uint64_value(cmd, poolmetadatasize_ARG, 0)))
lp->poolmetadata_sign = arg_sign_value(cmd, poolmetadatasize_ARG, SIGN_NONE);
set_extents_and_size = 1;
+ set_fsopt = 1;
break;
case lvreduce_size_CMD:
lp->resize = LV_REDUCE;
lp->poolmetadata_size = 0;
- lp->resizefs = arg_is_set(cmd, resizefs_ARG);
- lp->nofsck = arg_is_set(cmd, nofsck_ARG);
set_extents_and_size = 1;
+ set_fsopt = 1;
break;
case lvresize_size_CMD:
lp->resize = LV_ANY;
lp->poolmetadata_size = arg_uint64_value(cmd, poolmetadatasize_ARG, 0);
- lp->resizefs = arg_is_set(cmd, resizefs_ARG);
- lp->nofsck = arg_is_set(cmd, nofsck_ARG);
if ((lp->poolmetadata_size = arg_uint64_value(cmd, poolmetadatasize_ARG, 0)))
lp->poolmetadata_sign = arg_sign_value(cmd, poolmetadatasize_ARG, SIGN_NONE);
set_extents_and_size = 1;
+ set_fsopt = 1;
break;
default:
@@ -90,6 +87,43 @@ static int _lvresize_params(struct cmd_context *cmd, struct lvresize_params *lp)
return 0;
};
+ if (set_fsopt) {
+ const char *str;
+ if ((str = arg_str_value(cmd, fs_ARG, NULL))) {
+ if (!strcmp(str, "checksize") ||
+ !strcmp(str, "resize") ||
+ !strcmp(str, "resize_remount") ||
+ !strcmp(str, "resize_keepmount") ||
+ !strcmp(str, "resize_unmount") ||
+ !strcmp(str, "resize_fsadm")) {
+ strncpy(lp->fsopt, str, sizeof(lp->fsopt)-1);
+ } else if (!strcmp(str, "ignore")) {
+ lp->fsopt[0] = '\0';
+ } else {
+ log_error("Unknown --fs value.");
+ return 0;
+ }
+ lp->user_set_fs = 1;
+ } else if (arg_is_set(cmd, resizefs_ARG)) {
+ /* --resizefs alone equates to --fs resize */
+ strncpy(lp->fsopt, "resize", sizeof(lp->fsopt)-1);
+ lp->user_set_fs = 1;
+ } else {
+ /*
+ * Use checksize when no fs option is specified.
+ * checksize with extend does nothing: the LV
+ * is extended and any fs is ignored.
+ * checksize with reduce checks for an fs that
+ * needs reducing: the LV is reduced only if the
+ * fs does not need to be reduced (or no fs.)
+ */
+ strncpy(lp->fsopt, "checksize", sizeof(lp->fsopt)-1);
+ }
+
+ if (lp->fsopt[0])
+ lp->nofsck = arg_is_set(cmd, nofsck_ARG);
+ }
+
if (set_extents_and_size) {
if ((lp->extents = arg_uint_value(cmd, extents_ARG, 0))) {
lp->sign = arg_sign_value(cmd, extents_ARG, 0);
@@ -237,6 +271,7 @@ static int _lvresize_single(struct cmd_context *cmd, struct logical_volume *lv,
struct processing_handle *handle)
{
struct lvresize_params *lp = (struct lvresize_params *) handle->custom_handle;
+ int ret;
if (cmd->position_argc > 1) {
/* First pos arg is required LV, remaining are optional PVs. */
@@ -245,11 +280,13 @@ static int _lvresize_single(struct cmd_context *cmd, struct logical_volume *lv,
} else
lp->pvh = &lv->vg->pvs;
- if (!lv_resize(cmd, lv, lp))
- return ECMD_FAILED;
+ ret = lv_resize(cmd, lv, lp);
- log_print_unless_silent("Logical volume %s successfully resized.",
- display_lvname(lv));
+ if (ret || lp->extend_fs_error)
+ log_print_unless_silent("Logical volume %s successfully resized.",
+ display_lvname(lv));
+ if (!ret)
+ return ECMD_FAILED;
return ECMD_PROCESSED;
}