import lvm2-2.03.12-6.el8
This commit is contained in:
parent
bd661a2856
commit
adcf59fcaf
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1 @@
|
||||
SOURCES/LVM2.2.03.11.tgz
|
||||
SOURCES/LVM2.2.03.12.tgz
|
||||
|
@ -1 +1 @@
|
||||
9484fd277914a85f330b4067aa222ee13f061189 SOURCES/LVM2.2.03.11.tgz
|
||||
6d74d987b474dd0b45f239eb6dcc050622ad6962 SOURCES/LVM2.2.03.12.tgz
|
||||
|
@ -1,15 +0,0 @@
|
||||
WHATS_NEW | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/WHATS_NEW b/WHATS_NEW
|
||||
index ffefc9d..3953c7e 100644
|
||||
--- a/WHATS_NEW
|
||||
+++ b/WHATS_NEW
|
||||
@@ -1,5 +1,7 @@
|
||||
Version 2.03.12 -
|
||||
===================================
|
||||
+ Fix problem with wiping of converted LVs.
|
||||
+ Fix memleak in scanning (2.03.11).
|
||||
Fix corner case allocation for thin-pools.
|
||||
|
||||
Version 2.03.11 - 08th January 2021
|
@ -1,47 +0,0 @@
|
||||
WHATS_NEW | 10 ++++++++--
|
||||
lib/metadata/lv_manip.c | 10 +++++++---
|
||||
2 files changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/WHATS_NEW b/WHATS_NEW
|
||||
index 452a631..fe347f7 100644
|
||||
--- a/WHATS_NEW
|
||||
+++ b/WHATS_NEW
|
||||
@@ -1,3 +1,7 @@
|
||||
+Version 2.03.12 -
|
||||
+===================================
|
||||
+ Fix corner case allocation for thin-pools.
|
||||
+
|
||||
Version 2.03.11 - 08th January 2021
|
||||
===================================
|
||||
Fix pvck handling MDA at offset different from 4096.
|
||||
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
|
||||
index 7046436..443d32c 100644
|
||||
--- a/lib/metadata/lv_manip.c
|
||||
+++ b/lib/metadata/lv_manip.c
|
||||
@@ -1850,11 +1850,13 @@ static uint32_t _mirror_log_extents(uint32_t region_size, uint32_t pe_size, uint
|
||||
|
||||
/* Is there enough total space or should we give up immediately? */
|
||||
static int _sufficient_pes_free(struct alloc_handle *ah, struct dm_list *pvms,
|
||||
- uint32_t allocated, uint32_t extents_still_needed)
|
||||
+ uint32_t allocated, uint32_t log_still_needed,
|
||||
+ uint32_t extents_still_needed)
|
||||
{
|
||||
uint32_t area_extents_needed = (extents_still_needed - allocated) * ah->area_count / ah->area_multiple;
|
||||
uint32_t parity_extents_needed = (extents_still_needed - allocated) * ah->parity_count / ah->area_multiple;
|
||||
- uint32_t metadata_extents_needed = ah->alloc_and_split_meta ? 0 : ah->metadata_area_count * RAID_METADATA_AREA_LEN + ah->log_len; /* One each */
|
||||
+ uint32_t metadata_extents_needed = (ah->alloc_and_split_meta ? 0 : ah->metadata_area_count * RAID_METADATA_AREA_LEN) +
|
||||
+ (log_still_needed ? ah->log_len : 0); /* One each */
|
||||
uint64_t total_extents_needed = (uint64_t)area_extents_needed + parity_extents_needed + metadata_extents_needed;
|
||||
uint32_t free_pes = pv_maps_size(pvms);
|
||||
|
||||
@@ -3359,7 +3361,9 @@ static int _allocate(struct alloc_handle *ah,
|
||||
old_allocated = alloc_state.allocated;
|
||||
log_debug_alloc("Trying allocation using %s policy.", get_alloc_string(alloc));
|
||||
|
||||
- if (!ah->approx_alloc && !_sufficient_pes_free(ah, pvms, alloc_state.allocated, ah->new_extents))
|
||||
+ if (!ah->approx_alloc && !_sufficient_pes_free(ah, pvms, alloc_state.allocated,
|
||||
+ alloc_state.log_area_count_still_needed,
|
||||
+ ah->new_extents))
|
||||
goto_out;
|
||||
|
||||
_init_alloc_parms(ah, &alloc_parms, alloc, prev_lvseg,
|
@ -1,107 +0,0 @@
|
||||
lib/metadata/cache_manip.c | 40 ++++++++++++++--------------------------
|
||||
lib/metadata/metadata-exported.h | 1 +
|
||||
tools/lvconvert.c | 1 +
|
||||
tools/lvcreate.c | 1 +
|
||||
4 files changed, 17 insertions(+), 26 deletions(-)
|
||||
|
||||
diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
|
||||
index 2c4cc92..90ebd94 100644
|
||||
--- a/lib/metadata/cache_manip.c
|
||||
+++ b/lib/metadata/cache_manip.c
|
||||
@@ -204,6 +204,7 @@ int update_cache_pool_params(struct cmd_context *cmd,
|
||||
unsigned attr,
|
||||
uint32_t pool_data_extents,
|
||||
uint32_t *pool_metadata_extents,
|
||||
+ struct logical_volume *metadata_lv,
|
||||
int *chunk_size_calc_method, uint32_t *chunk_size)
|
||||
{
|
||||
uint64_t min_meta_size;
|
||||
@@ -252,39 +253,26 @@ int update_cache_pool_params(struct cmd_context *cmd,
|
||||
if (!validate_cache_chunk_size(cmd, *chunk_size))
|
||||
return_0;
|
||||
|
||||
- min_meta_size = _cache_min_metadata_size((uint64_t) pool_data_extents * extent_size, *chunk_size);
|
||||
+ if ((uint64_t) *chunk_size > (uint64_t) pool_data_extents * extent_size) {
|
||||
+ log_error("Size of %s data volume cannot be smaller than chunk size %s.",
|
||||
+ segtype->name, display_size(cmd, *chunk_size));
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
- /* Round up to extent size */
|
||||
- if (min_meta_size % extent_size)
|
||||
- min_meta_size += extent_size - min_meta_size % extent_size;
|
||||
+ min_meta_size = _cache_min_metadata_size((uint64_t) pool_data_extents * extent_size, *chunk_size);
|
||||
+ min_meta_size = dm_round_up(min_meta_size, extent_size);
|
||||
|
||||
if (!pool_metadata_size)
|
||||
pool_metadata_size = min_meta_size;
|
||||
|
||||
- if (pool_metadata_size > (2 * DEFAULT_CACHE_POOL_MAX_METADATA_SIZE)) {
|
||||
- pool_metadata_size = 2 * DEFAULT_CACHE_POOL_MAX_METADATA_SIZE;
|
||||
- if (*pool_metadata_extents)
|
||||
- log_warn("WARNING: Maximum supported pool metadata size is %s.",
|
||||
- display_size(cmd, pool_metadata_size));
|
||||
- } else if (pool_metadata_size < min_meta_size) {
|
||||
- if (*pool_metadata_extents)
|
||||
- log_warn("WARNING: Minimum required pool metadata size is %s "
|
||||
- "(needs extra %s).",
|
||||
- display_size(cmd, min_meta_size),
|
||||
- display_size(cmd, min_meta_size - pool_metadata_size));
|
||||
- pool_metadata_size = min_meta_size;
|
||||
- }
|
||||
-
|
||||
- if (!(*pool_metadata_extents =
|
||||
- extents_from_size(cmd, pool_metadata_size, extent_size)))
|
||||
+ if (!update_pool_metadata_min_max(cmd, extent_size,
|
||||
+ min_meta_size,
|
||||
+ (2 * DEFAULT_CACHE_POOL_MAX_METADATA_SIZE),
|
||||
+ &pool_metadata_size,
|
||||
+ metadata_lv,
|
||||
+ pool_metadata_extents))
|
||||
return_0;
|
||||
|
||||
- if ((uint64_t) *chunk_size > (uint64_t) pool_data_extents * extent_size) {
|
||||
- log_error("Size of %s data volume cannot be smaller than chunk size %s.",
|
||||
- segtype->name, display_size(cmd, *chunk_size));
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
log_verbose("Preferred pool metadata size %s.",
|
||||
display_size(cmd, (uint64_t)*pool_metadata_extents * extent_size));
|
||||
|
||||
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
|
||||
index 0e57722..c0fa564 100644
|
||||
--- a/lib/metadata/metadata-exported.h
|
||||
+++ b/lib/metadata/metadata-exported.h
|
||||
@@ -1319,6 +1319,7 @@ int update_cache_pool_params(struct cmd_context *cmd,
|
||||
unsigned attr,
|
||||
uint32_t pool_data_extents,
|
||||
uint32_t *pool_metadata_extents,
|
||||
+ struct logical_volume *metadata_lv,
|
||||
int *chunk_size_calc_method, uint32_t *chunk_size);
|
||||
int validate_lv_cache_chunk_size(struct logical_volume *pool_lv, uint32_t chunk_size);
|
||||
int validate_lv_cache_create_pool(const struct logical_volume *pool_lv);
|
||||
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
|
||||
index ce90279..416e8a7 100644
|
||||
--- a/tools/lvconvert.c
|
||||
+++ b/tools/lvconvert.c
|
||||
@@ -3189,6 +3189,7 @@ static int _lvconvert_to_pool(struct cmd_context *cmd,
|
||||
pool_segtype, target_attr,
|
||||
lv->le_count,
|
||||
&meta_extents,
|
||||
+ metadata_lv,
|
||||
&chunk_calc,
|
||||
&chunk_size))
|
||||
goto_bad;
|
||||
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
|
||||
index 1ee9e14..1ce561f 100644
|
||||
--- a/tools/lvcreate.c
|
||||
+++ b/tools/lvcreate.c
|
||||
@@ -403,6 +403,7 @@ static int _update_extents_params(struct volume_group *vg,
|
||||
lp->segtype, lp->target_attr,
|
||||
lp->extents,
|
||||
&lp->pool_metadata_extents,
|
||||
+ NULL,
|
||||
&lp->thin_chunk_size_calc_policy,
|
||||
&lp->chunk_size))
|
||||
return_0;
|
@ -1,48 +0,0 @@
|
||||
From b3719266bd5e3a9e6737d6bda60e543121ddf343 Mon Sep 17 00:00:00 2001
|
||||
From: David Teigland <teigland@redhat.com>
|
||||
Date: Tue, 9 Feb 2021 09:47:08 -0600
|
||||
Subject: [PATCH] dev_get_primary_dev: fix invalid path check
|
||||
|
||||
Fix commit bee9f4efdd81 "filter-mpath: work with nvme devices"
|
||||
which removed setting the path for readlink.
|
||||
|
||||
(cherry picked from commit f74f94c2ddb1d33d75d325c959344a566a621fd5)
|
||||
|
||||
Conflicts:
|
||||
lib/device/dev-type.c
|
||||
---
|
||||
lib/device/dev-type.c | 11 ++++++++---
|
||||
1 file changed, 8 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c
|
||||
index 379afa8..1342e97 100644
|
||||
--- a/lib/device/dev-type.c
|
||||
+++ b/lib/device/dev-type.c
|
||||
@@ -434,7 +434,7 @@ static int _has_sys_partition(struct device *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",
|
||||
+ if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/partition",
|
||||
dm_sysfs_dir(), major, minor) < 0) {
|
||||
log_error("dm_snprintf partition failed");
|
||||
return 0;
|
||||
@@ -660,8 +660,13 @@ int dev_get_primary_dev(struct dev_types *dt, struct device *dev, dev_t *result)
|
||||
* - basename ../../block/md0/md0 = md0
|
||||
* Parent's 'dev' sysfs attribute = /sys/block/md0/dev
|
||||
*/
|
||||
- if ((size = readlink(dirname(path), temp_path, sizeof(temp_path) - 1)) < 0) {
|
||||
- log_sys_error("readlink", path);
|
||||
+ if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d",
|
||||
+ dm_sysfs_dir(), major, minor) < 0) {
|
||||
+ log_warn("WARNING: %s: major:minor sysfs path is too long.", dev_name(dev));
|
||||
+ return 0;
|
||||
+ }
|
||||
+ if ((size = readlink(path, temp_path, sizeof(temp_path) - 1)) < 0) {
|
||||
+ log_warn("WARNING: Readlink of %s failed.", path);
|
||||
goto out;
|
||||
}
|
||||
|
||||
--
|
||||
1.8.3.1
|
||||
|
@ -1,255 +0,0 @@
|
||||
lib/device/dev-cache.c | 161 ++++++++++++++++++++++++++++++++++++----------
|
||||
test/shell/dev-aliases.sh | 53 +++++++++++++++
|
||||
2 files changed, 179 insertions(+), 35 deletions(-)
|
||||
create mode 100644 test/shell/dev-aliases.sh
|
||||
|
||||
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
|
||||
index d5f18ff..8082efa 100644
|
||||
--- a/lib/device/dev-cache.c
|
||||
+++ b/lib/device/dev-cache.c
|
||||
@@ -1428,60 +1428,151 @@ struct device *dev_hash_get(const char *name)
|
||||
return (struct device *) dm_hash_lookup(_cache.names, name);
|
||||
}
|
||||
|
||||
+static void _remove_alias(struct device *dev, const char *name)
|
||||
+{
|
||||
+ struct dm_str_list *strl;
|
||||
+
|
||||
+ dm_list_iterate_items(strl, &dev->aliases) {
|
||||
+ if (!strcmp(strl->str, name)) {
|
||||
+ dm_list_del(&strl->list);
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Check that paths for this dev still refer to the same dev_t. This is known
|
||||
+ * to drop invalid paths in the case where lvm deactivates an LV, which causes
|
||||
+ * that LV path to go away, but that LV path is not removed from dev-cache (it
|
||||
+ * probably should be). Later a new path to a different LV is added to
|
||||
+ * dev-cache, where the new LV has the same major:minor as the previously
|
||||
+ * deactivated LV. The new LV will find the existing struct dev, and that
|
||||
+ * struct dev will have dev->aliases entries that refer to the name of the old
|
||||
+ * deactivated LV. Those old paths are all invalid and are dropped here.
|
||||
+ */
|
||||
+
|
||||
+static void _verify_aliases(struct device *dev, const char *newname)
|
||||
+{
|
||||
+ struct dm_str_list *strl, *strl2;
|
||||
+ struct stat st;
|
||||
+
|
||||
+ dm_list_iterate_items_safe(strl, strl2, &dev->aliases) {
|
||||
+ /* newname was just stat'd and added by caller */
|
||||
+ if (newname && !strcmp(strl->str, newname))
|
||||
+ continue;
|
||||
+
|
||||
+ if (stat(strl->str, &st) || (st.st_rdev != dev->dev)) {
|
||||
+ log_debug("Drop invalid path %s for %d:%d (new path %s).",
|
||||
+ strl->str, (int)MAJOR(dev->dev), (int)MINOR(dev->dev), newname ?: "");
|
||||
+ dm_hash_remove(_cache.names, strl->str);
|
||||
+ dm_list_del(&strl->list);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct dev_filter *f)
|
||||
{
|
||||
- struct stat buf;
|
||||
- struct device *d = (struct device *) dm_hash_lookup(_cache.names, name);
|
||||
- int info_available = 0;
|
||||
- int ret = 1;
|
||||
+ struct device *dev = (struct device *) dm_hash_lookup(_cache.names, name);
|
||||
+ struct stat st;
|
||||
+ int ret;
|
||||
|
||||
- if (d && (d->flags & DEV_REGULAR))
|
||||
- return d;
|
||||
+ /*
|
||||
+ * DEV_REGULAR means that is "dev" is actually a file, not a device.
|
||||
+ * FIXME: I don't think dev-cache is used for files any more and this
|
||||
+ * can be dropped?
|
||||
+ */
|
||||
+ if (dev && (dev->flags & DEV_REGULAR))
|
||||
+ return dev;
|
||||
+
|
||||
+ /*
|
||||
+ * The requested path is invalid, remove any dev-cache
|
||||
+ * info for it.
|
||||
+ */
|
||||
+ if (stat(name, &st)) {
|
||||
+ if (dev) {
|
||||
+ log_print("Device path %s is invalid for %d:%d %s.",
|
||||
+ name, (int)MAJOR(dev->dev), (int)MINOR(dev->dev), dev_name(dev));
|
||||
|
||||
- /* If the entry's wrong, remove it */
|
||||
- if (stat(name, &buf) < 0) {
|
||||
- if (d)
|
||||
dm_hash_remove(_cache.names, name);
|
||||
- log_sys_very_verbose("stat", name);
|
||||
- d = NULL;
|
||||
- } else
|
||||
- info_available = 1;
|
||||
|
||||
- if (d && (buf.st_rdev != d->dev)) {
|
||||
- dm_hash_remove(_cache.names, name);
|
||||
- d = NULL;
|
||||
- }
|
||||
+ _remove_alias(dev, name);
|
||||
|
||||
- if (!d) {
|
||||
- _insert(name, info_available ? &buf : NULL, 0, obtain_device_list_from_udev());
|
||||
- d = (struct device *) dm_hash_lookup(_cache.names, name);
|
||||
- if (!d) {
|
||||
- log_debug_devs("Device name not found in dev_cache repeat dev_cache_scan for %s", name);
|
||||
- dev_cache_scan();
|
||||
- d = (struct device *) dm_hash_lookup(_cache.names, name);
|
||||
+ /* Remove any other names in dev->aliases that are incorrect. */
|
||||
+ _verify_aliases(dev, NULL);
|
||||
}
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
- if (!d)
|
||||
+ if (!S_ISBLK(st.st_mode)) {
|
||||
+ log_debug("Not a block device %s.", name);
|
||||
return NULL;
|
||||
+ }
|
||||
|
||||
- if (d && (d->flags & DEV_REGULAR))
|
||||
- return d;
|
||||
+ /*
|
||||
+ * dev-cache has incorrect info for the requested path.
|
||||
+ * Remove incorrect info and then add new dev-cache entry.
|
||||
+ */
|
||||
+ if (dev && (st.st_rdev != dev->dev)) {
|
||||
+ log_print("Device path %s does not match %d:%d %s.",
|
||||
+ name, (int)MAJOR(dev->dev), (int)MINOR(dev->dev), dev_name(dev));
|
||||
+
|
||||
+ dm_hash_remove(_cache.names, name);
|
||||
+
|
||||
+ _remove_alias(dev, name);
|
||||
+
|
||||
+ /* Remove any other names in dev->aliases that are incorrect. */
|
||||
+ _verify_aliases(dev, NULL);
|
||||
+
|
||||
+ /* Add new dev-cache entry next. */
|
||||
+ dev = NULL;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Either add a new struct dev for st_rdev and name,
|
||||
+ * or add name as a new alias for an existing struct dev
|
||||
+ * for st_rdev.
|
||||
+ */
|
||||
+ if (!dev) {
|
||||
+ _insert_dev(name, st.st_rdev);
|
||||
|
||||
- if (f && !(d->flags & DEV_REGULAR)) {
|
||||
- ret = f->passes_filter(cmd, f, d, NULL);
|
||||
+ /* Get the struct dev that was just added. */
|
||||
+ dev = (struct device *) dm_hash_lookup(_cache.names, name);
|
||||
|
||||
- if (ret == -EAGAIN) {
|
||||
- log_debug_devs("get device by name defer filter %s", dev_name(d));
|
||||
- d->flags |= DEV_FILTER_AFTER_SCAN;
|
||||
- ret = 1;
|
||||
+ if (!dev) {
|
||||
+ log_error("Failed to get device %s", name);
|
||||
+ return NULL;
|
||||
}
|
||||
+
|
||||
+ _verify_aliases(dev, name);
|
||||
}
|
||||
|
||||
- if (f && !(d->flags & DEV_REGULAR) && !ret)
|
||||
+ /*
|
||||
+ * The caller passed a filter if they only want the dev if it
|
||||
+ * passes filters.
|
||||
+ */
|
||||
+
|
||||
+ if (!f)
|
||||
+ return dev;
|
||||
+
|
||||
+ ret = f->passes_filter(cmd, f, dev, NULL);
|
||||
+
|
||||
+ /*
|
||||
+ * This might happen if this function is called before
|
||||
+ * filters can do i/o. I don't think this will happen
|
||||
+ * any longer and this EAGAIN case can be removed.
|
||||
+ */
|
||||
+ if (ret == -EAGAIN) {
|
||||
+ log_debug_devs("dev_cache_get filter deferred %s", dev_name(dev));
|
||||
+ dev->flags |= DEV_FILTER_AFTER_SCAN;
|
||||
+ ret = 1;
|
||||
+ }
|
||||
+
|
||||
+ if (!ret) {
|
||||
+ log_debug_devs("dev_cache_get filter excludes %s", dev_name(dev));
|
||||
return NULL;
|
||||
+ }
|
||||
|
||||
- return d;
|
||||
+ return dev;
|
||||
}
|
||||
|
||||
static struct device *_dev_cache_seek_devt(dev_t dev)
|
||||
diff --git a/test/shell/dev-aliases.sh b/test/shell/dev-aliases.sh
|
||||
new file mode 100644
|
||||
index 0000000..c97cd5d
|
||||
--- /dev/null
|
||||
+++ b/test/shell/dev-aliases.sh
|
||||
@@ -0,0 +1,53 @@
|
||||
+#!/usr/bin/env bash
|
||||
+
|
||||
+# Copyright (C) 2012 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_devs 3
|
||||
+
|
||||
+vgcreate $vg $dev1 $dev2 $dev3
|
||||
+
|
||||
+#
|
||||
+# This lvconvert command will deactivate LV1, then internally create a new
|
||||
+# lv, lvol0, as a poolmetadataspare, then activate lvol0 to zero it.
|
||||
+# lvol0 will get the same major:minor that LV1 had. When the code gets
|
||||
+# the struct dev for lvol0, the new path to lvol0 is added to the
|
||||
+# dev-cache with it's major:minor. That major:minor already exists in
|
||||
+# dev-cache and has the stale LV1 as an alias. So the path to lvol0 is
|
||||
+# added as an alias to the existing struct dev (with the correct
|
||||
+# major:minor), but that struct dev has the stale LV1 path on its aliases
|
||||
+# list. The code will now validate all the aliases before returning the
|
||||
+# dev for lvol0, and will find that the LV1 path is stale and remove it
|
||||
+# from the aliases. That will prevent the stale path from being used for
|
||||
+# the dev in place of the new path.
|
||||
+#
|
||||
+# The preferred_name is set to /dev/mapper so that if the stale path still
|
||||
+# exists, that stale path would be used as the name for the dev, and the
|
||||
+# wiping code would fail to open that stale name.
|
||||
+#
|
||||
+
|
||||
+lvcreate -n $lv1 -L32M $vg $dev1
|
||||
+lvcreate -n $lv2 -L16M $vg $dev2
|
||||
+lvconvert -y --type cache-pool --poolmetadata $lv2 --cachemode writeback $vg/$lv1 --config='devices { preferred_names=["/dev/mapper/"] }'
|
||||
+lvremove -y $vg/$lv1
|
||||
+
|
||||
+lvcreate -n $lv1 -L32M $vg $dev1
|
||||
+lvcreate -n $lv2 -L16M $vg $dev2
|
||||
+lvconvert -y --type cache-pool --poolmetadata $lv2 $vg/$lv1
|
||||
+lvremove -y $vg/$lv1
|
||||
+
|
||||
+# TODO: add more validation of dev aliases being specified as command
|
||||
+# args in combination with various preferred_names settings.
|
||||
+
|
||||
+vgremove -ff $vg
|
@ -1,494 +0,0 @@
|
||||
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 896821d..379afa8 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,11 +614,18 @@ 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 fdf7791..8b94b79 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 a58bff8..816db31 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 85d1625..40e7df6 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), "%s/block/%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), "%s/block/%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.");
|
@ -1,24 +0,0 @@
|
||||
lib/metadata/integrity_manip.c | 10 +++++++---
|
||||
1 file changed, 7 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/lib/metadata/integrity_manip.c b/lib/metadata/integrity_manip.c
|
||||
index 53ab1b3..abf90d8 100644
|
||||
--- a/lib/metadata/integrity_manip.c
|
||||
+++ b/lib/metadata/integrity_manip.c
|
||||
@@ -773,9 +773,13 @@ int lv_add_integrity_to_raid(struct logical_volume *lv, struct integrity_setting
|
||||
bad:
|
||||
log_error("Failed to add integrity.");
|
||||
|
||||
- for (s = 0; s < revert_meta_lvs; s++) {
|
||||
- if (!lv_remove(imeta_lvs[s]))
|
||||
- log_error("New integrity metadata LV may require manual removal.");
|
||||
+ if (revert_meta_lvs) {
|
||||
+ for (s = 0; s < DEFAULT_RAID_MAX_IMAGES; s++) {
|
||||
+ if (!imeta_lvs[s])
|
||||
+ continue;
|
||||
+ if (!lv_remove(imeta_lvs[s]))
|
||||
+ log_error("New integrity metadata LV may require manual removal.");
|
||||
+ }
|
||||
}
|
||||
|
||||
if (!vg_write(vg) || !vg_commit(vg))
|
@ -1,19 +0,0 @@
|
||||
lib/label/label.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/lib/label/label.c b/lib/label/label.c
|
||||
index e067a6b..e6dd4a1 100644
|
||||
--- a/lib/label/label.c
|
||||
+++ b/lib/label/label.c
|
||||
@@ -1243,6 +1243,11 @@ int label_scan(struct cmd_context *cmd)
|
||||
free(devl);
|
||||
}
|
||||
|
||||
+ dm_list_iterate_items_safe(devl, devl2, &filtered_devs) {
|
||||
+ dm_list_del(&devl->list);
|
||||
+ free(devl);
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* If hints were not available/usable, then we scanned all devs,
|
||||
* and we now know which are PVs. Save this list of PVs we've
|
@ -1,66 +0,0 @@
|
||||
WHATS_NEW | 4 ++++
|
||||
lib/activate/activate.c | 5 +++++
|
||||
lib/activate/activate.h | 2 ++
|
||||
lib/metadata/lv_manip.c | 6 ++++++
|
||||
4 files changed, 17 insertions(+)
|
||||
|
||||
diff --git a/WHATS_NEW b/WHATS_NEW
|
||||
index 3953c7e..c8f869c 100644
|
||||
--- a/WHATS_NEW
|
||||
+++ b/WHATS_NEW
|
||||
@@ -1,5 +1,9 @@
|
||||
Version 2.03.12 -
|
||||
===================================
|
||||
+ Check if lvcreate passes read_only_volume_list with tags and skips zeroing.
|
||||
+ Limit pool metadata spare to 16GiB.
|
||||
+ Improves conversion and allocation of pool metadata.
|
||||
+ Support thin pool metadata 15.88GiB, adds 64MiB, thin_pool_crop_metadata=0.
|
||||
Fix problem with wiping of converted LVs.
|
||||
Fix memleak in scanning (2.03.11).
|
||||
Fix corner case allocation for thin-pools.
|
||||
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
|
||||
index 7ed6441..de866fb 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 3f4d128..53c8631 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 445c4ad..5ff64a3 100644
|
||||
--- a/lib/metadata/lv_manip.c
|
||||
+++ b/lib/metadata/lv_manip.c
|
||||
@@ -7976,6 +7976,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))
|
@ -1,29 +0,0 @@
|
||||
daemons/lvmlockd/lvmlockd-core.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/daemons/lvmlockd/lvmlockd-core.c b/daemons/lvmlockd/lvmlockd-core.c
|
||||
index fea8ee6..c4abf66 100644
|
||||
--- a/daemons/lvmlockd/lvmlockd-core.c
|
||||
+++ b/daemons/lvmlockd/lvmlockd-core.c
|
||||
@@ -896,8 +896,9 @@ static int read_adopt_file(struct list_head *vg_lockd)
|
||||
goto fail;
|
||||
|
||||
memset(vg_uuid, 0, sizeof(vg_uuid));
|
||||
+ memset(lm_type_str, 0, sizeof(lm_type_str));
|
||||
|
||||
- if (sscanf(adopt_line, "VG: %63s %64s %16s %64s",
|
||||
+ if (sscanf(adopt_line, "VG: %63s %64s %15s %64s",
|
||||
vg_uuid, ls->vg_name, lm_type_str, ls->vg_args) != 4) {
|
||||
goto fail;
|
||||
}
|
||||
@@ -916,8 +917,9 @@ static int read_adopt_file(struct list_head *vg_lockd)
|
||||
r->type = LD_RT_LV;
|
||||
|
||||
memset(vg_uuid, 0, sizeof(vg_uuid));
|
||||
+ memset(mode, 0, sizeof(mode));
|
||||
|
||||
- if (sscanf(adopt_line, "LV: %64s %64s %s %8s %u",
|
||||
+ if (sscanf(adopt_line, "LV: %64s %64s %s %7s %u",
|
||||
vg_uuid, r->name, r->lv_args, mode, &r->version) != 5) {
|
||||
goto fail;
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
man/lvconvert.8_pregen | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/man/lvconvert.8_pregen b/man/lvconvert.8_pregen
|
||||
index a47ccac..170eec8 100644
|
||||
--- a/man/lvconvert.8_pregen
|
||||
+++ b/man/lvconvert.8_pregen
|
||||
@@ -772,6 +772,10 @@ Add a cache to an LV, using a specified cache device.
|
||||
.br
|
||||
.RS 4
|
||||
.ad l
|
||||
+[ \fB-c\fP|\fB--chunksize\fP \fISize\fP[k|UNIT] ]
|
||||
+.ad b
|
||||
+.br
|
||||
+.ad l
|
||||
[ \fB--cachesize\fP \fISize\fP[m|UNIT] ]
|
||||
.ad b
|
||||
.br
|
@ -1,86 +0,0 @@
|
||||
man/lvmthin.7_main | 37 +++++++++++++++++++++++++------------
|
||||
1 file changed, 25 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/man/lvmthin.7_main b/man/lvmthin.7_main
|
||||
index ce23431..e6f1d63 100644
|
||||
--- a/man/lvmthin.7_main
|
||||
+++ b/man/lvmthin.7_main
|
||||
@@ -394,7 +394,7 @@ the pmspare LV.
|
||||
\&
|
||||
|
||||
If thin pool metadata is damaged, it may be repairable.
|
||||
-Checking and repairing thin pool metadata is analagous to
|
||||
+Checking and repairing thin pool metadata is analogous to
|
||||
running fsck/repair on a file system.
|
||||
|
||||
When a thin pool LV is activated, lvm runs the thin_check command
|
||||
@@ -437,14 +437,24 @@ copy to the VG's pmspare LV.
|
||||
If step 1 is successful, the thin pool metadata LV is replaced
|
||||
with the pmspare LV containing the corrected metadata.
|
||||
The previous thin pool metadata LV, containing the damaged metadata,
|
||||
-becomes visible with the new name ThinPoolLV_tmetaN (where N is 0,1,...).
|
||||
-
|
||||
-If the repair works, the thin pool LV and its thin LVs can be activated,
|
||||
-and the LV containing the damaged thin pool metadata can be removed.
|
||||
-It may be useful to move the new metadata LV (previously pmspare) to a
|
||||
-better PV.
|
||||
-
|
||||
-If the repair does not work, the thin pool LV and its thin LVs are lost.
|
||||
+becomes visible with the new name ThinPoolLV_metaN (where N is 0,1,...).
|
||||
+
|
||||
+If the repair works, the thin pool LV and its thin LVs can be activated.
|
||||
+User should manually check if repaired thin pool kernel metadata
|
||||
+has all data for all lvm2 known LVs by individual activation of
|
||||
+every thin LV. When all works, user should continue with fsck of
|
||||
+all filesystems present these such volumes.
|
||||
+Once the thin pool is considered fully functional user may remove ThinPoolLV_metaN
|
||||
+(the LV containing the damaged thin pool metadata) for possible
|
||||
+space reuse.
|
||||
+For a better performance it may be useful to pvmove the new repaired metadata LV
|
||||
+(written to previous pmspare volume) to a better PV (i.e. SSD)
|
||||
+
|
||||
+If the repair operation fails, the thin pool LV and its thin LVs
|
||||
+are not accessible and it may be necessary to restore their content
|
||||
+from a backup. In such case the content of unmodified original damaged
|
||||
+ThinPoolLV_metaN volume can be used by your support for more
|
||||
+advanced recovery methods.
|
||||
|
||||
If metadata is manually restored with thin_repair directly,
|
||||
the pool metadata LV can be manually swapped with another LV
|
||||
@@ -452,6 +462,9 @@ containing new metadata:
|
||||
|
||||
.B lvconvert --thinpool VG/ThinPoolLV --poolmetadata VG/NewThinMetaLV
|
||||
|
||||
+Note: Thin pool metadata is compact so even small corruptions
|
||||
+in them may result in significant portions of mappings to be lost.
|
||||
+It is recommended to use fast resilient storage for them.
|
||||
|
||||
.SS Activation of thin snapshots
|
||||
|
||||
@@ -549,7 +562,7 @@ Command to extend thin pool data space:
|
||||
.fi
|
||||
|
||||
Other methods of increasing free data space in a thin pool LV
|
||||
-include removing a thin LV and its related snapsots, or running
|
||||
+include removing a thin LV and its related snapshots, or running
|
||||
fstrim on the file system using a thin LV.
|
||||
|
||||
|
||||
@@ -689,7 +702,7 @@ with two configuration settings:
|
||||
.B thin_pool_autoextend_threshold
|
||||
.br
|
||||
is a percentage full value that defines when the thin pool LV should be
|
||||
-extended. Setting this to 100 disables automatic extention. The minimum
|
||||
+extended. Setting this to 100 disables automatic extension. The minimum
|
||||
value is 50.
|
||||
|
||||
.BR lvm.conf (5)
|
||||
@@ -716,7 +729,7 @@ the --ignoremonitoring option can be used. With this option, the command
|
||||
will not ask dmeventd to monitor the thin pool LV.
|
||||
|
||||
.IP \[bu]
|
||||
-Setting thin_pool_autoextend_threshould to 100 disables automatic
|
||||
+Setting thin_pool_autoextend_threshold to 100 disables automatic
|
||||
extension of thin pool LVs, even if they are being monitored by dmeventd.
|
||||
|
||||
.P
|
@ -1,39 +0,0 @@
|
||||
lib/metadata/pool_manip.c | 10 +++++++++-
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/metadata/pool_manip.c b/lib/metadata/pool_manip.c
|
||||
index b67882e..1975cb4 100644
|
||||
--- a/lib/metadata/pool_manip.c
|
||||
+++ b/lib/metadata/pool_manip.c
|
||||
@@ -697,6 +697,8 @@ static struct logical_volume *_alloc_pool_metadata_spare(struct volume_group *vg
|
||||
int handle_pool_metadata_spare(struct volume_group *vg, uint32_t extents,
|
||||
struct dm_list *pvh, int poolmetadataspare)
|
||||
{
|
||||
+ /* Max usable size of any spare volume is currently 16GiB rouned to extent size */
|
||||
+ const uint64_t MAX_SIZE = (UINT64_C(2 * 16) * 1024 * 1024 + vg->extent_size - 1) / vg->extent_size;
|
||||
struct logical_volume *lv = vg->pool_metadata_spare_lv;
|
||||
uint32_t seg_mirrors;
|
||||
struct lv_segment *seg;
|
||||
@@ -706,8 +708,11 @@ int handle_pool_metadata_spare(struct volume_group *vg, uint32_t extents,
|
||||
/* Find maximal size of metadata LV */
|
||||
dm_list_iterate_items(lvl, &vg->lvs)
|
||||
if (lv_is_pool_metadata(lvl->lv) &&
|
||||
- (lvl->lv->le_count > extents))
|
||||
+ (lvl->lv->le_count > extents)) {
|
||||
extents = lvl->lv->le_count;
|
||||
+ if (extents >= MAX_SIZE)
|
||||
+ break;
|
||||
+ }
|
||||
|
||||
if (!poolmetadataspare) {
|
||||
/* TODO: Not showing when lvm.conf would define 'n' ? */
|
||||
@@ -718,6 +723,9 @@ int handle_pool_metadata_spare(struct volume_group *vg, uint32_t extents,
|
||||
return 1;
|
||||
}
|
||||
|
||||
+ if (extents > MAX_SIZE)
|
||||
+ extents = MAX_SIZE;
|
||||
+
|
||||
if (!lv) {
|
||||
if (!_alloc_pool_metadata_spare(vg, extents, pvh))
|
||||
return_0;
|
@ -1,24 +0,0 @@
|
||||
tools/pvck.c | 10 +++++++---
|
||||
1 file changed, 7 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/tools/pvck.c b/tools/pvck.c
|
||||
index c36e182..88350de 100644
|
||||
--- a/tools/pvck.c
|
||||
+++ b/tools/pvck.c
|
||||
@@ -1140,9 +1140,13 @@ static int _dump_label_and_pv_header(struct cmd_context *cmd, uint64_t labelsect
|
||||
*mda1_offset = xlate64(dlocn->offset);
|
||||
*mda1_size = xlate64(dlocn->size);
|
||||
|
||||
- if (*mda1_offset != 4096) {
|
||||
- log_print("CHECK: pv_header.disk_locn[%d].offset expected 4096 # for first mda", di);
|
||||
- bad++;
|
||||
+ /*
|
||||
+ * mda1 offset is page size from machine that created it,
|
||||
+ * warn if it's not one of the expected page sizes.
|
||||
+ */
|
||||
+ if ((*mda1_offset != 4096) && (*mda1_offset != 8192) && (*mda1_offset != 65536)) {
|
||||
+ log_print("WARNING: pv_header.disk_locn[%d].offset %llu is unexpected # for first mda",
|
||||
+ di, (unsigned long long)*mda1_offset);
|
||||
}
|
||||
} else {
|
||||
*mda2_offset = xlate64(dlocn->offset);
|
@ -1,19 +0,0 @@
|
||||
test/shell/tags.sh | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/test/shell/tags.sh b/test/shell/tags.sh
|
||||
index fd1b332..5b636a8 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
|
@ -1,98 +0,0 @@
|
||||
test/shell/thin-16g.sh | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 88 insertions(+)
|
||||
create mode 100644 test/shell/thin-16g.sh
|
||||
|
||||
diff --git a/test/shell/thin-16g.sh b/test/shell/thin-16g.sh
|
||||
new file mode 100644
|
||||
index 0000000..ee7e22e
|
||||
--- /dev/null
|
||||
+++ b/test/shell/thin-16g.sh
|
||||
@@ -0,0 +1,88 @@
|
||||
+#!/usr/bin/env bash
|
||||
+
|
||||
+# Copyright (C) 2021 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 usability of 16g thin pool metadata LV
|
||||
+
|
||||
+
|
||||
+SKIP_WITH_LVMPOLLD=1
|
||||
+
|
||||
+. lib/inittest
|
||||
+
|
||||
+aux have_thin 1 0 0 || skip
|
||||
+
|
||||
+aux prepare_vg 1 50000
|
||||
+
|
||||
+lvcreate -T -L10 --poolmetadatasize 16g $vg/pool
|
||||
+check lv_field $vg/pool_tmeta size "<15.88g"
|
||||
+lvremove -f $vg
|
||||
+
|
||||
+# Cropped way
|
||||
+lvcreate -T -L10 --poolmetadatasize 16g --config 'allocation/thin_pool_crop_metadata=1' $vg/pool
|
||||
+check lv_field $vg/pool_tmeta size "15.81g"
|
||||
+lvremove -f $vg
|
||||
+
|
||||
+lvcreate -L16G -n meta $vg
|
||||
+lvcreate -L10 -n pool $vg
|
||||
+lvconvert --yes --thinpool $vg/pool --poolmetadata meta
|
||||
+# Uncropped size 33554432 sectors - 16GiB
|
||||
+dmsetup table ${vg}-pool_tmeta | grep 33554432
|
||||
+lvremove -f $vg
|
||||
+
|
||||
+# Uses 20G metadata volume, but crops the size in DM table
|
||||
+lvcreate -L20G -n meta $vg
|
||||
+lvcreate -L10 -n pool $vg
|
||||
+lvconvert --yes --thinpool $vg/pool --poolmetadata meta --config 'allocation/thin_pool_crop_metadata=1'
|
||||
+check lv_field $vg/lvol0_pmspare size "16.00g"
|
||||
+# Size should be cropped to 33161216 sectors ~15.81GiB
|
||||
+dmsetup table ${vg}-pool_tmeta | grep 33161216
|
||||
+
|
||||
+# Also size remains unchanged with activation has no cropping,
|
||||
+# but metadata have no CROP_METADATA flag set
|
||||
+lvchange -an $vg
|
||||
+lvchange -ay $vg
|
||||
+# Size still stays cropped to 33161216 sectors ~15.81GiB
|
||||
+dmsetup table ${vg}-pool_tmeta | grep 33161216
|
||||
+lvremove -f $vg
|
||||
+
|
||||
+# Minimal size is 2M
|
||||
+lvcreate -L1M -n meta $vg
|
||||
+lvcreate -L10 -n pool $vg
|
||||
+not lvconvert --yes --thinpool $vg/pool --poolmetadata meta
|
||||
+lvremove -f $vg
|
||||
+
|
||||
+# Uses 20G metadata volume, but crops the size in DM table
|
||||
+lvcreate -L1 --poolmetadatasize 10G -T $vg/pool
|
||||
+lvresize -L+10G $vg/pool_tmeta --config 'allocation/thin_pool_crop_metadata=1'
|
||||
+check lv_field $vg/lvol0_pmspare size "15.81g"
|
||||
+# Size should be cropped to 33161216 sectors ~15.81GiB
|
||||
+dmsetup table ${vg}-pool_tmeta | grep 33161216
|
||||
+
|
||||
+# Without cropping we can grop to ~15.88GiB
|
||||
+lvresize -L+10G $vg/pool_tmeta
|
||||
+check lv_field $vg/lvol0_pmspare size "<15.88g"
|
||||
+lvremove -f $vg
|
||||
+
|
||||
+# User has already 'bigger' metadata and wants them uncropped
|
||||
+lvcreate -L16G -n meta $vg
|
||||
+lvcreate -L10 -n pool $vg
|
||||
+lvconvert --yes --thinpool $vg/pool --poolmetadata meta --config 'allocation/thin_pool_crop_metadata=1'
|
||||
+
|
||||
+# No change with cropping
|
||||
+lvresize -l+1 $vg/pool_tmeta --config 'allocation/thin_pool_crop_metadata=1'
|
||||
+dmsetup table ${vg}-pool_tmeta | grep 33161216
|
||||
+
|
||||
+# Resizes to 'uncropped' size 16GiB with ANY size
|
||||
+lvresize -l+1 $vg/pool_tmeta
|
||||
+dmsetup table ${vg}-pool_tmeta | grep 33554432
|
||||
+check lv_field $vg/pool_tmeta size "16.00g"
|
||||
+
|
||||
+vgremove -ff $vg
|
@ -1,78 +0,0 @@
|
||||
test/shell/thin-zero-meta.sh | 68 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 68 insertions(+)
|
||||
create mode 100644 test/shell/thin-zero-meta.sh
|
||||
|
||||
diff --git a/test/shell/thin-zero-meta.sh b/test/shell/thin-zero-meta.sh
|
||||
new file mode 100644
|
||||
index 0000000..6a15a73
|
||||
--- /dev/null
|
||||
+++ b/test/shell/thin-zero-meta.sh
|
||||
@@ -0,0 +1,68 @@
|
||||
+#!/usr/bin/env bash
|
||||
+
|
||||
+# Copyright (C) 2021 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 how zeroing of thin-pool metadata works
|
||||
+
|
||||
+SKIP_WITH_LVMLOCKD=1
|
||||
+SKIP_WITH_LVMPOLLD=1
|
||||
+
|
||||
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
|
||||
+
|
||||
+. lib/inittest
|
||||
+
|
||||
+#
|
||||
+# Main
|
||||
+#
|
||||
+aux have_thin 1 3 0 || skip
|
||||
+aux have_cache 1 3 0 || skip
|
||||
+
|
||||
+aux prepare_vg 3 40000
|
||||
+
|
||||
+# Create mostly-zero devs only front of it has some 'real' back-end
|
||||
+aux zero_dev "$dev1" "$(( $(get first_extent_sector "$dev1") + 8192 )):"
|
||||
+aux zero_dev "$dev2" "$(( $(get first_extent_sector "$dev2") + 8192 )):"
|
||||
+aux zero_dev "$dev3" "$(( $(get first_extent_sector "$dev3") + 8192 )):"
|
||||
+
|
||||
+# Prepare randomly filled 4M LV on dev2
|
||||
+lvcreate -L16G -n $lv1 $vg "$dev2"
|
||||
+dd if=/dev/urandom of="$DM_DEV_DIR/$vg/$lv1" bs=1M count=4 oflag=direct || true
|
||||
+lvremove -f $vg
|
||||
+
|
||||
+for i in 0 1
|
||||
+do
|
||||
+ aux lvmconf "allocation/zero_metadata = $i"
|
||||
+
|
||||
+ # Lvm2 should allocate metadata on dev2
|
||||
+ lvcreate -T -L10G --poolmetadatasize 16G $vg/pool "$dev1" "$dev2"
|
||||
+ lvchange -an $vg
|
||||
+
|
||||
+ lvs -ao+seg_pe_ranges $vg
|
||||
+ lvchange -ay $vg/pool_tmeta --yes
|
||||
+
|
||||
+ # Skip past 1.2M which is 'created' by thin-pool initialization
|
||||
+ hexdump -C -n 200 -s 2000000 "$DM_DEV_DIR/$vg/pool_tmeta" | tee out
|
||||
+
|
||||
+ # When fully zeroed, it should be zero - so almost no output from hexdump
|
||||
+ case "$i" in
|
||||
+ 0) test $(wc -l < out) -ge 10 ;; # should not be zeroed
|
||||
+ 1) test $(wc -l < out) -le 10 ;; # should be zeroed
|
||||
+ esac
|
||||
+
|
||||
+ lvremove -f $vg/pool
|
||||
+done
|
||||
+
|
||||
+# Check lvm2 spots error during full zeroing of metadata device
|
||||
+aux error_dev "$dev2" "$(( $(get first_extent_sector "$dev2") + 32 )):"
|
||||
+not lvcreate -T -L10G --poolmetadatasize 16G $vg/pool "$dev1" "$dev2" |& tee err
|
||||
+grep "Failed to initialize logical volume" err
|
||||
+
|
||||
+vgremove -ff $vg
|
@ -1,47 +0,0 @@
|
||||
test/shell/lvcreate-thin-limits.sh | 30 ++++++++++++++++++++++++++----
|
||||
1 file changed, 26 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/test/shell/lvcreate-thin-limits.sh b/test/shell/lvcreate-thin-limits.sh
|
||||
index 6a9c33d..5dcc160 100644
|
||||
--- a/test/shell/lvcreate-thin-limits.sh
|
||||
+++ b/test/shell/lvcreate-thin-limits.sh
|
||||
@@ -27,13 +27,35 @@ aux can_use_16T || skip
|
||||
aux have_thin 1 0 0 || skip
|
||||
which mkfs.ext4 || skip
|
||||
|
||||
-aux prepare_pvs 1 16777216
|
||||
+# 16T device
|
||||
+aux prepare_pvs 2 8388608
|
||||
get_devs
|
||||
|
||||
-vgcreate $SHARED -s 4K "$vg" "${DEVICES[@]}"
|
||||
+# gives 16777215M device
|
||||
+vgcreate $SHARED -s 4M "$vg" "${DEVICES[@]}"
|
||||
|
||||
-not lvcreate -T -L15.995T --poolmetadatasize 5G $vg/pool
|
||||
+# For 1st. pass only single PV
|
||||
+lvcreate -l100%PV --name $lv1 $vg "$dev2"
|
||||
|
||||
-lvs -ao+seg_pe_ranges $vg
|
||||
+for i in 1 0
|
||||
+do
|
||||
+ SIZE=$(get vg_field "$vg" vg_free --units m)
|
||||
+ SIZE=${SIZE%%\.*}
|
||||
+
|
||||
+ # ~16T - 2 * 5G + something -> should not fit
|
||||
+ not lvcreate -Zn -T -L$(( SIZE - 2 * 5 * 1024 + 1 )) --poolmetadatasize 5G $vg/pool
|
||||
+
|
||||
+ check vg_field "$vg" lv_count "$i"
|
||||
+
|
||||
+ # Should fit data + metadata + pmspare
|
||||
+ lvcreate -Zn -T -L$(( SIZE - 2 * 5 * 1024 )) --poolmetadatasize 5G $vg/pool
|
||||
+
|
||||
+ check vg_field "$vg" vg_free "0"
|
||||
+
|
||||
+ lvs -ao+seg_pe_ranges $vg
|
||||
+
|
||||
+ # Remove everything for 2nd. pass
|
||||
+ lvremove -ff $vg
|
||||
+done
|
||||
|
||||
vgremove -ff $vg
|
@ -1,77 +0,0 @@
|
||||
test/shell/lvconvert-thin.sh | 2 +-
|
||||
test/shell/lvcreate-cache.sh | 12 +++++-------
|
||||
test/shell/lvcreate-thin-big.sh | 10 +++++-----
|
||||
3 files changed, 11 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/test/shell/lvconvert-thin.sh b/test/shell/lvconvert-thin.sh
|
||||
index 1319655..ee85691 100644
|
||||
--- a/test/shell/lvconvert-thin.sh
|
||||
+++ b/test/shell/lvconvert-thin.sh
|
||||
@@ -128,7 +128,7 @@ lvcreate -L1T -n $lv1 $vg
|
||||
lvcreate -L32G -n $lv2 $vg
|
||||
# Warning about bigger then needed
|
||||
lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 2>&1 | tee err
|
||||
-grep "WARNING: Maximum" err
|
||||
+grep -i "maximum" err
|
||||
lvremove -f $vg
|
||||
|
||||
|
||||
diff --git a/test/shell/lvcreate-cache.sh b/test/shell/lvcreate-cache.sh
|
||||
index 2c46e21..4d9d75e 100644
|
||||
--- a/test/shell/lvcreate-cache.sh
|
||||
+++ b/test/shell/lvcreate-cache.sh
|
||||
@@ -27,7 +27,6 @@ aux prepare_vg 5 80000
|
||||
|
||||
aux lvmconf 'global/cache_disabled_features = [ "policy_smq" ]'
|
||||
|
||||
-
|
||||
#######################
|
||||
# Cache_Pool creation #
|
||||
#######################
|
||||
@@ -173,17 +172,16 @@ dmsetup table ${vg}-$lv1 | grep cache # ensure it is loaded in kernel
|
||||
|
||||
lvremove -f $vg
|
||||
|
||||
-
|
||||
# Check minimum cache pool metadata size
|
||||
-lvcreate -l 1 --type cache-pool --poolmetadatasize 1 $vg 2>out
|
||||
-grep "WARNING: Minimum" out
|
||||
+lvcreate -l 1 --type cache-pool --poolmetadatasize 1 $vg 2>&1 | tee out
|
||||
+grep -i "minimal" out
|
||||
+
|
||||
|
||||
# FIXME: This test is failing in allocator with smaller VG sizes
|
||||
-lvcreate -l 1 --type cache-pool --poolmetadatasize 17G $vg 2>out
|
||||
-grep "WARNING: Maximum" out
|
||||
+lvcreate -l 1 --type cache-pool --poolmetadatasize 17G $vg 2>&1 | tee out
|
||||
+grep -i "maximum" out
|
||||
|
||||
lvremove -f $vg
|
||||
-
|
||||
########################################
|
||||
# Cache conversion and r/w permissions #
|
||||
########################################
|
||||
diff --git a/test/shell/lvcreate-thin-big.sh b/test/shell/lvcreate-thin-big.sh
|
||||
index 0b622b7..2549035 100644
|
||||
--- a/test/shell/lvcreate-thin-big.sh
|
||||
+++ b/test/shell/lvcreate-thin-big.sh
|
||||
@@ -31,14 +31,14 @@ vgcreate $SHARED -s 64K "$vg" "${DEVICES[@]}"
|
||||
|
||||
# Size 0 is not valid
|
||||
invalid lvcreate -L4M --chunksize 128 --poolmetadatasize 0 -T $vg/pool1 2>out
|
||||
-lvcreate -Zn -L4M --chunksize 128 --poolmetadatasize 16k -T $vg/pool1 2>out
|
||||
-grep "WARNING: Minimum" out
|
||||
+lvcreate -Zn -L4M --chunksize 128 --poolmetadatasize 16k -T $vg/pool1 2>&1 >out
|
||||
+grep -i "minimal" out
|
||||
# FIXME: metadata allocation fails, if PV doesn't have at least 16GB
|
||||
# i.e. pool metadata device cannot be multisegment
|
||||
-lvcreate -Zn -L4M --chunksize 64k --poolmetadatasize 17G -T $vg/pool2 2>out
|
||||
-grep "WARNING: Maximum" out
|
||||
+lvcreate -Zn -L4M --chunksize 64k --poolmetadatasize 17G -T $vg/pool2 2>&1 >out
|
||||
+grep "maximum" out
|
||||
check lv_field $vg/pool1_tmeta size "2.00m"
|
||||
-check lv_field $vg/pool2_tmeta size "15.81g"
|
||||
+check lv_field $vg/pool2_tmeta size "<15.88g"
|
||||
|
||||
# Check we do report correct percent values.
|
||||
lvcreate --type zero -L3G $vg -n pool3
|
@ -1,694 +0,0 @@
|
||||
conf/example.conf.in | 7 +++
|
||||
device_mapper/all.h | 16 +++++--
|
||||
device_mapper/libdm-deptree.c | 39 ++++++++++++-----
|
||||
lib/activate/dev_manager.c | 8 ++--
|
||||
lib/config/config_settings.h | 5 +++
|
||||
lib/config/defaults.h | 2 +
|
||||
lib/format_text/flags.c | 1 +
|
||||
lib/metadata/lv_manip.c | 31 ++++++++++++++
|
||||
lib/metadata/merge.c | 2 +
|
||||
lib/metadata/metadata-exported.h | 11 +++++
|
||||
lib/metadata/metadata.h | 13 ++++++
|
||||
lib/metadata/pool_manip.c | 46 ++++++++++++++++++++
|
||||
lib/metadata/thin_manip.c | 92 ++++++++++++++++++++++++++--------------
|
||||
lib/thin/thin.c | 22 +++++++---
|
||||
man/lvmthin.7_main | 10 ++++-
|
||||
tools/lvconvert.c | 4 ++
|
||||
tools/lvcreate.c | 2 +
|
||||
17 files changed, 256 insertions(+), 55 deletions(-)
|
||||
|
||||
diff --git a/conf/example.conf.in b/conf/example.conf.in
|
||||
index d149ed9..107a071 100644
|
||||
--- a/conf/example.conf.in
|
||||
+++ b/conf/example.conf.in
|
||||
@@ -494,6 +494,13 @@ allocation {
|
||||
# This configuration option has an automatic default value.
|
||||
# thin_pool_metadata_require_separate_pvs = 0
|
||||
|
||||
+ # Configuration option allocation/thin_pool_crop_metadata.
|
||||
+ # Older version of lvm2 cropped pool's metadata size to 15.81 GiB.
|
||||
+ # This is slightly less then the actual maximum 15.88 GiB.
|
||||
+ # For compatibility with older version and use of cropped size set to 1.
|
||||
+ # This configuration option has an automatic default value.
|
||||
+ # thin_pool_crop_metadata = 0
|
||||
+
|
||||
# Configuration option allocation/thin_pool_zero.
|
||||
# Thin pool data chunks are zeroed before they are first used.
|
||||