Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=0c1316cda876849d5d137…
Commit: 0c1316cda876849d5d1375d40e8cdc08db37c2b5
Parent: 56a295f78c4638e201ad78a8b25fd7874f2d905d
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Nov 26 11:56:51 2019 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Nov 26 16:52:28 2019 -0600
scanning: optimize by checking text offset and checksum
After the VG lock is taken for vg_read, reread the mda_header
and compare the metadata text offset and checksum to what was
seen during label scan. If it is unchanged, then the metadata
has not changed since the label scan, and the metadata does not
need to be reread under the lock for command processing.
For commands that do not make changes (e.g. reporting), the
mda_header is reread and checked on one mda to decide if the
full metadata rereading can be skipped. For other commands
(e.g. modifying the vg) the mda_header is reread and checked
from all PVs. (These could probably just check one mda also.)
---
lib/cache/lvmcache.c | 24 ++++++++
lib/cache/lvmcache.h | 4 +
lib/format_text/format-text.c | 12 ++++
lib/format_text/layout.h | 3 +-
lib/format_text/text_label.c | 2 +-
lib/metadata/metadata.c | 130 ++++++++++++++++++++++++++++++++++++++--
lib/metadata/metadata.h | 2 +
7 files changed, 168 insertions(+), 9 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 6224fe0..2c8c614 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -238,6 +238,30 @@ void lvmcache_get_bad_mdas(struct cmd_context *cmd,
}
}
+void lvmcache_get_mdas(struct cmd_context *cmd,
+ const char *vgname, const char *vgid,
+ struct dm_list *mda_list)
+{
+ struct lvmcache_vginfo *vginfo;
+ struct lvmcache_info *info;
+ struct mda_list *mdal;
+ struct metadata_area *mda, *mda2;
+
+ if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid))) {
+ log_error(INTERNAL_ERROR "lvmcache_get_mdas no vginfo %s", vgname);
+ return;
+ }
+
+ dm_list_iterate_items(info, &vginfo->infos) {
+ dm_list_iterate_items_safe(mda, mda2, &info->mdas) {
+ if (!(mdal = zalloc(sizeof(*mdal))))
+ continue;
+ mdal->mda = mda;
+ dm_list_add(mda_list, &mdal->list);
+ }
+ }
+}
+
static void _vginfo_attach_info(struct lvmcache_vginfo *vginfo,
struct lvmcache_info *info)
{
diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h
index d614e54..0c8c789 100644
--- a/lib/cache/lvmcache.h
+++ b/lib/cache/lvmcache.h
@@ -216,4 +216,8 @@ void lvmcache_get_bad_mdas(struct cmd_context *cmd,
const char *vgname, const char *vgid,
struct dm_list *bad_mda_list);
+void lvmcache_get_mdas(struct cmd_context *cmd,
+ const char *vgname, const char *vgid,
+ struct dm_list *mda_list);
+
#endif
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index 2c2b7fa..268bd64 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -1507,6 +1507,7 @@ static int _vg_remove_file(struct format_instance *fid __attribute__((unused)),
}
int read_metadata_location_summary(const struct format_type *fmt,
+ struct metadata_area *mda,
struct mda_header *mdah, int primary_mda, struct device_area *dev_area,
struct lvmcache_vgsummary *vgsummary, uint64_t *mda_free_sectors)
{
@@ -1565,6 +1566,17 @@ int read_metadata_location_summary(const struct format_type *fmt,
}
/*
+ * This function is used to read the vg summary during label scan.
+ * Save the text start location and checksum during scan. After the VG
+ * lock is acquired in vg_read, we can reread the mda_header, and
+ * compare rlocn->offset,checksum to what was saved during scan. If
+ * unchanged, it means that the metadata was not changed between scan
+ * and the read.
+ */
+ mda->scan_text_offset = rlocn->offset;
+ mda->scan_text_checksum = rlocn->checksum;
+
+ /*
* When the current metadata wraps around the end of the metadata area
* (so some is located at the end and some is located at the
* beginning), then "wrap" is the number of bytes that was written back
diff --git a/lib/format_text/layout.h b/lib/format_text/layout.h
index 7320d9c..7ec699e 100644
--- a/lib/format_text/layout.h
+++ b/lib/format_text/layout.h
@@ -104,7 +104,8 @@ struct mda_context {
#define MDA_SIZE_MIN (8 * (unsigned) lvm_getpagesize())
#define MDA_ORIGINAL_ALIGNMENT 512 /* Original alignment used for start of VG metadata content */
-int read_metadata_location_summary(const struct format_type *fmt, struct mda_header *mdah, int primary_mda,
+int read_metadata_location_summary(const struct format_type *fmt,
+ struct metadata_area *mda, struct mda_header *mdah, int primary_mda,
struct device_area *dev_area, struct lvmcache_vgsummary *vgsummary,
uint64_t *mda_free_sectors);
diff --git a/lib/format_text/text_label.c b/lib/format_text/text_label.c
index cb60c15..9241eca 100644
--- a/lib/format_text/text_label.c
+++ b/lib/format_text/text_label.c
@@ -349,7 +349,7 @@ static int _read_mda_header_and_metadata(const struct format_type *fmt,
return 1;
}
- if (!read_metadata_location_summary(fmt, mdah, mda_is_primary(mda), &mdac->area,
+ if (!read_metadata_location_summary(fmt, mda, mdah, mda_is_primary(mda), &mdac->area,
vgsummary, &mdac->free_sectors)) {
if (vgsummary->zero_offset)
return 1;
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index c4f7247..1ac5445 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -4571,6 +4571,118 @@ void vg_write_commit_bad_mdas(struct cmd_context *cmd, struct volume_group *vg)
}
}
+/*
+ * Reread an mda_header. If the text offset is the same as was seen and saved
+ * by label scan, it means the metadata is unchanged and we do not need to
+ * reread metadata.
+ */
+
+static int _scan_text_mismatch(struct cmd_context *cmd, const char *vgname, const char *vgid)
+{
+ struct dm_list mda_list;
+ struct mda_list *mdal, *safe;
+ struct metadata_area *mda;
+ struct mda_context *mdac;
+ struct device_area *area;
+ struct mda_header *mdah;
+ struct raw_locn *rlocn;
+ struct device *dev;
+ uint32_t bad_fields;
+ int ret = 1;
+
+ /*
+ * if cmd->can_use_one_scan, check one mda_header is unchanged,
+ * else check that all mda_headers are unchanged.
+ */
+
+ dm_list_init(&mda_list);
+
+ lvmcache_get_mdas(cmd, vgname, vgid, &mda_list);
+
+ dm_list_iterate_items(mdal, &mda_list) {
+ mda = mdal->mda;
+
+ if (!mda->scan_text_offset)
+ continue;
+
+ if (mda->mda_num != 1)
+ continue;
+
+ if (!(dev = mda_get_device(mda))) {
+ log_debug("rescan for text mismatch - no mda dev");
+ ret = 1;
+ goto out;
+ }
+
+ bad_fields = 0;
+
+ mdac = mda->metadata_locn;
+ area = &mdac->area;
+
+ /*
+ * Invalidate mda_header in bcache so it will be reread from disk.
+ */
+ if (!dev_invalidate_bytes(dev, 4096, 512)) {
+ log_debug("rescan for text mismatch - cannot invalidate");
+ ret = 1;
+ goto out;
+ }
+
+ if (!(mdah = raw_read_mda_header(cmd->fmt, area, 1, 0, &bad_fields))) {
+ log_debug("rescan for text mismatch - no mda header");
+ ret = 1;
+ goto out;
+ }
+
+ rlocn = mdah->raw_locns;
+
+ if (bad_fields) {
+ log_debug("rescan for text mismatch - bad_fields");
+ ret = 1;
+ } else if (rlocn->checksum != mda->scan_text_checksum) {
+ log_debug("rescan for text checksum mismatch - now %x prev %x",
+ rlocn->checksum, mda->scan_text_checksum);
+ ret = 1;
+ } else if (rlocn->offset != mda->scan_text_offset) {
+ log_debug("rescan for text offset mismatch - now %llu prev %llu",
+ (unsigned long long)rlocn->offset,
+ (unsigned long long)mda->scan_text_offset);
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+
+ dm_pool_free(cmd->mem, mdah);
+
+ /* For can_use_one_scan commands, return result from checking one mda. */
+ if (cmd->can_use_one_scan)
+ goto out;
+
+ /* For other commands, return mismatch immediately. */
+ if (ret)
+ goto_out;
+ }
+
+ if (ret) {
+ /* shouldn't happen */
+ log_debug("rescan for text mismatch - no mdas");
+ goto out;
+ }
+
+ ret = 0;
+
+out:
+ if (!ret)
+ log_debug("rescan skipped - text offset and checksum unchanged");
+
+ dm_list_iterate_items_safe(mdal, safe, &mda_list) {
+ dm_list_del(&mdal->list);
+ free(mdal);
+ }
+
+ return ret;
+}
+
static struct volume_group *_vg_read(struct cmd_context *cmd,
const char *vgname,
const char *vgid,
@@ -4625,19 +4737,23 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
* find the same inconsistency. The VG repair (mistakenly done by
* vg_read below) is supposed to fix that.
*
- * FIXME: sort out the usage of the global lock (which is mixed up
- * with the orphan lock), and when we can tell that the global
- * lock is taken prior to the label scan, and still held here,
- * we can also skip the rescan in that case.
+ * If the VG was not modified between the time we scanned the PVs
+ * and now, when we hold the lock, then we don't need to rescan.
+ * We can read the mda_header, and look at the text offset/checksum,
+ * and if the current text offset/checksum matches what was seen during
+ * label scan, we know that metadata is unchanged and doesn't need
+ * to be rescanned. For reporting/display commands (CAN_USE_ONE_SCAN/
+ * can_use_one_scan), we check that the text offset/checksum are unchanged
+ * in just one mda before deciding to skip rescanning. For other commands,
+ * we check that they are unchanged in all mdas. This added checking is
+ * probably unnecessary; all commands could likely just check a single mda.
*/
- if (!cmd->can_use_one_scan || lvmcache_scan_mismatch(cmd, vgname, vgid)) {
+ if (lvmcache_scan_mismatch(cmd, vgname, vgid) || _scan_text_mismatch(cmd, vgname, vgid)) {
log_debug_metadata("Rescanning devices for %s %s", vgname, writing ? "rw" : "");
if (writing)
lvmcache_label_rescan_vg_rw(cmd, vgname, vgid);
else
lvmcache_label_rescan_vg(cmd, vgname, vgid);
- } else {
- log_debug_metadata("Skipped rescanning devices for %s", vgname);
}
/* Now determine the correct vgname if none was supplied */
diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h
index ac18879..377a063 100644
--- a/lib/metadata/metadata.h
+++ b/lib/metadata/metadata.h
@@ -187,6 +187,8 @@ struct metadata_area {
void *metadata_locn;
uint32_t status;
uint64_t header_start; /* mda_header.start */
+ uint64_t scan_text_offset; /* rlocn->offset seen during scan */
+ uint32_t scan_text_checksum; /* rlocn->checksum seen during scan */
int mda_num;
uint32_t bad_fields; /* BAD_MDA_ flags are set to indicate errors found when reading */
uint32_t ignore_bad_fields; /* BAD_MDA_ flags are set to indicate errors to ignore */
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=29db9c6325ac3552b0ba3…
Commit: 29db9c6325ac3552b0ba3a0f49682e8e8112cca2
Parent: 2037476008ea42e79388a407355c7f285656a5d9
Author: Heinz Mauelshagen <heinzm(a)redhat.com>
AuthorDate: Tue Nov 26 22:17:34 2019 +0100
Committer: Heinz Mauelshagen <heinzm(a)redhat.com>
CommitterDate: Tue Nov 26 22:31:58 2019 +0100
lvcreate: ensure striped raid region size is at least stripe size
The kernel MD runtime requires region size to be larger than stripe size
on striped raid layouts, thus the dm-raid target's constructor rejects
such request.
This causes e.g. an 'lvcreate --type raid10 -i3 -I4096 -R2048 -n lv vg' to fail.
Avoid failing late in the kernel by enforcing region size to be
larger or equal to stripe size.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1698225
---
WHATS_NEW | 1 +
tools/lvcreate.c | 7 +++++++
2 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index e5af036..41d0e56 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.03.07 -
===================================
+ Ensure minimum required region size on striped RaidLV creation.
Fix resize of thin-pool with data and metadata of different segtype.
Improve mirror type leg splitting.
Fix activation order when removing merged snapshot.
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index ebe6c9f..4a1534c 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -575,6 +575,13 @@ static int _read_raid_params(struct cmd_context *cmd,
log_error("Minimum recovery rate cannot be higher than maximum.");
return 0;
}
+
+ if (lp->region_size < lp->stripe_size) {
+ log_print_unless_silent("Adjusting %s %s region size to required minimum of stripe size %s.",
+ lp->segtype->name, display_size(cmd, (uint64_t)lp->region_size),
+ display_size(cmd, (uint64_t)lp->stripe_size));
+ lp->region_size = lp->stripe_size;
+ }
}
return 1;
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=50c56ade2a7a89f751091…
Commit: 50c56ade2a7a89f751091669fb8b31854f93eff1
Parent: 61c321d110630d4fc2ed8f75cb3a9ba78e29599b
Author: Heinz Mauelshagen <heinzm(a)redhat.com>
AuthorDate: Tue Nov 26 22:17:34 2019 +0100
Committer: Heinz Mauelshagen <heinzm(a)redhat.com>
CommitterDate: Tue Nov 26 22:30:54 2019 +0100
lvcreate: ensure striped raid region size is at least stripe size
The kernel MD runtime requires region size to be larger than stripe size
on striped raid layouts, thus the dm-raid target's constructor rejects
such request.
This causes e.g. an 'lvcreate --type raid10 -i3 -I4096 -R2048 -n lv vg' to fail.
Avoid failing late in the kernel by enforcing region size to be
larger or equal to stripe size.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1698225
---
WHATS_NEW | 1 +
tools/lvcreate.c | 7 +++++++
2 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 50fd519..047479b 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.187 -
===================================
+ Ensure minimum required region size on striped RaidLV creation.
Fix resize of thin-pool with data and metadata of different segtype.
Fix splitting mirror leg in cluster.
Fix activation order when removing merged snapshot.
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index 6e8cc90..c27b798 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -574,6 +574,13 @@ static int _read_raid_params(struct cmd_context *cmd,
log_error("Minimum recovery rate cannot be higher than maximum.");
return 0;
}
+
+ if (lp->region_size < lp->stripe_size) {
+ log_print_unless_silent("Adjusting %s %s region size to required minimum of stripe size %s.",
+ lp->segtype->name, display_size(cmd, (uint64_t)lp->region_size),
+ display_size(cmd, (uint64_t)lp->stripe_size));
+ lp->region_size = lp->stripe_size;
+ }
}
return 1;
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=2037476008ea42e79388a…
Commit: 2037476008ea42e79388a407355c7f285656a5d9
Parent: 1c9b36618ec8357350ed4d83c807ae0bf27a12be
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Nov 26 14:34:43 2019 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Nov 26 14:34:43 2019 -0600
pvcreate,pvremove: fix reacquiring global lock after prompt
When pvcreate/pvremove prompt the user, they first release
the global lock, then acquire it again after the prompt,
to avoid blocking other commands while waiting for a user
response. This release/reacquire changes the locking
order with respect to the hints flock (and potentially other
locks). So, to avoid deadlock, use a nonblocking request
when reacquiring the global lock.
---
lib/locking/locking.c | 14 +++++++++++---
lib/locking/locking.h | 1 +
lib/misc/lvm-flock.c | 2 +-
tools/toollib.c | 5 +++--
4 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/lib/locking/locking.c b/lib/locking/locking.c
index 3058a8b..65ff8c2 100644
--- a/lib/locking/locking.c
+++ b/lib/locking/locking.c
@@ -338,7 +338,7 @@ int sync_local_dev_names(struct cmd_context* cmd)
* an explicitly acquired ex global lock to sh in process_each.
*/
-static int _lockf_global(struct cmd_context *cmd, const char *mode, int convert)
+static int _lockf_global(struct cmd_context *cmd, const char *mode, int convert, int nonblock)
{
uint32_t flags = 0;
int ret;
@@ -346,6 +346,9 @@ static int _lockf_global(struct cmd_context *cmd, const char *mode, int convert)
if (convert)
flags |= LCK_CONVERT;
+ if (nonblock)
+ flags |= LCK_NONBLOCK;
+
if (!strcmp(mode, "ex")) {
flags |= LCK_WRITE;
@@ -379,7 +382,7 @@ static int _lockf_global(struct cmd_context *cmd, const char *mode, int convert)
int lockf_global(struct cmd_context *cmd, const char *mode)
{
- return _lockf_global(cmd, mode, 0);
+ return _lockf_global(cmd, mode, 0, 0);
}
int lockf_global_convert(struct cmd_context *cmd, const char *mode)
@@ -388,7 +391,12 @@ int lockf_global_convert(struct cmd_context *cmd, const char *mode)
if (cmd->lockf_global_ex && !strcmp(mode, "ex"))
return 1;
- return _lockf_global(cmd, mode, 1);
+ return _lockf_global(cmd, mode, 1, 0);
+}
+
+int lockf_global_nonblock(struct cmd_context *cmd, const char *mode)
+{
+ return _lockf_global(cmd, mode, 0, 1);
}
int lock_global(struct cmd_context *cmd, const char *mode)
diff --git a/lib/locking/locking.h b/lib/locking/locking.h
index 746667a..3e8ae6f 100644
--- a/lib/locking/locking.h
+++ b/lib/locking/locking.h
@@ -75,6 +75,7 @@ int activate_lvs(struct cmd_context *cmd, struct dm_list *lvs, unsigned exclusiv
int lockf_global(struct cmd_context *cmd, const char *mode);
int lockf_global_convert(struct cmd_context *cmd, const char *mode);
+int lockf_global_nonblock(struct cmd_context *cmd, const char *mode);
int lock_global(struct cmd_context *cmd, const char *mode);
int lock_global_convert(struct cmd_context *cmd, const char *mode);
diff --git a/lib/misc/lvm-flock.c b/lib/misc/lvm-flock.c
index d65601d..d48ff22 100644
--- a/lib/misc/lvm-flock.c
+++ b/lib/misc/lvm-flock.c
@@ -164,7 +164,7 @@ static int _do_write_priority_flock(const char *file, int *fd, int operation, ui
strcpy(file_aux, file);
strcat(file_aux, AUX_LOCK_SUFFIX);
- if ((r = _do_flock(file_aux, &fd_aux, LOCK_EX, 0))) {
+ if ((r = _do_flock(file_aux, &fd_aux, LOCK_EX, nonblock))) {
if (operation == LOCK_EX) {
r = _do_flock(file, fd, operation, nonblock);
_undo_flock(file_aux, fd_aux);
diff --git a/tools/toollib.c b/tools/toollib.c
index ee2419b..a5304bf 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -5577,10 +5577,11 @@ int pvcreate_each_device(struct cmd_context *cmd,
* Reacquire the lock that was released above before waiting, then
* check again that the devices can still be used. If the second loop
* finds them changed, or can't find them any more, then they aren't
- * used.
+ * used. Use a non-blocking request when reacquiring to avoid
+ * potential deadlock since this is not the normal locking sequence.
*/
- if (!lockf_global(cmd, "ex")) {
+ if (!lockf_global_nonblock(cmd, "ex")) {
log_error("Failed to reacquire global lock after prompt.");
goto_out;
}