main - cachevol: allow forced detaching of damaged or invalid cachevol
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=cb54d0801d776205788...
Commit: cb54d0801d776205788f8f46b31dd9e487833343
Parent: ae2af1d5eda8fa4e082e67429758f731ca6fcef6
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Jan 12 11:53:02 2021 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Feb 2 14:31:23 2021 -0600
cachevol: allow forced detaching of damaged or invalid cachevol
A cachevol can be forcibly detached when it's missing devices.
Also allow this if it's damaged/invalid and unrepairable.
This would be needed to recover data from the origin LV after
a cachevol is lost or damaged beyond repair.
---
test/shell/writecache-split.sh | 34 ++++++++++++++++++++++++++++++++++
tools/lvconvert.c | 27 ++++++++++++++++++++-------
2 files changed, 54 insertions(+), 7 deletions(-)
diff --git a/test/shell/writecache-split.sh b/test/shell/writecache-split.sh
index 5723f7aab..f6d2d9aec 100644
--- a/test/shell/writecache-split.sh
+++ b/test/shell/writecache-split.sh
@@ -153,6 +153,40 @@ vgextend --restoremissing $vg "$dev3"
vgremove -ff $vg
+#
+# split while cachevol is damaged
+#
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4"
+
+lvcreate -n $lv1 -l 16 -an $vg "$dev1" "$dev4"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+
+lvchange -ay $vg/$lv1
+
+mkfs_mount_umount $lv1
+
+lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+diff pattern1 "$mount_dir/pattern1"
+cp pattern1 "$mount_dir/pattern2"
+umount "$mount_dir"
+lvchange -an $vg/$lv1
+
+dd if=/dev/zero of="$dev2" seek=1 bs=1M count=16
+
+lvconvert --splitcache --force --yes $vg/$lv1
+
+lvchange -ay $vg/$lv1
+
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+diff pattern1 "$mount_dir/pattern1"
+umount "$mount_dir"
+lvchange -an $vg/$lv1
+
+vgremove -ff $vg
+
#
# splitcache when origin is raid
#
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 3457cd08a..a72126bf4 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -1882,12 +1882,22 @@ static int _lvconvert_split_and_keep_cachevol(struct cmd_context *cmd,
char cvol_name[NAME_LEN];
struct lv_segment *cache_seg = first_seg(lv);
int cache_mode = cache_seg->cache_mode;
+ int direct_detach = 0;
if (!archive(lv->vg))
return_0;
log_debug("Detaching cachevol %s from LV %s.", display_lvname(lv_fast), display_lvname(lv));
+ /*
+ * Allow forcible detach without activating or flushing
+ * in case the cache is corrupt/damaged/invalid.
+ * This would generally be done to rescue data from
+ * the origin if the cache could not be repaired.
+ */
+ if (!lv_is_active(lv) && arg_count(cmd, force_ARG))
+ direct_detach = 1;
+
/*
* Detaching a writeback cache generally requires flushing;
* doing otherwise can mean data loss/corruption.
@@ -1902,7 +1912,10 @@ static int _lvconvert_split_and_keep_cachevol(struct cmd_context *cmd,
log_error("Conversion aborted.");
return 0;
}
+ direct_detach = 1;
+ }
+ if (direct_detach) {
log_warn("WARNING: Data may be lost by detaching writeback cache without flushing.");
if (!arg_count(cmd, yes_ARG) &&
@@ -5554,7 +5567,13 @@ static int _lvconvert_detach_writecache(struct cmd_context *cmd,
if (!archive(lv->vg))
return_0;
- if (lv_is_partial(lv_fast)) {
+ /*
+ * If the LV is inactive when we begin, then we want to
+ * deactivate the LV at the end.
+ */
+ active_begin = lv_is_active(lv);
+
+ if (lv_is_partial(lv_fast) || (!active_begin && arg_count(cmd, force_ARG))) {
if (!arg_count(cmd, force_ARG)) {
log_warn("WARNING: writecache on %s is not complete and cannot be flushed.", display_lvname(lv_fast));
log_warn("WARNING: cannot detach writecache from %s without --force.", display_lvname(lv));
@@ -5574,12 +5593,6 @@ static int _lvconvert_detach_writecache(struct cmd_context *cmd,
noflush = 1;
}
- /*
- * If the LV is inactive when we begin, then we want to
- * deactivate the LV at the end.
- */
- active_begin = lv_is_active(lv);
-
if (!noflush) {
/*
* --cachesettings cleaner=0 means to skip the use of the cleaner
2 years, 8 months
main - test: check read_only_volume_list tagging works
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=ae2af1d5eda8fa4e082...
Commit: ae2af1d5eda8fa4e082e67429758f731ca6fcef6
Parent: 51c83f14837c8647c3522abb23707da3ece2085c
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Tue Feb 2 19:53:28 2021 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Tue Feb 2 21:23:39 2021 +0100
test: check read_only_volume_list tagging works
---
test/shell/tags.sh | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/test/shell/tags.sh b/test/shell/tags.sh
index fd1b33229..5b636a877 100644
--- a/test/shell/tags.sh
+++ b/test/shell/tags.sh
@@ -52,6 +52,11 @@ check lv_field @firstlvtag1 tags "firstlvtag1"
not check lv_field @secondlvtag1 tags "firstlvtag1"
check lv_field $vg1/$lv2 tags "secondlvtag1"
not check lv_field $vg1/$lv1 tags "secondlvtag1"
+
+# LV is not zeroed when tag matches read only volume list
+lvcreate -l1 $vg1 --addtag "RO" --config "activation/read_only_volume_list = [ \"@RO\" ]" 2>&1 | tee out
+grep "not zeroed" out
+
vgremove -f $vg1
# lvchange with --addtag and --deltag
2 years, 8 months
main - lvcreate: use lv_passes_readonly_filter
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=51c83f14837c8647c35...
Commit: 51c83f14837c8647c3522abb23707da3ece2085c
Parent: 8454ce66c511438ef0d9da3d3b0bac2a5a3d8f2b
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Tue Feb 2 19:53:59 2021 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Tue Feb 2 21:23:39 2021 +0100
lvcreate: use lv_passes_readonly_filter
Check if created LV is going to be activated read-only
because such LV cannot be zeroed (equals to use
option '-pr').
---
WHATS_NEW | 1 +
lib/activate/activate.c | 5 +++++
lib/activate/activate.h | 2 ++
lib/metadata/lv_manip.c | 6 ++++++
4 files changed, 14 insertions(+)
diff --git a/WHATS_NEW b/WHATS_NEW
index c6be9b481..42ea4f550 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.03.12 -
===================================
+ Check if lvcreate passes read_only_volume_list with tags and skips zeroing.
Allocation prints better error when metadata cannot fit on a single PV.
Pvmove can better resolve full thin-pool tree move.
Limit pool metadata spare to 16GiB.
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index 7ed644113..de866fb6c 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -466,6 +466,11 @@ static int _passes_readonly_filter(struct cmd_context *cmd,
return _lv_passes_volumes_filter(cmd, lv, cn, activation_read_only_volume_list_CFG);
}
+int lv_passes_readonly_filter(const struct logical_volume *lv)
+{
+ return _passes_readonly_filter(lv->vg->cmd, lv);
+}
+
int library_version(char *version, size_t size)
{
if (!activation())
diff --git a/lib/activate/activate.h b/lib/activate/activate.h
index 3f4d128be..53c8631b4 100644
--- a/lib/activate/activate.h
+++ b/lib/activate/activate.h
@@ -208,6 +208,8 @@ int lvs_in_vg_opened(const struct volume_group *vg);
int lv_is_active(const struct logical_volume *lv);
+int lv_passes_readonly_filter(const struct logical_volume *lv);
+
/* Check is any component LV is active */
const struct logical_volume *lv_component_is_active(const struct logical_volume *lv);
const struct logical_volume *lv_holder_is_active(const struct logical_volume *lv);
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index d101fa582..29c95ff63 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -7987,6 +7987,12 @@ static int _should_wipe_lv(struct lvcreate_params *lp,
first_seg(first_seg(lv)->pool_lv)->zero_new_blocks))
return 0;
+ if (warn && (lv_passes_readonly_filter(lv))) {
+ log_warn("WARNING: Read-only activated logical volume %s not zeroed.",
+ display_lvname(lv));
+ return 0;
+ }
+
/* Cannot zero read-only volume */
if ((lv->status & LVM_WRITE) &&
(lp->zero || lp->wipe_signatures))
2 years, 8 months
main - writecache: let block_size setting override device block sizes
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=8454ce66c511438ef0d...
Commit: 8454ce66c511438ef0d9da3d3b0bac2a5a3d8f2b
Parent: bee9f4efdd8195f383f026290b741314cdc42439
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Jan 12 14:41:38 2021 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Feb 2 13:52:31 2021 -0600
writecache: let block_size setting override device block sizes
In cases where lvconvert does not detect a fs block size on the
device, it falls back to choosing a writecache block size based
on the device's LBS and PBS (tries to match those.)
If the user specifies a writecache block size on the command
line (--cachesettings block_size=4096|512), lvconvert currently
fails and reports an error if the user-specified value does not
match the value lvconvert would have chosen based on LBS and PBS.
The purpose of allowing a user-specified value on the command line
is to override what lvconvert would otherwise do, so change this
to just print a warning that the user value does not match the
value that would be chosen based on the LBS/PBS, and then take
the user-specified value as the writecache block size.
---
test/shell/writecache-blocksize.sh | 38 ++++++++++++++++++++++++++++++++++++++
tools/lvconvert.c | 6 +++---
2 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/test/shell/writecache-blocksize.sh b/test/shell/writecache-blocksize.sh
index 3685fdd05..74f8c2ae5 100644
--- a/test/shell/writecache-blocksize.sh
+++ b/test/shell/writecache-blocksize.sh
@@ -184,3 +184,41 @@ _check_env "4096" "4096"
_run_test 4096 ""
aux cleanup_scsi_debug_dev
+
+
+# scsi_debug devices with 512 LBS 512 PBS
+aux prepare_scsi_debug_dev 256 || skip
+aux prepare_devs 2 64
+
+_check_env "512" "512"
+
+vgcreate $SHARED $vg "$dev1"
+vgextend $vg "$dev2"
+lvcreate -n $lv1 -l 8 -an $vg "$dev1"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+lvconvert --yes --type writecache --cachevol $lv2 --cachesettings "block_size=4096" $vg/$lv1
+lvchange -ay $vg/$lv1
+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1" |tee out
+grep "sectsz=4096" out
+_add_new_data_to_mnt
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1" |tee out
+grep 4096 out
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_add_more_data_to_mnt
+_verify_data_on_mnt
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_verify_data_on_mnt
+_verify_more_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+lvchange -an $vg/$lv2
+_verify_data_on_lv
+lvremove $vg/$lv1
+lvremove $vg/$lv2
+vgremove $vg
+
+aux cleanup_scsi_debug_dev
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index e37172a5e..3457cd08a 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -6015,9 +6015,9 @@ skip_fs:
}
if (block_size_setting && (block_size_setting != block_size)) {
- log_error("Cannot use writecache block size %u with unknown file system block size, logical block size %u, physical block size %u.",
- block_size_setting, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
- goto bad;
+ log_warn("WARNING: writecache block size %u does not match device block sizes, logical %u physical %u",
+ block_size_setting, lbs_4k ? 4096 : 512, pbs_4k ? 4096 : 512);
+ block_size = block_size_setting;
}
if (block_size != 512) {
2 years, 8 months
main - filter-mpath: work with nvme devices
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=bee9f4efdd8195f383f...
Commit: bee9f4efdd8195f383f026290b741314cdc42439
Parent: 48dfc388f7bde964d8e4d6816f27de858c984fb3
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Dec 3 10:48:21 2020 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Feb 2 13:01:20 2021 -0600
filter-mpath: work with nvme devices
Recognize when a device is nvme, and apply filter-mpath to
nvme devices in addition to scsi devices.
---
lib/device/dev-type.c | 81 +++++++++++++++++++----
lib/device/dev-type.h | 2 +
lib/device/device.h | 1 +
lib/filters/filter-mpath.c | 156 ++++++++++++++++++++++++++++++---------------
4 files changed, 177 insertions(+), 63 deletions(-)
diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c
index 896821de8..379afa89c 100644
--- a/lib/device/dev-type.c
+++ b/lib/device/dev-type.c
@@ -21,6 +21,7 @@
#include "lib/metadata/metadata.h"
#include "lib/device/bcache.h"
#include "lib/label/label.h"
+#include "lib/commands/toolcontext.h"
#ifdef BLKID_WIPING_SUPPORT
#include <blkid.h>
@@ -67,6 +68,31 @@ int dev_is_pmem(struct device *dev)
return is_pmem ? 1 : 0;
}
+/*
+ * An nvme device has major number 259 (BLKEXT), minor number <minor>,
+ * and reading /sys/dev/block/259:<minor>/device/dev shows a character
+ * device cmajor:cminor where cmajor matches the major number of the
+ * nvme character device entry in /proc/devices. Checking all of that
+ * is excessive and unnecessary compared to just comparing /dev/name*.
+ */
+
+int dev_is_nvme(struct dev_types *dt, struct device *dev)
+{
+ struct dm_str_list *strl;
+
+ if (dev->flags & DEV_IS_NVME)
+ return 1;
+
+ dm_list_iterate_items(strl, &dev->aliases) {
+ if (!strncmp(strl->str, "/dev/nvme", 9)) {
+ log_debug("Found nvme device %s", dev_name(dev));
+ dev->flags |= DEV_IS_NVME;
+ return 1;
+ }
+ }
+ return 0;
+}
+
int dev_is_lv(struct device *dev)
{
FILE *fp;
@@ -302,6 +328,9 @@ int dev_subsystem_part_major(struct dev_types *dt, struct device *dev)
const char *dev_subsystem_name(struct dev_types *dt, struct device *dev)
{
+ if (dev->flags & DEV_IS_NVME)
+ return "NVME";
+
if (MAJOR(dev->dev) == dt->device_mapper_major)
return "DM";
@@ -348,7 +377,6 @@ int major_is_scsi_device(struct dev_types *dt, int major)
return (dt->dev_type_array[major].flags & PARTITION_SCSI_DEVICE) ? 1 : 0;
}
-
static int _loop_is_with_partscan(struct device *dev)
{
FILE *fp;
@@ -398,6 +426,28 @@ struct partition {
uint32_t nr_sects;
} __attribute__((packed));
+static int _has_sys_partition(struct device *dev)
+{
+ char path[PATH_MAX];
+ struct stat info;
+ int major = (int) MAJOR(dev->dev);
+ int minor = (int) MINOR(dev->dev);
+
+ /* check if dev is a partition */
+ if (dm_snprintf(path, sizeof(path), "%s/dev/block/%d:%d/partition",
+ dm_sysfs_dir(), major, minor) < 0) {
+ log_error("dm_snprintf partition failed");
+ return 0;
+ }
+
+ if (stat(path, &info) == -1) {
+ if (errno != ENOENT)
+ log_sys_error("stat", path);
+ return 0;
+ }
+ return 1;
+}
+
static int _is_partitionable(struct dev_types *dt, struct device *dev)
{
int parts = major_max_partitions(dt, MAJOR(dev->dev));
@@ -414,6 +464,13 @@ static int _is_partitionable(struct dev_types *dt, struct device *dev)
_loop_is_with_partscan(dev))
return 1;
+ if (dev_is_nvme(dt, dev)) {
+ /* If this dev is already a partition then it's not partitionable. */
+ if (_has_sys_partition(dev))
+ return 0;
+ return 1;
+ }
+
if ((parts <= 1) || (MINOR(dev->dev) % parts))
return 0;
@@ -557,10 +614,17 @@ int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result)
char path[PATH_MAX];
char temp_path[PATH_MAX];
char buffer[64];
- struct stat info;
FILE *fp = NULL;
int parts, residue, size, ret = 0;
+ /*
+ * /dev/nvme devs don't use the major:minor numbering like
+ * block dev types that have their own major number, so
+ * the calculation based on minor number doesn't work.
+ */
+ if (dev_is_nvme(dt, dev))
+ goto sys_partition;
+
/*
* Try to get the primary dev out of the
* list of known device types first.
@@ -576,23 +640,14 @@ int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result)
goto out;
}
+ sys_partition:
/*
* If we can't get the primary dev out of the list of known device
* types, try to look at sysfs directly then. This is more complex
* way and it also requires certain sysfs layout to be present
* which might not be there in old kernels!
*/
-
- /* check if dev is a partition */
- if (dm_snprintf(path, sizeof(path), "%s/dev/block/%d:%d/partition",
- sysfs_dir, major, minor) < 0) {
- log_error("dm_snprintf partition failed");
- goto out;
- }
-
- if (stat(path, &info) == -1) {
- if (errno != ENOENT)
- log_sys_error("stat", path);
+ if (!_has_sys_partition(dev)) {
*result = dev->dev;
ret = 1;
goto out; /* dev is not a partition! */
diff --git a/lib/device/dev-type.h b/lib/device/dev-type.h
index fdf7791cf..8b94b7997 100644
--- a/lib/device/dev-type.h
+++ b/lib/device/dev-type.h
@@ -95,6 +95,8 @@ int dev_is_rotational(struct dev_types *dt, struct device *dev);
int dev_is_pmem(struct device *dev);
+int dev_is_nvme(struct dev_types *dt, struct device *dev);
+
int dev_is_lv(struct device *dev);
int get_fs_block_size(struct device *dev, uint32_t *fs_block_size);
diff --git a/lib/device/device.h b/lib/device/device.h
index a58bff8e3..816db3166 100644
--- a/lib/device/device.h
+++ b/lib/device/device.h
@@ -38,6 +38,7 @@
#define DEV_SCAN_FOUND_LABEL 0x00010000 /* label scan read dev and found label */
#define DEV_IS_MD_COMPONENT 0x00020000 /* device is an md component */
#define DEV_UDEV_INFO_MISSING 0x00040000 /* we have no udev info for this device */
+#define DEV_IS_NVME 0x00080000 /* set if dev is nvme */
/*
* Support for external device info.
diff --git a/lib/filters/filter-mpath.c b/lib/filters/filter-mpath.c
index 889a2dd96..853a2c569 100644
--- a/lib/filters/filter-mpath.c
+++ b/lib/filters/filter-mpath.c
@@ -16,6 +16,7 @@
#include "lib/misc/lib.h"
#include "lib/filters/filter.h"
#include "lib/activate/activate.h"
+#include "lib/commands/toolcontext.h"
#ifdef UDEV_SYNC_SUPPORT
#include <libudev.h>
#include "lib/device/dev-ext-udev-constants.h"
@@ -27,7 +28,6 @@
#define MPATH_PREFIX "mpath-"
-
struct mpath_priv {
struct dm_pool *mem;
struct dev_filter f;
@@ -35,6 +35,9 @@ struct mpath_priv {
struct dm_hash_table *hash;
};
+/*
+ * given "/dev/foo" return "foo"
+ */
static const char *_get_sysfs_name(struct device *dev)
{
const char *name;
@@ -53,6 +56,11 @@ static const char *_get_sysfs_name(struct device *dev)
return name;
}
+/*
+ * given major:minor
+ * readlink translates /sys/dev/block/major:minor to /sys/.../foo
+ * from /sys/.../foo return "foo"
+ */
static const char *_get_sysfs_name_by_devt(const char *sysfs_dir, dev_t devno,
char *buf, size_t buf_size)
{
@@ -102,27 +110,28 @@ static int _get_sysfs_string(const char *path, char *buffer, int max_size)
return r;
}
-static int _get_sysfs_get_major_minor(const char *sysfs_dir, const char *kname, int *major, int *minor)
+static int _get_sysfs_dm_mpath(struct dev_types *dt, const char *sysfs_dir, const char *holder_name)
{
- char path[PATH_MAX], buffer[64];
+ char path[PATH_MAX];
+ char buffer[128];
- if (dm_snprintf(path, sizeof(path), "%sblock/%s/dev", sysfs_dir, kname) < 0) {
+ if (dm_snprintf(path, sizeof(path), "%sblock/%s/dm/uuid", sysfs_dir, holder_name) < 0) {
log_error("Sysfs path string is too long.");
return 0;
}
+ buffer[0] = '\0';
+
if (!_get_sysfs_string(path, buffer, sizeof(buffer)))
return_0;
- if (sscanf(buffer, "%d:%d", major, minor) != 2) {
- log_error("Failed to parse major minor from %s", buffer);
- return 0;
- }
+ if (!strncmp(buffer, MPATH_PREFIX, 6))
+ return 1;
- return 1;
+ return 0;
}
-static int _get_parent_mpath(const char *dir, char *name, int max_size)
+static int _get_holder_name(const char *dir, char *name, int max_size)
{
struct dirent *d;
DIR *dr;
@@ -155,7 +164,7 @@ static int _get_parent_mpath(const char *dir, char *name, int max_size)
}
#ifdef UDEV_SYNC_SUPPORT
-static int _udev_dev_is_mpath(struct device *dev)
+static int _udev_dev_is_mpath_component(struct device *dev)
{
const char *value;
struct dev_ext *ext;
@@ -174,95 +183,148 @@ static int _udev_dev_is_mpath(struct device *dev)
return 0;
}
#else
-static int _udev_dev_is_mpath(struct device *dev)
+static int _udev_dev_is_mpath_component(struct device *dev)
{
return 0;
}
#endif
-static int _native_dev_is_mpath(struct dev_filter *f, struct device *dev)
+static int _native_dev_is_mpath_component(struct cmd_context *cmd, struct dev_filter *f, struct device *dev)
{
struct mpath_priv *mp = (struct mpath_priv *) f->private;
struct dev_types *dt = mp->dt;
- const char *part_name, *name;
- struct stat info;
- char path[PATH_MAX], parent_name[PATH_MAX];
+ const char *part_name;
+ const char *name; /* e.g. "sda" for "/dev/sda" */
+ char link_path[PATH_MAX]; /* some obscure, unpredictable sysfs path */
+ char holders_path[PATH_MAX]; /* e.g. "/sys/block/sda/holders/" */
+ char dm_dev_path[PATH_MAX]; /* e.g. "/dev/dm-1" */
+ char holder_name[128] = { 0 }; /* e.g. "dm-1" */
const char *sysfs_dir = dm_sysfs_dir();
- int major = MAJOR(dev->dev);
- int minor = MINOR(dev->dev);
+ int dev_major = MAJOR(dev->dev);
+ int dev_minor = MINOR(dev->dev);
+ int dm_dev_major;
+ int dm_dev_minor;
+ struct stat info;
dev_t primary_dev;
long look;
- /* Limit this filter only to SCSI devices */
- if (!major_is_scsi_device(dt, MAJOR(dev->dev)))
+ /* Limit this filter to SCSI or NVME devices */
+ if (!major_is_scsi_device(dt, dev_major) && !dev_is_nvme(dt, dev))
return 0;
switch (dev_get_primary_dev(dt, dev, &primary_dev)) {
+
case 2: /* The dev is partition. */
part_name = dev_name(dev); /* name of original dev for log_debug msg */
- if (!(name = _get_sysfs_name_by_devt(sysfs_dir, primary_dev, parent_name, sizeof(parent_name))))
+
+ /* gets "foo" for "/dev/foo" where "/dev/foo" comes from major:minor */
+ if (!(name = _get_sysfs_name_by_devt(sysfs_dir, primary_dev, link_path, sizeof(link_path))))
return_0;
+
log_debug_devs("%s: Device is a partition, using primary "
"device %s for mpath component detection",
part_name, name);
break;
+
case 1: /* The dev is already a primary dev. Just continue with the dev. */
+
+ /* gets "foo" for "/dev/foo" */
if (!(name = _get_sysfs_name(dev)))
return_0;
break;
+
default: /* 0, error. */
- log_warn("Failed to get primary device for %d:%d.", major, minor);
+ log_warn("Failed to get primary device for %d:%d.", dev_major, dev_minor);
return 0;
}
- if (dm_snprintf(path, sizeof(path), "%sblock/%s/holders", sysfs_dir, name) < 0) {
+ if (dm_snprintf(holders_path, sizeof(holders_path), "%sblock/%s/holders", sysfs_dir, name) < 0) {
log_warn("Sysfs path to check mpath is too long.");
return 0;
}
/* also will filter out partitions */
- if (stat(path, &info))
+ if (stat(holders_path, &info))
return 0;
if (!S_ISDIR(info.st_mode)) {
- log_warn("Path %s is not a directory.", path);
+ log_warn("Path %s is not a directory.", holders_path);
return 0;
}
- if (!_get_parent_mpath(path, parent_name, sizeof(parent_name)))
+ /*
+ * If holders dir contains an entry such as "dm-1", then this sets
+ * holder_name to "dm-1".
+ *
+ * If holders dir is empty, return 0 (this is generally where
+ * devs that are not mpath components return.)
+ */
+ if (!_get_holder_name(holders_path, holder_name, sizeof(holder_name)))
return 0;
- if (!_get_sysfs_get_major_minor(sysfs_dir, parent_name, &major, &minor))
- return_0;
+ if (dm_snprintf(dm_dev_path, sizeof(dm_dev_path), "%s/%s", cmd->dev_dir, holder_name) < 0) {
+ log_warn("dm device path to check mpath is too long.");
+ return 0;
+ }
- if (major != dt->device_mapper_major)
+ /*
+ * stat "/dev/dm-1" which is the holder of the dev we're checking
+ * dm_dev_major:dm_dev_minor come from stat("/dev/dm-1")
+ */
+ if (stat(dm_dev_path, &info)) {
+ log_debug("filter-mpath %s holder %s stat result %d",
+ dev_name(dev), dm_dev_path, errno);
return 0;
+ }
+ dm_dev_major = (int)MAJOR(info.st_rdev);
+ dm_dev_minor = (int)MINOR(info.st_rdev);
+
+ if (dm_dev_major != dt->device_mapper_major) {
+ log_debug_devs("filter-mpath %s holder %s %d:%d does not have dm major",
+ dev_name(dev), dm_dev_path, dm_dev_major, dm_dev_minor);
+ return 0;
+ }
- /* Avoid repeated detection of multipath device and use first checked result */
- look = (long) dm_hash_lookup_binary(mp->hash, &minor, sizeof(minor));
+ /*
+ * Save the result of checking that "/dev/dm-1" is an mpath device
+ * to avoid repeating it for each path component.
+ * The minor number of "/dev/dm-1" is added to the hash table with
+ * const value 2 meaning that dm minor 1 (for /dev/dm-1) is a multipath dev
+ * and const value 1 meaning that dm minor 1 is not a multipath dev.
+ */
+ look = (long) dm_hash_lookup_binary(mp->hash, &dm_dev_minor, sizeof(dm_dev_minor));
if (look > 0) {
- log_debug_devs("%s(%u:%u): already checked as %sbeing mpath.",
- parent_name, major, minor, (look > 1) ? "" : "not ");
+ log_debug_devs("filter-mpath %s holder %s %u:%u already checked as %sbeing mpath.",
+ dev_name(dev), holder_name, dm_dev_major, dm_dev_minor, (look > 1) ? "" : "not ");
return (look > 1) ? 1 : 0;
}
- if (lvm_dm_prefix_check(major, minor, MPATH_PREFIX)) {
- (void) dm_hash_insert_binary(mp->hash, &minor, sizeof(minor), (void*)2);
+ /*
+ * Returns 1 if /sys/block/<holder_name>/dm/uuid indicates that
+ * <holder_name> is a dm device with dm uuid prefix mpath-.
+ * When true, <holder_name> will be something like "dm-1".
+ *
+ * (Is a hash table worth it to avoid reading one sysfs file?)
+ */
+ if (_get_sysfs_dm_mpath(dt, sysfs_dir, holder_name)) {
+ log_debug_devs("filter-mpath %s holder %s %u:%u ignore mpath component",
+ dev_name(dev), holder_name, dm_dev_major, dm_dev_minor);
+ (void) dm_hash_insert_binary(mp->hash, &dm_dev_minor, sizeof(dm_dev_minor), (void*)2);
return 1;
}
- (void) dm_hash_insert_binary(mp->hash, &minor, sizeof(minor), (void*)1);
+ (void) dm_hash_insert_binary(mp->hash, &dm_dev_minor, sizeof(dm_dev_minor), (void*)1);
return 0;
}
-static int _dev_is_mpath(struct dev_filter *f, struct device *dev)
+static int _dev_is_mpath_component(struct cmd_context *cmd, struct dev_filter *f, struct device *dev)
{
if (dev->ext.src == DEV_EXT_NONE)
- return _native_dev_is_mpath(f, dev);
+ return _native_dev_is_mpath_component(cmd, f, dev);
if (dev->ext.src == DEV_EXT_UDEV)
- return _udev_dev_is_mpath(dev);
+ return _udev_dev_is_mpath_component(dev);
log_error(INTERNAL_ERROR "Missing hook for mpath recognition "
"using external device info source %s", dev_ext_name(dev));
@@ -272,11 +334,11 @@ static int _dev_is_mpath(struct dev_filter *f, struct device *dev)
#define MSG_SKIPPING "%s: Skipping mpath component device"
-static int _ignore_mpath(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
+static int _ignore_mpath_component(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
{
dev->filtered_flags &= ~DEV_FILTERED_MPATH_COMPONENT;
- if (_dev_is_mpath(f, dev) == 1) {
+ if (_dev_is_mpath_component(cmd, f, dev) == 1) {
if (dev->ext.src == DEV_EXT_NONE)
log_debug_devs(MSG_SKIPPING, dev_name(dev));
else
@@ -303,8 +365,8 @@ static void _destroy(struct dev_filter *f)
struct dev_filter *mpath_filter_create(struct dev_types *dt)
{
const char *sysfs_dir = dm_sysfs_dir();
- struct dm_pool *mem;
struct mpath_priv *mp;
+ struct dm_pool *mem;
struct dm_hash_table *hash;
if (!*sysfs_dir) {
@@ -328,19 +390,13 @@ struct dev_filter *mpath_filter_create(struct dev_types *dt)
goto bad;
}
- if (!(mp = dm_pool_zalloc(mem, sizeof(*mp)))) {
- log_error("mpath filter allocation failed.");
- goto bad;
- }
-
- mp->f.passes_filter = _ignore_mpath;
+ mp->f.passes_filter = _ignore_mpath_component;
mp->f.destroy = _destroy;
mp->f.use_count = 0;
mp->f.private = mp;
mp->f.name = "mpath";
-
- mp->mem = mem;
mp->dt = dt;
+ mp->mem = mem;
mp->hash = hash;
log_debug_devs("mpath filter initialised.");
2 years, 8 months
main - tests: increase required target version
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=48dfc388f7bde964d8e...
Commit: 48dfc388f7bde964d8e4d6816f27de858c984fb3
Parent: 6e8a32e4fd424ef599549ac1036ce795a8ae3837
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Mon Feb 1 20:10:07 2021 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Feb 1 20:10:07 2021 +0100
tests: increase required target version
Require 1.7.0 for raid0.
---
test/shell/lvdisplay-raid.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/shell/lvdisplay-raid.sh b/test/shell/lvdisplay-raid.sh
index 0c6bfba34..95205ba81 100644
--- a/test/shell/lvdisplay-raid.sh
+++ b/test/shell/lvdisplay-raid.sh
@@ -18,7 +18,7 @@ SKIP_WITH_LVMPOLLD=1
. lib/inittest
-aux have_raid 1 3 0 || skip
+aux have_raid 1 7 0 || skip
aux prepare_vg 6
get_devs
2 years, 8 months
main - tests: avoid killing test machines with kernel bug
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=6e8a32e4fd424ef5995...
Commit: 6e8a32e4fd424ef599549ac1036ce795a8ae3837
Parent: bfafd2b4e962b8b6bce3355843dec47b4842ed12
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Mon Feb 1 15:02:38 2021 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Feb 1 15:02:38 2021 +0100
tests: avoid killing test machines with kernel bug
Bug 1916891 still applies:
https://bugzilla.redhat.com/show_bug.cgi?id=1916891
---
test/shell/lvconvert-raid-reshape-stripes-load-reload.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/shell/lvconvert-raid-reshape-stripes-load-reload.sh b/test/shell/lvconvert-raid-reshape-stripes-load-reload.sh
index b79561fbb..3920da1a5 100644
--- a/test/shell/lvconvert-raid-reshape-stripes-load-reload.sh
+++ b/test/shell/lvconvert-raid-reshape-stripes-load-reload.sh
@@ -22,7 +22,7 @@ which mkfs.ext4 || skip
aux have_raid 1 13 2 || skip
case "$(uname -r)" in
- 5.[89]*|3.10.0-862*) die "Cannot run this test on unfixed kernel." ;;
+ 5.[891]*|3.10.0-862*) die "Cannot run this test on unfixed kernel." ;;
esac
mount_dir="mnt"
2 years, 8 months
main - tests: check for raid target support
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=bfafd2b4e962b8b6bce...
Commit: bfafd2b4e962b8b6bce3355843dec47b4842ed12
Parent: 026d94d882635f859814280573d1198203652d29
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Mon Feb 1 15:01:04 2021 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Feb 1 15:01:04 2021 +0100
tests: check for raid target support
---
test/shell/lvdisplay-raid.sh | 2 ++
1 file changed, 2 insertions(+)
diff --git a/test/shell/lvdisplay-raid.sh b/test/shell/lvdisplay-raid.sh
index 18ea9ae1e..0c6bfba34 100644
--- a/test/shell/lvdisplay-raid.sh
+++ b/test/shell/lvdisplay-raid.sh
@@ -18,6 +18,8 @@ SKIP_WITH_LVMPOLLD=1
. lib/inittest
+aux have_raid 1 3 0 || skip
+
aux prepare_vg 6
get_devs
2 years, 8 months
main - gcc: hide uninitialized warning with older gcc
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=026d94d882635f85981...
Commit: 026d94d882635f859814280573d1198203652d29
Parent: 48030389ceb43a6ae90568e5cf7475bc7715ca47
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Mon Feb 1 14:54:49 2021 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Feb 1 14:54:49 2021 +0100
gcc: hide uninitialized warning with older gcc
---
lib/raid/raid.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/raid/raid.c b/lib/raid/raid.c
index 126b22d43..6344200f5 100644
--- a/lib/raid/raid.c
+++ b/lib/raid/raid.c
@@ -472,7 +472,7 @@ static int _check_feature(const struct raid_feature *feature, uint32_t maj, uint
/* Check availability of raid10 taking data copies into consideration. */
static bool _raid10_is_available(const struct logical_volume *lv)
{
- uint32_t i, rebuilds_per_group, s;
+ uint32_t i, rebuilds_per_group = 0, s;
const uint32_t copies = 2; /* FIXME: we only support 2-way mirrors (i.e. 2 data copies) in RAID10 for now. */
struct lv_segment *seg = first_seg(lv); /* We only have one segment in RaidLVs for now. */
2 years, 8 months
main - libdm: add dm_tree_node_add_thin_pool_target_v1
by Zdenek Kabelac
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=48030389ceb43a6ae90...
Commit: 48030389ceb43a6ae90568e5cf7475bc7715ca47
Parent: 25b942a8acd35c44ea39ff1840d8c4af0bed12d6
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Mon Feb 1 14:06:31 2021 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Feb 1 14:52:32 2021 +0100
libdm: add dm_tree_node_add_thin_pool_target_v1
Supports thin-pool without crop.
---
WHATS_NEW_DM | 1 +
libdm/.exported_symbols.DM_1_02_172 | 1 +
libdm/libdevmapper.h | 16 ++++++++++++---
libdm/libdm-deptree.c | 39 +++++++++++++++++++++++++++----------
4 files changed, 44 insertions(+), 13 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 80ce15729..ba0129a55 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,6 @@
Version 1.02.177 -
====================================
+ Add dm_tree_node_add_thin_pool_target_v1 with crop_metadata support.
Version 1.02.175 - 08th January 2021
====================================
diff --git a/libdm/.exported_symbols.DM_1_02_172 b/libdm/.exported_symbols.DM_1_02_172
new file mode 100644
index 000000000..ed4cce7d6
--- /dev/null
+++ b/libdm/.exported_symbols.DM_1_02_172
@@ -0,0 +1 @@
+dm_tree_node_add_thin_pool_target_v1
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index a61ffe17e..26d64bf4e 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -1968,10 +1968,10 @@ int dm_tree_node_add_replicator_dev_target(struct dm_tree_node *node,
#define DM_THIN_MIN_DATA_BLOCK_SIZE (UINT32_C(128))
#define DM_THIN_MAX_DATA_BLOCK_SIZE (UINT32_C(2097152))
/*
- * Max supported size for thin pool metadata device (17112760320 bytes)
- * Limitation is hardcoded into the kernel and bigger device size
- * is not accepted.
+ * Max supported size for thin pool metadata device (17045913600 bytes)
* drivers/md/dm-thin-metadata.h THIN_METADATA_MAX_SECTORS
+ * But here DM_THIN_MAX_METADATA_SIZE got defined incorrectly
+ * Correct size is (UINT64_C(255) * ((1 << 14) - 64) * (4096 / (1 << 9)))
*/
#define DM_THIN_MAX_METADATA_SIZE (UINT64_C(255) * (1 << 14) * (4096 / (1 << 9)) - 256 * 1024)
@@ -1984,6 +1984,16 @@ int dm_tree_node_add_thin_pool_target(struct dm_tree_node *node,
uint64_t low_water_mark,
unsigned skip_block_zeroing);
+int dm_tree_node_add_thin_pool_target_v1(struct dm_tree_node *node,
+ uint64_t size,
+ uint64_t transaction_id,
+ const char *metadata_uuid,
+ const char *pool_uuid,
+ uint32_t data_block_size,
+ uint64_t low_water_mark,
+ unsigned skip_block_zeroing,
+ unsigned crop_metadata);
+
/* Supported messages for thin provision target */
typedef enum {
DM_THIN_MESSAGE_CREATE_SNAP, /* device_id, origin_id */
diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c
index f16db8568..336cbb696 100644
--- a/libdm/libdm-deptree.c
+++ b/libdm/libdm-deptree.c
@@ -3502,6 +3502,24 @@ int dm_tree_node_add_thin_pool_target(struct dm_tree_node *node,
uint32_t data_block_size,
uint64_t low_water_mark,
unsigned skip_block_zeroing)
+{
+ return dm_tree_node_add_thin_pool_target_v1(node, size, transaction_id,
+ metadata_uuid, pool_uuid,
+ data_block_size,
+ low_water_mark,
+ skip_block_zeroing,
+ 1);
+}
+
+int dm_tree_node_add_thin_pool_target_v1(struct dm_tree_node *node,
+ uint64_t size,
+ uint64_t transaction_id,
+ const char *metadata_uuid,
+ const char *pool_uuid,
+ uint32_t data_block_size,
+ uint64_t low_water_mark,
+ unsigned skip_block_zeroing,
+ unsigned crop_metadata)
{
struct load_segment *seg, *mseg;
uint64_t devsize = 0;
@@ -3529,17 +3547,18 @@ int dm_tree_node_add_thin_pool_target(struct dm_tree_node *node,
if (!_link_tree_nodes(node, seg->metadata))
return_0;
- /* FIXME: more complex target may need more tweaks */
- dm_list_iterate_items(mseg, &seg->metadata->props.segs) {
- devsize += mseg->size;
- if (devsize > DM_THIN_MAX_METADATA_SIZE) {
- log_debug_activation("Ignoring %" PRIu64 " of device.",
- devsize - DM_THIN_MAX_METADATA_SIZE);
- mseg->size -= (devsize - DM_THIN_MAX_METADATA_SIZE);
- devsize = DM_THIN_MAX_METADATA_SIZE;
- /* FIXME: drop remaining segs */
+ if (crop_metadata)
+ /* FIXME: more complex target may need more tweaks */
+ dm_list_iterate_items(mseg, &seg->metadata->props.segs) {
+ devsize += mseg->size;
+ if (devsize > DM_THIN_MAX_METADATA_SIZE) {
+ log_debug_activation("Ignoring %" PRIu64 " of device.",
+ devsize - DM_THIN_MAX_METADATA_SIZE);
+ mseg->size -= (devsize - DM_THIN_MAX_METADATA_SIZE);
+ devsize = DM_THIN_MAX_METADATA_SIZE;
+ /* FIXME: drop remaining segs */
+ }
}
- }
if (!(seg->pool = dm_tree_find_node_by_uuid(node->dtree, pool_uuid))) {
log_error("Missing pool uuid %s.", pool_uuid);
2 years, 8 months