summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2021-04-28 16:44:23 -0500
committerDavid Teigland <teigland@redhat.com>2021-05-07 10:53:35 -0500
commitb0693d981f1ecd2cf934738bd0e3cb67220434f4 (patch)
tree9bf21efe84563f90c2fbc021931ce270e4c4133d
parent00f603de2c507ee12195487fa007510ee3ff9770 (diff)
downloadlvm2-b0693d981f1ecd2cf934738bd0e3cb67220434f4.tar.gz
lvreduce: check for file system that cannot be reduced
Add a new command line option --detectfs y|n, along with the capability to detect if the LV contains a shrinkable file system (using libblkid). The new fs detection is performed by default to avoid acccidental data loss by users who reduce an LV without knowing that the file system cannot be reduced, or without including the --resizefs option to reduce the reducible fs. . If detectfs finds a shrinkable file system on the LV, then resizefs is also required. . If detectfs finds a non-shrinkable file system on the LV, then the LV is not reduced. . If detectfs does not find a file system on the LV, then the LV is reduced. The new errors reported for these cases are: $ lvreduce -L64M --detectfs y vg/lv Detected file system type xfs that cannot be reduced (from --detectfs). $ lvreduce -L64M --detectfs y vg/lv Detected file system type ext4 that can be reduced (see --resizefs). When detectfs is enabled, the lvreduce command will activate the LV to check the fs type. Using --detectfs n results in the same historical (and somewhat dangerous) lvreduce behavior.
-rw-r--r--lib/device/dev-type.c33
-rw-r--r--lib/device/dev-type.h2
-rw-r--r--lib/metadata/lv_manip.c49
-rw-r--r--lib/metadata/metadata-exported.h1
-rw-r--r--tools/args.h7
-rw-r--r--tools/command-lines.in6
-rw-r--r--tools/lvresize.c7
7 files changed, 102 insertions, 3 deletions
diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c
index 706061814..14c3f50d3 100644
--- a/lib/device/dev-type.c
+++ b/lib/device/dev-type.c
@@ -726,6 +726,39 @@ int get_fs_block_size(const char *pathname, uint32_t *fs_block_size)
#endif
#ifdef BLKID_WIPING_SUPPORT
+int get_fs_can_reduce(const char *pathname, int *fs_can_reduce, char *fs_buf, int fs_buf_len)
+{
+ char *fs_str = NULL;
+
+ if ((fs_str = blkid_get_tag_value(NULL, "TYPE", pathname))) {
+ if (fs_buf && fs_buf_len)
+ strncpy(fs_buf, fs_str, fs_buf_len-1);
+
+ log_debug("Found blkid filesystem TYPE %s on %s", fs_str, pathname);
+
+ if (fs_str && (!strcmp(fs_str, "ext4") || !strcmp(fs_str, "ext3") || !strcmp(fs_str, "ext2")))
+ *fs_can_reduce = 1;
+ else
+ *fs_can_reduce = 0;
+
+ free(fs_str);
+ return 1;
+ } else {
+ log_debug("No blkid filesystem TYPE found for %s", pathname);;
+ *fs_can_reduce = 1;
+ return 1;
+ }
+}
+#else
+int get_fs_can_reduce(const char *pathname, int *fs_can_reduce, char *fs_buf, int fs_buf_len)
+{
+ log_warn("Disabled blkid for fs type check.");
+ *fs_can_reduce = 1;
+ return 1;
+}
+#endif
+
+#ifdef BLKID_WIPING_SUPPORT
static inline int _type_in_flag_list(const char *type, uint32_t flag_list)
{
diff --git a/lib/device/dev-type.h b/lib/device/dev-type.h
index d358520df..35f265462 100644
--- a/lib/device/dev-type.h
+++ b/lib/device/dev-type.h
@@ -102,4 +102,6 @@ int dev_is_lv(struct device *dev);
int get_fs_block_size(const char *pathname, uint32_t *fs_block_size);
+int get_fs_can_reduce(const char *pathname, int *fs_can_reduce, char *fs_buf, int fs_buf_len);
+
#endif
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index 508f78c13..0ec9c2f51 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -6050,6 +6050,55 @@ int lv_resize(struct logical_volume *lv,
(pvh != &vg->pvs))
log_print_unless_silent("Ignoring PVs on command line when reducing.");
+ if (lp->detectfs) {
+ char pathname[PATH_MAX];
+ char *dmname;
+ char fs_buf[16] = {0};
+ int fs_can_reduce = 0;
+
+ /* if lv is not active, activate it */
+ if (!lv_is_active(lv)) {
+ if (!activate_lv(cmd, lv)) {
+ log_error("Failed to activate %s for --detectfs.", display_lvname(lv));
+ return 0;
+ }
+ if (!sync_local_dev_names(cmd))
+ return_0;
+ activated = 1;
+ }
+
+ if (!(dmname = dm_build_dm_name(cmd->mem, vg->name, lv->name, NULL)))
+ return_0;
+
+ if (dm_snprintf(pathname, sizeof(pathname), "%s/%s", dm_dir(), dmname) < 0)
+ return_0;
+
+ /* use blkid to check fs type, we know which types can reduce */
+ if (!get_fs_can_reduce(pathname, &fs_can_reduce, fs_buf, sizeof(fs_buf))) {
+ log_error("Failed to find file system type for --detectfs.");
+ goto bad;
+ }
+
+ if (!fs_can_reduce) {
+ log_error("Detected file system type %s that cannot be reduced (from --detectfs).",
+ fs_buf[0] ? fs_buf : "unknown");
+ goto bad;
+ }
+
+ /*
+ * We've checked that the fs can reduce, but if the user has
+ * not set --resizefs to actually do the fs reduction, then
+ * report an error since it would unnecessarily cause data
+ * loss. i.e. require the user to add either --detectfs n or
+ * --resizefs.
+ */
+ if (!lp->resizefs) {
+ log_error("Detected file system type %s that can be reduced (see --resizefs).",
+ fs_buf[0] ? fs_buf : "unknown");
+ goto bad;
+ }
+ }
+
/* Request confirmation before operations that are often mistakes. */
/* aux_lv never resize fs */
if ((lp->resizefs || (lp->resize == LV_REDUCE)) &&
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index c6116350f..06be68a48 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -687,6 +687,7 @@ struct lvresize_params {
int nosync;
int nofsck;
int resizefs;
+ int detectfs;
unsigned mirrors;
uint32_t stripes;
diff --git a/tools/args.h b/tools/args.h
index 741c82b9f..5dbc285b7 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -155,6 +155,13 @@ arg(cachesize_ARG, '\0', "cachesize", sizemb_VAL, 0, 0,
arg(check_ARG, '\0', "check", 0, 0, 0,
"Check the content of the devices file.\n")
+arg(detectfs_ARG, '\0', "detectfs", bool_VAL, 0, 0,
+ "Use blkid to check for a file system on the LV before reducing it.\n"
+ "If a shrinkable file system is found, then --resizefs is also required.\n"
+ "If a non-shrinkable file system is found, then the LV is not reduced.\n"
+ "If no file system is found, then the LV is reduced.\n"
+ "An inactive LV is activated to look for file systems.\n")
+
arg(commandprofile_ARG, '\0', "commandprofile", string_VAL, 0, 0,
"The command profile to use for command configuration.\n"
"See \\fBlvm.conf\\fP(5) for more information about profiles.\n")
diff --git a/tools/command-lines.in b/tools/command-lines.in
index 1107c1e02..73a758114 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -1449,7 +1449,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, --detectfs Bool
ID: lvreduce_general
---
@@ -1479,7 +1479,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, --detectfs Bool
OP: PV ...
ID: lvresize_by_size
DESC: Resize an LV by a specified size.
@@ -1488,7 +1488,7 @@ lvresize LV PV ...
OO: --alloc Alloc, --autobackup Bool, --force,
--nofsck, --nosync, --noudevsync,
--reportformat ReportFmt, --resizefs, --stripes Number, --stripesize SizeKB,
---type SegType
+--type SegType, --detectfs Bool
ID: lvresize_by_pv
DESC: Resize an LV by specified PV extents.
diff --git a/tools/lvresize.c b/tools/lvresize.c
index f39f03a40..ab434ba14 100644
--- a/tools/lvresize.c
+++ b/tools/lvresize.c
@@ -39,6 +39,13 @@ static int _lvresize_params(struct cmd_context *cmd, int argc, char **argv,
else
lp->resize = LV_ANY;
+ if (lp->resize == LV_REDUCE) {
+ if (arg_is_set(cmd, detectfs_ARG))
+ lp->detectfs = arg_int_value(cmd, detectfs_ARG, 1);
+ else
+ lp->detectfs = 1;
+ }
+
lp->sign = lp->poolmetadata_sign = SIGN_NONE;
if ((lp->use_policies = arg_is_set(cmd, usepolicies_ARG))) {