master - tests: metadata-zero-space
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=bbca70a0b7de682ce3f...
Commit: bbca70a0b7de682ce3f4547f313f55a9a44ed89d
Parent: c22ad12bab1cff6fa4c23cb0242650751716803e
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Jul 12 14:08:22 2019 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Jul 12 15:03:47 2019 -0500
tests: metadata-zero-space
Test zero padding between copies of metadata.
---
test/shell/metadata-zero-space.sh | 86 +++++++++++++++++++++++++++++++++++++
1 files changed, 86 insertions(+), 0 deletions(-)
diff --git a/test/shell/metadata-zero-space.sh b/test/shell/metadata-zero-space.sh
new file mode 100644
index 0000000..847ef44
--- /dev/null
+++ b/test/shell/metadata-zero-space.sh
@@ -0,0 +1,86 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008 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 1 256
+get_devs
+
+# Fill with random data so if the space between metadata
+# copies are not zeroed the grep for zeros will fail.
+dd if=/dev/urandom of="$dev1" bs=1M || true
+
+pvcreate --pvmetadatacopies 2 "$dev1"
+
+vgcreate $SHARED "$vg" "$dev1"
+
+for i in `seq 1 50`; do lvcreate -l1 -an $vg; done
+
+if [ -e "/usr/bin/xxd" ]; then
+
+# Check metadata copies are separated by zeroes in the first mda
+
+dd if="$dev1" of=meta.raw bs=1M count=1
+
+xxd meta.raw > meta.txt
+
+grep -B1 "$vg {" meta.txt > meta.vg
+
+cat meta.vg
+
+grep -v $vg meta.vg > meta.zeros
+
+cat meta.zeros
+
+grep '0000 0000 0000 0000 0000 0000 0000 0000' meta.zeros > meta.count
+
+cat meta.count | wc -l
+
+# wc will often equal 51, but some natural variability in
+# metadata locations/content mean that some lines do not
+# require a full line of zero padding, and will not match
+# the grep for a full row of zeros. So, check that more
+# than 20 lines match the full row of zeros (this is a
+# random choice, and this isn't a perfect way to test for
+# zero padding.)
+
+test "$(cat meta.count | wc -l)" -gt 20
+
+rm meta.raw meta.txt meta.vg meta.zeros meta.count
+
+#
+# Check metadata copies are separated by zeroes in the second mda
+#
+
+dd if="$dev1" of=meta.raw bs=1M seek=15 count=1
+
+xxd meta.raw > meta.txt
+
+grep -B1 "$vg {" meta.txt > meta.vg
+
+cat meta.vg
+
+grep -v $vg meta.vg > meta.zeros
+
+cat meta.zeros
+
+grep '0000 0000 0000 0000 0000 0000 0000 0000' meta.zeros > meta.count
+
+cat meta.count | wc -l
+
+test "$(cat meta.count | wc -l)" -gt 20
+
+fi
+
+vgremove -ff $vg
4 years, 8 months
master - metadata: extend writes to zero space
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=c22ad12bab1cff6fa4c...
Commit: c22ad12bab1cff6fa4c23cb0242650751716803e
Parent: 76573137404dafa58795995f5c10dfb5dbc714de
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Jul 1 15:00:34 2019 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Jul 12 15:00:12 2019 -0500
metadata: extend writes to zero space
Previously, consecutive copies of metadata would have garbage
data in the space between them. After metadata wrapping,
the garbage would be portions of old metadata. This made
analysis of the metadata area more difficult.
This would happen because the start of new copy of metadata
is advanced from the end of the last copy to start at the
next 512 byte boundary.
Zero the space between consecutive copies of metadata by
extending each metadata write to end at the next 512 byte
boundary. The size of the metadata itself is not extended,
only the write. The buffer being written contains the
metadata text followed by the necessary number of zeros.
---
lib/format_text/export.c | 10 +-
lib/format_text/format-text.c | 303 ++++++++++++++++++++++++++++++---------
lib/format_text/import-export.h | 2 +-
3 files changed, 244 insertions(+), 71 deletions(-)
diff --git a/lib/format_text/export.c b/lib/format_text/export.c
index 2a3f844..b5e987e 100644
--- a/lib/format_text/export.c
+++ b/lib/format_text/export.c
@@ -129,6 +129,7 @@ static int _extend_buffer(struct formatter *f)
log_error("Buffer reallocation failed.");
return 0;
}
+ memset(newbuf + f->data.buf.size, 0, f->data.buf.size);
f->data.buf.start = newbuf;
f->data.buf.size *= 2;
@@ -1052,7 +1053,7 @@ int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp)
}
/* Returns amount of buffer used incl. terminating NUL */
-size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
+size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf, uint32_t *buf_size)
{
struct formatter *f;
size_t r = 0;
@@ -1063,7 +1064,7 @@ size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
return_0;
f->data.buf.size = 65536; /* Initial metadata limit */
- if (!(f->data.buf.start = malloc(f->data.buf.size))) {
+ if (!(f->data.buf.start = zalloc(f->data.buf.size))) {
log_error("text_export buffer allocation failed");
goto out;
}
@@ -1081,6 +1082,9 @@ size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
r = f->data.buf.used + 1;
*buf = f->data.buf.start;
+ if (buf_size)
+ *buf_size = f->data.buf.size;
+
out:
free(f);
return r;
@@ -1088,7 +1092,7 @@ size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
static size_t _export_vg_to_buffer(struct volume_group *vg, char **buf)
{
- return text_vg_export_raw(vg, "", buf);
+ return text_vg_export_raw(vg, "", buf, NULL);
}
struct dm_config_tree *export_vg_to_config_tree(struct volume_group *vg)
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index 6873f19..2a5c8ec 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -38,8 +38,9 @@ static struct format_instance *_text_create_text_instance(const struct format_ty
const struct format_instance_ctx *fic);
struct text_fid_context {
- char *raw_metadata_buf;
- uint32_t raw_metadata_buf_size;
+ char *write_buf; /* buffer containing metadata text to write to disk */
+ uint32_t write_buf_size; /* mem size of write_buf, increases in 64K multiples */
+ uint32_t new_metadata_size; /* size of text metadata in buf */
};
int rlocn_is_ignored(const struct raw_locn *rlocn)
@@ -349,19 +350,25 @@ static struct raw_locn *_read_metadata_location_vg(struct device_area *dev_area,
/*
* Determine offset for new metadata
*
- * FIXME: The rounding can have a negative effect: when the current metadata
+ * The rounding can have a negative effect: when the current metadata
* text size is just below the max, a command to remove something, that
* *reduces* the text metadata size, can still be rejected for being too large,
* even though it's smaller than the current size. In this case, the user
* would need to find something in the VG to remove that uses more text space
* to compensate for the increase due to rounding.
+ * Update: I think that the new max_size restriction avoids this problem.
*/
-static uint64_t _next_rlocn_offset(struct raw_locn *rlocn_old, uint64_t old_last, struct mda_header *mdah, uint64_t mdac_area_start, uint64_t alignment)
+static uint64_t _next_rlocn_offset(struct volume_group *vg, struct raw_locn *rlocn_old, uint64_t old_last, struct mda_header *mdah, uint64_t mdac_area_start, uint64_t alignment)
{
uint64_t next_start;
uint64_t new_start;
- uint64_t adjust;
+ uint64_t adjust = 0;
+
+ /* This has only been designed to work with 512. */
+ if (alignment != 512)
+ log_warn("WARNING: metadata alignment should be 512 not %llu",
+ (unsigned long long)alignment);
/*
* No metadata has been written yet, begin at MDA_HEADER_SIZE offset
@@ -375,7 +382,8 @@ static uint64_t _next_rlocn_offset(struct raw_locn *rlocn_old, uint64_t old_last
* metadata area, then start at beginning.
*/
if (mdah->size - old_last < alignment) {
- log_debug_metadata("new metadata offset adjusted from %llu to beginning %u",
+ log_debug_metadata("VG %s %u new metadata start align from %llu to beginning %u",
+ vg->name, vg->seqno,
(unsigned long long)(old_last + 1), MDA_HEADER_SIZE);
return MDA_HEADER_SIZE;
}
@@ -386,22 +394,24 @@ static uint64_t _next_rlocn_offset(struct raw_locn *rlocn_old, uint64_t old_last
next_start = old_last + 1;
- adjust = alignment - (next_start % alignment);
+ if (next_start % alignment)
+ adjust = alignment - (next_start % alignment);
new_start = next_start + adjust;
- log_debug_metadata("new metadata offset adjusted from %llu to %llu (+%llu) for alignment %llu",
+ log_debug_metadata("VG %s %u new metadata start align from %llu to %llu (+%llu)",
+ vg->name, vg->seqno,
(unsigned long long)next_start,
(unsigned long long)new_start,
- (unsigned long long)adjust,
- (unsigned long long)alignment);
+ (unsigned long long)adjust);
/*
* If new_start is beyond the end of the metadata area or within
* alignment bytes of the end, then start at the beginning.
*/
if (new_start > mdah->size - alignment) {
- log_debug_metadata("new metadata offset adjusted from %llu to beginning %u",
+ log_debug_metadata("VG %s %u new metadata start align from %llu to beginning %u",
+ vg->name, vg->seqno,
(unsigned long long)new_start, MDA_HEADER_SIZE);
return MDA_HEADER_SIZE;
}
@@ -566,15 +576,43 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
struct raw_locn *rlocn_new;
struct mda_header *mdah;
struct pv_list *pvl;
+ uint64_t mda_start = mdac->area.start;
+ uint64_t max_size;
uint64_t old_start = 0, old_last = 0, old_size = 0, old_wrap = 0;
uint64_t new_start = 0, new_last = 0, new_size = 0, new_wrap = 0;
- uint64_t max_size;
+ uint64_t write1_start = 0, write1_last = 0, write1_size = 0;
+ uint64_t write2_start = 0, write2_last = 0, write2_size = 0;
+ uint32_t write1_over = 0, write2_over = 0;
+ uint32_t write_buf_size;
+ uint32_t extra_size;
uint32_t bad_fields = 0;
- char *new_buf = NULL;
- int overlap;
+ char *write_buf = NULL;
+ const char *devname = dev_name(mdac->area.dev);
+ bool overlap;
int found = 0;
int r = 0;
+ /*
+ * old_start/old_last/new_start/new_last are relative to the
+ * start of the metadata area (mda_start), and specify the first
+ * and last bytes of old/new metadata copies in the metadata area.
+ *
+ * write1_start/write1_last/write2_start/write2_last are
+ * relative to the start of the disk, and specify the
+ * first/last bytes written to disk when writing a new
+ * copy of metadata. (Will generally be larger than the
+ * size of the metadata since the write is extended past
+ * the end of the new metadata to end on a 512 byte boundary.)
+ *
+ * So, write1_start == mda_start + new_start.
+ *
+ * "last" values are inclusive, so last - start + 1 = size.
+ * old_last/new_last are the last bytes containing metadata.
+ * write1_last/write2_last are the last bytes written.
+ * The next copy of metadata will be written beginning at
+ * write1_last+1.
+ */
+
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
dm_list_iterate_items(pvl, &vg->pvs) {
if (pvl->pv->dev == mdac->area.dev) {
@@ -592,25 +630,39 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
* Create a text metadata representation of struct vg in buffer.
* This buffer is written to disk below. This function is called
* to write metadata to each device/mda in the VG. The first time
- * the metadata text is saved in raw_metadata_buf and subsequent
+ * the metadata text is saved in write_buf and subsequent
* mdas use that.
+ *
+ * write_buf_size is increased in 64K increments, so will generally
+ * be larger than new_size. The extra space in write_buf (after
+ * new_size) is zeroed. More than new_size can be written from
+ * write_buf to zero data on disk following the new text metadata,
+ * up to the next 512 byte boundary.
*/
- if (fidtc->raw_metadata_buf) {
- new_buf = fidtc->raw_metadata_buf;
- new_size = fidtc->raw_metadata_buf_size;
+ if (fidtc->write_buf) {
+ write_buf = fidtc->write_buf;
+ write_buf_size = fidtc->write_buf_size;
+ new_size = fidtc->new_metadata_size;
} else {
char *desc = _build_desc_write(fid->fmt->cmd, vg);
- new_size = text_vg_export_raw(vg, desc, &new_buf);
- fidtc->raw_metadata_buf = new_buf;
- fidtc->raw_metadata_buf_size = new_size;
+ new_size = text_vg_export_raw(vg, desc, &write_buf, &write_buf_size);
+ fidtc->write_buf = write_buf;
+ fidtc->write_buf_size = write_buf_size;
+ fidtc->new_metadata_size = new_size;
free(desc);
}
- if (!new_size || !new_buf) {
+ if (!new_size || !write_buf) {
log_error("VG %s metadata writing failed", vg->name);
goto out;
}
+ log_debug_metadata("VG %s seqno %u metadata write to %s mda_start %llu mda_size %llu mda_last %llu",
+ vg->name, vg->seqno, devname,
+ (unsigned long long)mda_start,
+ (unsigned long long)mdah->size,
+ (unsigned long long)(mda_start + mdah->size - 1));
+
/*
* The max size of a single copy of text metadata.
*
@@ -624,9 +676,8 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
max_size = ((mdah->size - MDA_HEADER_SIZE) / 2) - 512;
if (new_size > max_size) {
- log_error("VG %s metadata on %s (%llu bytes) exceeds maximum metadata size (%llu bytes)",
- vg->name,
- dev_name(mdac->area.dev),
+ log_error("VG %s %u metadata on %s (%llu bytes) exceeds maximum metadata size (%llu bytes)",
+ vg->name, vg->seqno, devname,
(unsigned long long)new_size,
(unsigned long long)max_size);
goto out;
@@ -636,7 +687,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
* rlocn_old is the current, committed, raw_locn data in slot0 on disk.
*
* rlocn_new (mdac->rlocn) is the new, in-memory, raw_locn data for the
- * new metadata. It is in-memory only, not yet written to disk.
+ * new metadata. rlocn_new is in-memory only, not yet written to disk.
*
* rlocn_new is not written to disk by vg_write. vg_write only writes
* the new text metadata into the circular buffer, it does not update any
@@ -645,7 +696,8 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
* vg_precommit and vg_commit can find it later and write it to disk.
*
* rlocn/raw_locn values, old_start, old_last, old_size, new_start,
- * new_last, new_size, are all in bytes.
+ * new_last, new_size, are all in bytes, and are all relative to the
+ * the start of the metadata area (not to the start of the disk.)
*
* The start and last values are the first and last bytes that hold
* the metadata inclusively, e.g.
@@ -659,6 +711,10 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
* after which the circular buffer of text metadata begins.
* So, the when the text metadata wraps around, it starts again at
* area.start + MDA_HEADER_SIZE.
+ *
+ * When pe_start is at 1MB (the default), and mda_start is at 4KB,
+ * there will be 1MB - 4KB - 512 bytes of circular buffer space for
+ * text metadata.
*/
rlocn_old = &mdah->raw_locns[0]; /* slot0, committed metadata */
@@ -691,11 +747,18 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
* area, then the new start is set back at the beginning
* (metadata begins MDA_HEADER_SIZE after start of metadata area).
*/
- new_start = _next_rlocn_offset(rlocn_old, old_last, mdah, mdac->area.start, MDA_ORIGINAL_ALIGNMENT);
+ new_start = _next_rlocn_offset(vg, rlocn_old, old_last, mdah, mda_start, MDA_ORIGINAL_ALIGNMENT);
if (new_start + new_size > mdah->size) {
new_wrap = (new_start + new_size) - mdah->size;
new_last = new_wrap + MDA_HEADER_SIZE - 1;
+
+ log_debug_metadata("VG %s %u wrapping metadata new_start %llu new_size %llu to size1 %llu size2 %llu",
+ vg->name, vg->seqno,
+ (unsigned long long)new_start,
+ (unsigned long long)new_size,
+ (unsigned long long)(new_size - new_wrap),
+ (unsigned long long)new_wrap);
} else {
new_wrap = 0;
new_last = new_start + new_size - 1;
@@ -709,21 +772,20 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
rlocn_new->offset = new_start;
rlocn_new->size = new_size;
- log_debug_metadata("VG %s metadata offsets: old start %llu last %llu size %llu wrap %llu",
- vg->name,
+ log_debug_metadata("VG %s %u metadata area location old start %llu last %llu size %llu wrap %llu",
+ vg->name, vg->seqno,
(unsigned long long)old_start,
(unsigned long long)old_last,
(unsigned long long)old_size,
(unsigned long long)old_wrap);
- log_debug_metadata("VG %s metadata offsets: new start %llu last %llu size %llu wrap %llu",
- vg->name,
+ log_debug_metadata("VG %s %u metadata area location new start %llu last %llu size %llu wrap %llu",
+ vg->name, vg->seqno,
(unsigned long long)new_start,
(unsigned long long)new_last,
(unsigned long long)new_size,
(unsigned long long)new_wrap);
-
/*
* If the new copy of the metadata would overlap the old copy of the
* metadata, it means that the circular metadata buffer is full.
@@ -739,19 +801,19 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
if (new_wrap && old_wrap) {
/* old and new can't both wrap without overlapping */
- overlap = 1;
+ overlap = true;
} else if (!new_wrap && !old_wrap &&
(new_start > old_last) && (new_last > new_start)) {
/* new metadata is located entirely after the old metadata */
- overlap = 0;
+ overlap = false;
} else if (!new_wrap && !old_wrap &&
(new_start < old_start) && (new_last < old_start)) {
/* new metadata is located entirely before the old metadata */
- overlap = 0;
+ overlap = false;
} else if (old_wrap && !new_wrap &&
(old_last < new_start) && (new_start < new_last) && (new_last < old_start)) {
@@ -759,7 +821,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
/* when old wraps and the new doesn't, then no overlap is:
old_last followed by new_start followed by new_last
followed by old_start */
- overlap = 0;
+ overlap = false;
} else if (new_wrap && !old_wrap &&
(new_last < old_start) && (old_start < old_last) && (old_last < new_start)) {
@@ -767,46 +829,150 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
/* when new wraps and the old doesn't, then no overlap is:
new_last followed by old_start followed by old_last
followed by new_start. */
- overlap = 0;
+ overlap = false;
} else {
- overlap = 1;
+ overlap = true;
}
if (overlap) {
- log_error("VG %s metadata on %s (%llu bytes) too large for circular buffer (%llu bytes with %llu used)",
- vg->name,
- dev_name(mdac->area.dev),
+ log_error("VG %s %u metadata on %s (%llu bytes) too large for circular buffer (%llu bytes with %llu used)",
+ vg->name, vg->seqno, devname,
(unsigned long long)new_size,
(unsigned long long)(mdah->size - MDA_HEADER_SIZE),
(unsigned long long)old_size);
goto out;
}
- log_debug_metadata("VG %s metadata write to %s at %llu len %llu (wrap %llu)",
- vg->name, dev_name(mdac->area.dev),
- (unsigned long long)(mdac->area.start + rlocn_new->offset),
- (unsigned long long)(rlocn_new->size - new_wrap),
- (unsigned long long)new_wrap);
+ if (!new_wrap) {
+ write1_start = mda_start + new_start;
+ write1_size = new_size;
+ write1_last = write1_start + write1_size - 1;
+ write1_over = (write1_last + 1) % 512;
+ write2_start = 0;
+ write2_size = 0;
+ write2_last = 0;
+ write2_over = 0;
+ } else {
+ write1_start = mda_start + new_start;
+ write1_size = new_size - new_wrap;
+ write1_last = write1_start + write1_size - 1;
+ write1_over = 0;
+ write2_start = mda_start + MDA_HEADER_SIZE;
+ write2_size = new_wrap;
+ write2_last = write2_start + write2_size - 1;
+ write2_over = (write2_last + 1) % 512;
+ }
+
+ if (!new_wrap)
+ log_debug_metadata("VG %s %u metadata disk location start %llu size %llu last %llu",
+ vg->name, vg->seqno,
+ (unsigned long long)write1_start,
+ (unsigned long long)write1_size,
+ (unsigned long long)write1_last);
+ else
+ log_debug_metadata("VG %s %u metadata disk location write1 start %llu size %llu last %llu write2 start %llu size %llu last %llu",
+ vg->name, vg->seqno,
+ (unsigned long long)write1_start,
+ (unsigned long long)write1_size,
+ (unsigned long long)write1_last,
+ (unsigned long long)write2_start,
+ (unsigned long long)write2_size,
+ (unsigned long long)write2_last);
+
+ /*
+ * Write more than the size of the new metadata, up to the next
+ * 512 byte boundary so that the space between this copy and the
+ * subsequent copy of metadata will be zeroed.
+ *
+ * Extend write1_size so that write1_last+1 is a 512 byte multiple.
+ * The next metadata write should follow immediately after the
+ * extended write1_last since new metadata tries to begin on a 512
+ * byte boundary.
+ *
+ * write1_size can be extended up to write_buf_size which is the size
+ * of write_buf (new_size is the portion of write_buf used by the new
+ * metadata.)
+ *
+ * If this metadata write will wrap, the first write is written
+ * all the way to the end of the metadata area, and it's the
+ * second wrapped write that is extended up to a 512 byte boundary.
+ */
+
+ if (write1_over) {
+ extra_size = 512 - write1_over; /* this many extra zero bytes written after metadata text */
+ write1_size += extra_size;
+ write1_last = write1_start + write1_size - 1;
+
+ log_debug_metadata("VG %s %u metadata last align from %llu to %llu (+%u)",
+ vg->name, vg->seqno,
+ (unsigned long long)write1_last - extra_size,
+ (unsigned long long)write1_last, extra_size);
+
+ if (write1_size > write_buf_size) {
+ /* sanity check, shouldn't happen */
+ log_error("VG %s %u %s adjusted metadata end %llu extra %u larger than write buffer %llu",
+ vg->name, vg->seqno, devname,
+ (unsigned long long)write1_size, extra_size,
+ (unsigned long long)write_buf_size);
+ write1_size -= extra_size;
+ }
+ }
+
+ if (write2_over) {
+ extra_size = 512 - write2_over; /* this many extra zero bytes written after metadata text */
+ write2_size += extra_size;
+ write2_last = write2_start + write2_size - 1;
+
+ log_debug_metadata("VG %s %u metadata last align from %llu to %llu (+%u) (wrapped)",
+ vg->name, vg->seqno,
+ (unsigned long long)write2_last - extra_size,
+ (unsigned long long)write2_last, extra_size);
+
+ if (write1_size + write2_size > write_buf_size) {
+ /* sanity check, shouldn't happen */
+ log_error("VG %s %u %s adjusted metadata end %llu wrap %llu extra %u larger than write buffer %llu",
+ vg->name, vg->seqno, devname,
+ (unsigned long long)write1_size,
+ (unsigned long long)write2_size, extra_size,
+ (unsigned long long)write_buf_size);
+ write2_size -= extra_size;
+ }
+ }
+
+ if ((write1_size > write_buf_size) || (write2_size > write_buf_size)) {
+ /* sanity check, shouldn't happen */
+ log_error("VG %s %u %s metadata write size %llu %llu larger than buffer %llu",
+ vg->name, vg->seqno, devname,
+ (unsigned long long)write1_size,
+ (unsigned long long)write2_size,
+ (unsigned long long)write_buf_size);
+ goto out;
+ }
+
+ dev_set_last_byte(mdac->area.dev, mda_start + mdah->size);
- dev_set_last_byte(mdac->area.dev, mdac->area.start + mdah->size);
+ log_debug_metadata("VG %s %u metadata write at %llu size %llu (wrap %llu)",
+ vg->name, vg->seqno,
+ (unsigned long long)write1_start,
+ (unsigned long long)write1_size,
+ (unsigned long long)write2_size);
- if (!dev_write_bytes(mdac->area.dev, mdac->area.start + rlocn_new->offset,
- (size_t) (rlocn_new->size - new_wrap), new_buf)) {
- log_error("Failed to write metadata to %s fd %d", dev_name(mdac->area.dev), mdac->area.dev->bcache_fd);
+ if (!dev_write_bytes(mdac->area.dev, write1_start, (size_t)write1_size, write_buf)) {
+ log_error("Failed to write metadata to %s fd %d", devname, mdac->area.dev->bcache_fd);
dev_unset_last_byte(mdac->area.dev);
goto out;
}
- if (new_wrap) {
- log_debug_metadata("VG %s metadata write to %s at %llu len %llu (wrapped)",
- vg->name, dev_name(mdac->area.dev),
- (unsigned long long)(mdac->area.start + MDA_HEADER_SIZE),
- (unsigned long long)new_wrap);
+ if (write2_size) {
+ log_debug_metadata("VG %s %u metadata write at %llu size %llu (wrapped)",
+ vg->name, vg->seqno,
+ (unsigned long long)write2_start,
+ (unsigned long long)write2_size);
- if (!dev_write_bytes(mdac->area.dev, mdac->area.start + MDA_HEADER_SIZE,
- (size_t) new_wrap, new_buf + rlocn_new->size - new_wrap)) {
- log_error("Failed to write metadata wrap to %s fd %d", dev_name(mdac->area.dev), mdac->area.dev->bcache_fd);
+ if (!dev_write_bytes(mdac->area.dev, write2_start, write2_size,
+ write_buf + new_size - new_wrap)) {
+ log_error("Failed to write metadata wrap to %s fd %d", devname, mdac->area.dev->bcache_fd);
dev_unset_last_byte(mdac->area.dev);
goto out;
}
@@ -815,20 +981,21 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
dev_unset_last_byte(mdac->area.dev);
rlocn_new->checksum = calc_crc(INITIAL_CRC,
- (uint8_t *)new_buf,
- (uint32_t)(rlocn_new->size - new_wrap));
+ (uint8_t *)write_buf,
+ (uint32_t)(new_size - new_wrap));
if (new_wrap)
rlocn_new->checksum = calc_crc(rlocn_new->checksum,
- (uint8_t *)new_buf + rlocn_new->size - new_wrap,
+ (uint8_t *)write_buf + new_size - new_wrap,
(uint32_t)new_wrap);
r = 1;
out:
if (!r) {
- free(fidtc->raw_metadata_buf);
- fidtc->raw_metadata_buf = NULL;
- fidtc->raw_metadata_buf_size = 0;
+ free(fidtc->write_buf);
+ fidtc->write_buf = NULL;
+ fidtc->write_buf_size = 0;
+ fidtc->new_metadata_size = 0;
}
return r;
@@ -1015,8 +1182,10 @@ static int _vg_commit_raw_rlocn(struct format_instance *fid,
out:
if (!precommit) {
- free(fidtc->raw_metadata_buf);
- fidtc->raw_metadata_buf = NULL;
+ free(fidtc->write_buf);
+ fidtc->write_buf = NULL;
+ fidtc->write_buf_size = 0;
+ fidtc->new_metadata_size = 0;
}
return r;
diff --git a/lib/format_text/import-export.h b/lib/format_text/import-export.h
index b7a8fa6..0bfc60b 100644
--- a/lib/format_text/import-export.h
+++ b/lib/format_text/import-export.h
@@ -66,7 +66,7 @@ int print_segtype_lvflags(char *buffer, size_t size, uint64_t status);
int read_segtype_lvflags(uint64_t *status, char *segtype_str);
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
-size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf);
+size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf, uint32_t *alloc_size);
struct volume_group *text_read_metadata_file(struct format_instance *fid,
const char *file,
time_t *when, char **desc);
4 years, 8 months
master - pvck: fix looping dump metadata_all
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=76573137404dafa5879...
Commit: 76573137404dafa58795995f5c10dfb5dbc714de
Parent: 7230aa891c4186ab425f6821c25101d9049fadde
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Jul 12 12:21:27 2019 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Jul 12 14:09:06 2019 -0500
pvck: fix looping dump metadata_all
dump metadata_all wouldn't quit if the metadata wrapped.
---
tools/pvck.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/tools/pvck.c b/tools/pvck.c
index 3437164..af2dd8e 100644
--- a/tools/pvck.c
+++ b/tools/pvck.c
@@ -395,6 +395,9 @@ static int _dump_meta_all(struct device *dev, const char *tofile,
search_offset = meta_offset + meta_size;
search_next:
+ if (search_wrapped && (search_offset >= meta_offset + meta_size))
+ goto done;
+
if (search_offset > mda_size) {
if (search_wrapped)
goto done;
4 years, 8 months
master - tests: pvscan-autoactivate test unmatching dev and PV size
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=7230aa891c4186ab425...
Commit: 7230aa891c4186ab425f6821c25101d9049fadde
Parent: 4eb0e65693a6e3d7f4fe406aff5fdc75c3ef9b87
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Jul 11 11:38:12 2019 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Thu Jul 11 11:38:12 2019 -0500
tests: pvscan-autoactivate test unmatching dev and PV size
---
test/shell/pvscan-autoactivate.sh | 28 +++++++++++++++++++++++++++-
1 files changed, 27 insertions(+), 1 deletions(-)
diff --git a/test/shell/pvscan-autoactivate.sh b/test/shell/pvscan-autoactivate.sh
index d674dc5..d79a7e3 100644
--- a/test/shell/pvscan-autoactivate.sh
+++ b/test/shell/pvscan-autoactivate.sh
@@ -27,7 +27,7 @@ _clear_online_files() {
. lib/inittest
-aux prepare_pvs 8
+aux prepare_devs 8 16
vgcreate $vg1 "$dev1" "$dev2"
lvcreate -n $lv1 -l 4 -a n $vg1
@@ -209,3 +209,29 @@ pvscan --cache -aay
check lv_field $vg3/$lv1 lv_active "active"
lvchange -an $vg3
+# Test event activation when PV and dev size don't match
+
+vgremove -ff $vg3
+
+pvremove "$dev8"
+pvcreate -y --setphysicalvolumesize 8M "$dev8"
+
+PVID8=`pvs $dev8 --noheading -o uuid | tr -d - | awk '{print $1}'`
+echo $PVID8
+
+vgcreate $vg3 "$dev8"
+lvcreate -l1 -n $lv1 $vg3
+check lv_field $vg3/$lv1 lv_active "active"
+vgchange -an $vg3
+check lv_field $vg3/$lv1 lv_active ""
+
+_clear_online_files
+
+pvscan --cache -aay "$dev8"
+check lv_field $vg3/$lv1 lv_active "active"
+ls "$RUNDIR/lvm/pvs_online/$PVID8"
+ls "$RUNDIR/lvm/vgs_online/$vg3"
+vgchange -an $vg3
+
+vgremove -ff $vg3
+
4 years, 8 months
master - tests: extend lvm-on-md
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=4eb0e65693a6e3d7f4f...
Commit: 4eb0e65693a6e3d7f4fe406aff5fdc75c3ef9b87
Parent: 4567c6a2b2f4f2662ef909887640681c8bba0e02
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Jul 10 14:13:01 2019 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Thu Jul 11 11:20:06 2019 -0500
tests: extend lvm-on-md
---
test/shell/lvm-on-md.sh | 257 +++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 237 insertions(+), 20 deletions(-)
diff --git a/test/shell/lvm-on-md.sh b/test/shell/lvm-on-md.sh
index 22cbee8..c848083 100644
--- a/test/shell/lvm-on-md.sh
+++ b/test/shell/lvm-on-md.sh
@@ -42,7 +42,7 @@ aux lvmconf 'devices/obtain_device_list_from_udev = 0'
aux extend_filter_LVMTEST "a|/dev/md|"
-aux prepare_devs 2
+aux prepare_devs 3
# create 2 disk MD raid1 array
# by default using metadata format 1.0 with data at the end of device
@@ -55,6 +55,9 @@ pvdev=$(< MD_DEV_PV)
vgcreate $vg "$mddev"
+PVIDMD=`pvs $mddev --noheading -o uuid | tr -d - | awk '{print $1}'`
+echo $PVIDMD
+
lvcreate -n $lv1 -l 2 $vg
lvcreate -n $lv2 -l 2 -an $vg
@@ -87,7 +90,8 @@ pvs > out
not grep "$dev1" out
not grep "$dev2" out
-pvs -vvvv
+pvs 2>&1|tee out
+not grep "Not using device" out
# should not activate from the md legs
not vgchange -ay $vg
@@ -105,42 +109,62 @@ _clear_online_files
pvscan --cache -aay "$dev1"
pvscan --cache -aay "$dev2"
+not ls "$RUNDIR/lvm/pvs_online/$PVIDMD"
+not ls "$RUNDIR/lvm/vgs_online/$vg"
+
# should not show an active lv
rm out
lvs -o active $vg |tee out || true
not grep "active" out
-# start the md dev
mdadm --assemble "$mddev" "$dev1" "$dev2"
aux udev_wait
-# Now that the md dev is online, pvs can see it
-# and check for components even if
-# md_component_checks is "start" (which disables
-# most default end-of-device scans)
-aux lvmconf 'devices/md_component_checks = "start"'
-
not pvs "$dev1"
not pvs "$dev2"
pvs > out
not grep "$dev1" out
not grep "$dev2" out
+lvs $vg
+vgchange -an $vg
+
+# should not activate from the md legs
+_clear_online_files
+pvscan --cache -aay "$dev1"
+pvscan --cache -aay "$dev2"
+
+not ls "$RUNDIR/lvm/pvs_online/$PVIDMD"
+not ls "$RUNDIR/lvm/vgs_online/$vg"
+
+# should not show an active lv
+rm out
+lvs -o active $vg |tee out || true
+not grep "active" out
vgchange -ay $vg
check lv_field $vg/$lv1 lv_active "active"
vgchange -an $vg
+
+_clear_online_files
+pvscan --cache -aay "$mddev"
+
+ls "$RUNDIR/lvm/pvs_online/$PVIDMD"
+ls "$RUNDIR/lvm/vgs_online/$vg"
+
+lvs -o active $vg |tee out || true
+grep "active" out
+
+vgchange -an $vg
+
aux udev_wait
vgremove -f $vg
aux cleanup_md_dev
-# Put this setting back to the default
-aux lvmconf 'devices/md_component_checks = "auto"'
-
# create 2 disk MD raid0 array
# by default using metadata format 1.0 with data at the end of device
# When a raid0 md array is stopped, the components will not look like
@@ -154,7 +178,8 @@ pvdev=$(< MD_DEV_PV)
vgcreate $vg "$mddev"
-lvs $vg
+PVIDMD=`pvs $mddev --noheading -o uuid | tr -d - | awk '{print $1}'`
+echo $PVIDMD
lvcreate -n $lv1 -l 2 $vg
lvcreate -n $lv2 -l 2 -an $vg
@@ -188,7 +213,8 @@ pvs > out
not grep "$dev1" out
not grep "$dev2" out
-pvs -vvvv
+pvs 2>&1|tee out
+not grep "Not using device" out
# should not activate from the md legs
not vgchange -ay $vg
@@ -206,6 +232,9 @@ _clear_online_files
pvscan --cache -aay "$dev1"
pvscan --cache -aay "$dev2"
+not ls "$RUNDIR/lvm/pvs_online/$PVIDMD"
+not ls "$RUNDIR/lvm/vgs_online/$vg"
+
# should not show an active lv
rm out
lvs -o active $vg |tee out || true
@@ -215,23 +244,211 @@ not grep "active" out
mdadm --assemble "$mddev" "$dev1" "$dev2"
aux udev_wait
-# Now that the md dev is online, pvs can see it
-# and check for components even if
-# md_component_checks is "start" (which disables
-# most default end-of-device scans)
-aux lvmconf 'devices/md_component_checks = "start"'
+not pvs "$dev1"
+not pvs "$dev2"
+pvs > out
+not grep "$dev1" out
+not grep "$dev2" out
+
+lvs $vg
+vgchange -an $vg
+
+# should not activate from the md legs
+_clear_online_files
+pvscan --cache -aay "$dev1"
+pvscan --cache -aay "$dev2"
+
+not ls "$RUNDIR/lvm/pvs_online/$PVIDMD"
+not ls "$RUNDIR/lvm/vgs_online/$vg"
+
+# should not show an active lv
+rm out
+lvs -o active $vg |tee out || true
+not grep "active" out
+
+vgchange -ay $vg
+
+check lv_field $vg/$lv1 lv_active "active"
+
+vgchange -an $vg
+
+_clear_online_files
+pvscan --cache -aay "$mddev"
+
+ls "$RUNDIR/lvm/pvs_online/$PVIDMD"
+ls "$RUNDIR/lvm/vgs_online/$vg"
+
+lvs -o active $vg |tee out || true
+grep "active" out
+
+vgchange -an $vg
+
+aux udev_wait
+
+vgremove -f $vg
+
+aux cleanup_md_dev
+
+# Repeat tests using the default config settings
+
+aux lvmconf 'devices/hints = "all"'
+aux lvmconf 'devices/obtain_device_list_from_udev = 1'
+
+# create 2 disk MD raid0 array
+# by default using metadata format 1.0 with data at the end of device
+# When a raid0 md array is stopped, the components will not look like
+# duplicate PVs as they do with raid1.
+aux prepare_md_dev 0 64 2 "$dev1" "$dev2"
+
+cat /proc/mdstat
+
+mddev=$(< MD_DEV)
+pvdev=$(< MD_DEV_PV)
+
+# Create an unused PV so that there is at least one PV in the hints
+# when the MD dev is stopped. If there are no PVs, the hints are
+# empty, and the code falls back to scanning all, and we do not end
+# up testing the code with hints actively used.
+pvcreate "$dev3"
+
+vgcreate $vg "$mddev"
+
+PVIDMD=`pvs $mddev --noheading -o uuid | tr -d - | awk '{print $1}'`
+echo $PVIDMD
+
+lvcreate -n $lv1 -l 2 $vg
+lvcreate -n $lv2 -l 2 -an $vg
+
+lvchange -ay $vg/$lv2
+check lv_field $vg/$lv1 lv_active "active"
+
+# lvm does not show md components as PVs
+pvs "$mddev"
+not pvs "$dev1"
+not pvs "$dev2"
+pvs > out
+not grep "$dev1" out
+not grep "$dev2" out
+
+grep "$mddev" /run/lvm/hints
+grep "$dev3" /run/lvm/hints
+not grep "$dev1" /run/lvm/hints
+not grep "$dev2" /run/lvm/hints
+
+sleep 1
+
+vgchange -an $vg
+sleep 1
+
+# When the md device is started, lvm will see that and know to
+# scan for md components, so stop the md device to remove this
+# advantage so we will test the fallback detection.
+mdadm --stop "$mddev"
+aux udev_wait
+
+# A WARNING indicating duplicate PVs is printed by 'pvs' in this
+# case. It's printed during the scan, but after the scan, the
+# md component detection is run on the devs and they are dropped
+# when we see they are md components. So, we ignore the warning
+# containing the word duplicate, and look for the "Not using device"
+# message, which shouldn't appear, as it would indicate that
+# we didn't drop the md components.
+# FIXME: we should avoid printing the premature warning indicating
+# duplicate PVs which are eventually recognized as md components
+# and dropped.
+pvs 2>&1|tee out1
+grep -v WARNING out1 > out2
+not grep "Not using device" out2
+not grep "$mddev" out2
+not grep "$dev1" out2
+not grep "$dev2" out2
+grep "$dev3" out2
+cat /run/lvm/hints
+
+pvs 2>&1|tee out1
+grep -v WARNING out1 > out2
+not grep "Not using device" out2
+not grep "$mddev" out2
+not grep "$dev1" out2
+not grep "$dev2" out2
+grep "$dev3" out2
+cat /run/lvm/hints
+# The md components should still be detected and excluded.
not pvs "$dev1"
not pvs "$dev2"
pvs > out
not grep "$dev1" out
not grep "$dev2" out
+grep "$dev3" out
-vgchange -ay $vg 2>&1 |tee out
+# should not activate from the md legs
+not vgchange -ay $vg
+
+# should not show an active lv
+rm out
+lvs -o active $vg |tee out || true
+not grep "active" out
+
+# should not allow updating vg
+not lvcreate -l1 $vg
+
+# should not activate from the md legs
+_clear_online_files
+pvscan --cache -aay "$dev1"
+pvscan --cache -aay "$dev2"
+
+not ls "$RUNDIR/lvm/pvs_online/$PVIDMD"
+not ls "$RUNDIR/lvm/vgs_online/$vg"
+
+# should not show an active lv
+rm out
+lvs -o active $vg |tee out || true
+not grep "active" out
+
+# start the md dev
+mdadm --assemble "$mddev" "$dev1" "$dev2"
+aux udev_wait
+
+not pvs "$dev1"
+not pvs "$dev2"
+pvs > out
+not grep "$dev1" out
+not grep "$dev2" out
+
+lvs $vg
+vgchange -an $vg
+
+# should not activate from the md legs
+_clear_online_files
+pvscan --cache -aay "$dev1"
+pvscan --cache -aay "$dev2"
+
+not ls "$RUNDIR/lvm/pvs_online/$PVIDMD"
+not ls "$RUNDIR/lvm/vgs_online/$vg"
+
+# should not show an active lv
+rm out
+lvs -o active $vg |tee out || true
+not grep "active" out
+
+vgchange -ay $vg
check lv_field $vg/$lv1 lv_active "active"
vgchange -an $vg
+
+_clear_online_files
+pvscan --cache -aay "$mddev"
+
+ls "$RUNDIR/lvm/pvs_online/$PVIDMD"
+ls "$RUNDIR/lvm/vgs_online/$vg"
+
+lvs -o active $vg |tee out || true
+grep "active" out
+
+vgchange -an $vg
+
aux udev_wait
vgremove -f $vg
4 years, 8 months
master - enable full md component detection at the right time
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=4567c6a2b2f4f2662ef...
Commit: 4567c6a2b2f4f2662ef909887640681c8bba0e02
Parent: b16abb3816408a296343a75658d4be0ef688390b
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Jul 9 14:48:31 2019 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Jul 10 13:30:50 2019 -0500
enable full md component detection at the right time
An active md device with an end superblock causes lvm to
enable full md component detection. This was being done
within the filter loop instead of before, so the full
filtering of some devs could be missed.
Also incorporate the recently added config setting that
controls the md component detection.
---
lib/device/dev-cache.c | 19 +++++++++++++++++++
lib/device/dev-cache.h | 3 +++
lib/device/dev-md.c | 6 +++---
lib/label/label.c | 27 ++++++++++++++-------------
tools/pvscan.c | 7 +++++++
5 files changed, 46 insertions(+), 16 deletions(-)
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
index 1492181..980dd3c 100644
--- a/lib/device/dev-cache.c
+++ b/lib/device/dev-cache.c
@@ -15,6 +15,7 @@
#include "base/memory/zalloc.h"
#include "lib/misc/lib.h"
+#include "lib/device/dev-type.h"
#include "lib/datastruct/btree.h"
#include "lib/config/config.h"
#include "lib/commands/toolcontext.h"
@@ -1634,3 +1635,21 @@ const char *dev_name(const struct device *dev)
return (dev && dev->aliases.n) ? dm_list_item(dev->aliases.n, struct dm_str_list)->str :
unknown_device_name();
}
+
+bool dev_cache_has_md_with_end_superblock(struct dev_types *dt)
+{
+ struct btree_iter *iter = btree_first(_cache.devices);
+ struct device *dev;
+
+ while (iter) {
+ dev = btree_get_data(iter);
+
+ if (dev_is_md_with_end_superblock(dt, dev))
+ return true;
+
+ iter = btree_next(iter);
+ }
+
+ return false;
+}
+
diff --git a/lib/device/dev-cache.h b/lib/device/dev-cache.h
index 8a1c277..46c86c2 100644
--- a/lib/device/dev-cache.h
+++ b/lib/device/dev-cache.h
@@ -17,6 +17,7 @@
#define _LVM_DEV_CACHE_H
#include "lib/device/device.h"
+#include "lib/device/dev-type.h"
#include "lib/misc/lvm-wrappers.h"
struct cmd_context;
@@ -71,4 +72,6 @@ void dev_reset_error_count(struct cmd_context *cmd);
void dev_cache_failed_path(struct device *dev, const char *path);
+bool dev_cache_has_md_with_end_superblock(struct dev_types *dt);
+
#endif
diff --git a/lib/device/dev-md.c b/lib/device/dev-md.c
index 08143b7..9d0a363 100644
--- a/lib/device/dev-md.c
+++ b/lib/device/dev-md.c
@@ -302,12 +302,12 @@ static int _md_sysfs_attribute_scanf(struct dev_types *dt,
return ret;
if (!(fp = fopen(path, "r"))) {
- log_sys_error("fopen", path);
+ log_debug("_md_sysfs_attribute_scanf fopen failed %s", path);
return ret;
}
if (!fgets(buffer, sizeof(buffer), fp)) {
- log_sys_error("fgets", path);
+ log_debug("_md_sysfs_attribute_scanf fgets failed %s", path);
goto out;
}
@@ -449,7 +449,7 @@ int dev_is_md_with_end_superblock(struct dev_types *dt, struct device *dev)
if (_md_sysfs_attribute_scanf(dt, dev, attribute,
"%s", &version_string) != 1)
- return -1;
+ return 0;
log_very_verbose("Device %s %s is %s.",
dev_name(dev), attribute, version_string);
diff --git a/lib/label/label.c b/lib/label/label.c
index 8b841f6..fb7ad1d 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -894,6 +894,20 @@ int label_scan(struct cmd_context *cmd)
dev_cache_scan();
/*
+ * If we know that there will be md components with an end
+ * superblock, then enable the full md filter before label
+ * scan begins. FIXME: we could skip the full md check on
+ * devs that are not identified as PVs, but then we'd need
+ * to do something other than using the standard md filter.
+ */
+ if (cmd->md_component_detection && !cmd->use_full_md_check &&
+ !strcmp(cmd->md_component_checks, "auto") &&
+ dev_cache_has_md_with_end_superblock(cmd->dev_types)) {
+ log_debug("Enable full md component check.");
+ cmd->use_full_md_check = 1;
+ }
+
+ /*
* Set up the iterator that is needed to step through each device in
* dev cache.
*/
@@ -931,19 +945,6 @@ int label_scan(struct cmd_context *cmd)
bcache_invalidate_fd(scan_bcache, dev->bcache_fd);
_scan_dev_close(dev);
}
-
- /*
- * When md devices exist that use the old superblock at the
- * end of the device, then in order to detect and filter out
- * the component devices of those md devs, we enable the full
- * md filter which scans both the start and the end of every
- * device. This doubles the amount of scanning i/o, which we
- * want to avoid. FIXME: this forces start+end scanning of
- * every device, but it would be more efficient to limit the
- * end scan only to PVs.
- */
- if (dev_is_md_with_end_superblock(cmd->dev_types, dev))
- cmd->use_full_md_check = 1;
};
dev_iter_destroy(iter);
diff --git a/tools/pvscan.c b/tools/pvscan.c
index facc70c..2a88eaa 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -938,6 +938,13 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
/* Creates a list of dev names from /dev, sysfs, etc; does not read any. */
dev_cache_scan();
+ if (cmd->md_component_detection && !cmd->use_full_md_check &&
+ !strcmp(cmd->md_component_checks, "auto") &&
+ dev_cache_has_md_with_end_superblock(cmd->dev_types)) {
+ log_debug("Enable full md component check.");
+ cmd->use_full_md_check = 1;
+ }
+
/*
* For each device command arg (from either position or --major/--minor),
* decide if that device is being added to the system (a dev node exists
4 years, 8 months
master - pvscan: fix PV online when device has a different size
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=b16abb3816408a29634...
Commit: b16abb3816408a296343a75658d4be0ef688390b
Parent: f17353e3e604ad2d80bcd77ea0a6a93472e6b5bd
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Jul 9 13:45:09 2019 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jul 9 13:45:09 2019 -0500
pvscan: fix PV online when device has a different size
Fix commit 7836e7aa1c17216ed368fda89cfc805a07efda81
"pvscan: ignore device with incorrect size"
which caused pvscan to not consider a PV online (for purposes
of event based activation) if the PV and device sizes differed.
This helped to avoid mistaking MD components for PVs, and is
replaced by triggering an md component check when PV and device
sizes differ (which happens in set_pv_device).
---
tools/pvscan.c | 40 ++++++++++------------------------------
1 files changed, 10 insertions(+), 30 deletions(-)
diff --git a/tools/pvscan.c b/tools/pvscan.c
index 12711cb..facc70c 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -621,6 +621,16 @@ static int _online_pvscan_one(struct cmd_context *cmd, struct device *dev,
set_pv_devices(baton.fid, baton.vg);
}
+ /* This check repeated because set_pv_devices can do new md check. */
+ if (dev->flags & DEV_IS_MD_COMPONENT) {
+ log_print("pvscan[%d] PV %s ignore MD component, ignore metadata.", getpid(), dev_name(dev));
+ if (baton.vg)
+ release_vg(baton.vg);
+ else
+ fmt->ops->destroy_instance(baton.fid);
+ return 1;
+ }
+
if (baton.vg && vg_is_shared(baton.vg)) {
log_print("pvscan[%d] PV %s ignore shared VG.", getpid(), dev_name(dev));
release_vg(baton.vg);
@@ -638,36 +648,6 @@ static int _online_pvscan_one(struct cmd_context *cmd, struct device *dev,
return 1;
}
- /*
- * Do not consider a device online (for purposes of autoactivation)
- * if its size does not match the PV size recorded in the metadata.
- * It may mean that it's not the correct dev for the PV, e.g. it
- * could be an md component device that's not been filtered.
- */
- if (baton.vg && cmd->check_pv_dev_sizes) {
- struct pv_list *pvl;
- uint64_t dev_size = 0;
- uint64_t meta_pv_size = 0;
-
- dm_list_iterate_items(pvl, &baton.vg->pvs) {
- if (pvl->pv->dev != dev)
- continue;
-
- if (!dev_get_size(dev, &dev_size))
- stack;
- meta_pv_size = pv_size(pvl->pv);
- break;
- }
-
- if (dev_size != meta_pv_size) {
- log_print("pvscan[%d] PV %s ignore for size %llu not matching device %llu.",
- getpid(), dev_name(dev),
- (unsigned long long)meta_pv_size, (unsigned long long)dev_size);
- release_vg(baton.vg);
- return 1;
- }
- }
-
ret = _online_pv_found(cmd, dev, dev_args, baton.vg, found_vgnames);
/*
4 years, 8 months
master - md component detection for differing PV and device sizes
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=f17353e3e604ad2d80b...
Commit: f17353e3e604ad2d80bcd77ea0a6a93472e6b5bd
Parent: d2b88f271512c56737e27bbdfbd0e0b6891b4cd0
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Jul 9 13:32:41 2019 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jul 9 13:40:41 2019 -0500
md component detection for differing PV and device sizes
This check was mistakenly removed when shifting code in commit
"separate code for setting devices from metadata parsing".
Put it back with some new conditions.
---
lib/metadata/metadata.c | 26 ++++++++++++++++++++++++--
1 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 121cf4f..f19df3d 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -3504,19 +3504,41 @@ static void _set_pv_device(struct format_instance *fid,
struct physical_volume *pv)
{
char buffer[64] __attribute__((aligned(8)));
+ struct cmd_context *cmd = fid->fmt->cmd;
+ struct device *dev;
uint64_t size;
- if (!(pv->dev = lvmcache_device_from_pvid(fid->fmt->cmd, &pv->id, &pv->label_sector))) {
+ if (!(dev = lvmcache_device_from_pvid(cmd, &pv->id, &pv->label_sector))) {
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
buffer[0] = '\0';
- if (fid->fmt->cmd && !fid->fmt->cmd->pvscan_cache_single)
+ if (cmd && !cmd->pvscan_cache_single)
log_warn("WARNING: Couldn't find device with uuid %s.", buffer);
else
log_debug_metadata("Couldn't find device with uuid %s.", buffer);
}
/*
+ * If the device and PV are not the size, it's a clue that we might
+ * be reading an MD component (but not necessarily). Skip this check:
+ * . if md component detection is disabled
+ * . if we are already doing full a md check in label scan
+ * . if md_component_checks is auto, not none (full means use_full_md_check is set)
+ */
+ if (dev && (pv->size != dev->size) && cmd &&
+ cmd->md_component_detection &&
+ !cmd->use_full_md_check &&
+ !strcmp(cmd->md_component_checks, "auto")) {
+ if (dev_is_md_component(dev, NULL, 1)) {
+ log_warn("WARNING: device %s is an md component, not setting device for PV.",
+ dev_name(dev));
+ dev = NULL;
+ }
+ }
+
+ pv->dev = dev;
+
+ /*
* A previous command wrote the VG while this dev was missing, so
* the MISSING flag was included in the PV.
*/
4 years, 8 months
master - scan: remove unused arg to setup_bcache
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=d2b88f271512c56737e...
Commit: d2b88f271512c56737e27bbdfbd0e0b6891b4cd0
Parent: 1b63a219f4f9d7f2f6c5086375b96c3bd892a1a0
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Jul 9 13:16:26 2019 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jul 9 13:16:26 2019 -0500
scan: remove unused arg to setup_bcache
---
lib/label/label.c | 17 +++++------------
1 files changed, 5 insertions(+), 12 deletions(-)
diff --git a/lib/label/label.c b/lib/label/label.c
index 185e51b..8b841f6 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -798,13 +798,6 @@ out:
}
/*
- * num_devs is the number of devices the caller is going to scan.
- * When 0 the caller doesn't know, and we use the default cache size.
- * When non-zero, allocate at least num_devs bcache blocks.
- * num_devs doesn't really tell us how many bcache blocks we'll use
- * because it includes lvm devs and non-lvm devs, and each lvm dev
- * will often use a number of bcache blocks.
- *
* We don't know ahead of time if we will find some VG metadata
* that is larger than the total size of the bcache, which would
* prevent us from reading/writing the VG since we do not dynamically
@@ -817,7 +810,7 @@ out:
#define MIN_BCACHE_BLOCKS 32 /* 4MB */
#define MAX_BCACHE_BLOCKS 1024
-static int _setup_bcache(int num_devs)
+static int _setup_bcache(void)
{
struct io_engine *ioe = NULL;
int iomem_kb = io_memory_size();
@@ -955,7 +948,7 @@ int label_scan(struct cmd_context *cmd)
dev_iter_destroy(iter);
if (!scan_bcache) {
- if (!_setup_bcache(dm_list_size(&all_devs)))
+ if (!_setup_bcache())
return 0;
}
@@ -1105,7 +1098,7 @@ int label_scan_devs(struct cmd_context *cmd, struct dev_filter *f, struct dm_lis
struct device_list *devl;
if (!scan_bcache) {
- if (!_setup_bcache(0))
+ if (!_setup_bcache())
return 0;
}
@@ -1132,7 +1125,7 @@ int label_scan_devs_rw(struct cmd_context *cmd, struct dev_filter *f, struct dm_
struct device_list *devl;
if (!scan_bcache) {
- if (!_setup_bcache(0))
+ if (!_setup_bcache())
return 0;
}
@@ -1278,7 +1271,7 @@ int label_read(struct device *dev)
int label_scan_setup_bcache(void)
{
if (!scan_bcache) {
- if (!_setup_bcache(0))
+ if (!_setup_bcache())
return 0;
}
4 years, 8 months
master - lvconvert: allow --stripes/--stripesize in 'mirror' conversions
by Heinz Mauelshagen
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=1b63a219f4f9d7f2f6c...
Commit: 1b63a219f4f9d7f2f6c5086375b96c3bd892a1a0
Parent: fef8e506891bd159475de83f248fdac660675163
Author: Heinz Mauelshagen <heinzm(a)redhat.com>
AuthorDate: Mon Jul 8 19:07:18 2019 +0200
Committer: Heinz Mauelshagen <heinzm(a)redhat.com>
CommitterDate: Mon Jul 8 19:32:17 2019 +0200
lvconvert: allow --stripes/--stripesize in 'mirror' conversions
This allows the creation of a striped mirror leg(s) during upconvert
by adding lvconvert command line options --stripes/--stripesize
for 'mirror' to tools/command-lines.in.
In case multiple mirror legs are being added, all will have the
same requested striped layout.
Resolves: rhbz1720705
---
tools/command-lines.in | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/tools/command-lines.in b/tools/command-lines.in
index 73a1e64..f914650 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -343,13 +343,11 @@ DESC: Convert LV to striped.
RULE: all not lv_is_locked lv_is_pvmove
lvconvert --type mirror LV
-OO: --mirrors SNumber, --regionsize RegionSize, --interval Number, --mirrorlog MirrorLog, OO_LVCONVERT
+OO: --mirrors SNumber, --stripes_long Number, --stripesize SizeKB, --regionsize RegionSize, --interval Number, --mirrorlog MirrorLog, OO_LVCONVERT
OP: PV ...
ID: lvconvert_raid_types
DESC: Convert LV to type mirror (also see type raid1),
-DESC: (also see lvconvert --mirrors).
RULE: all not lv_is_locked lv_is_pvmove
-FLAGS: SECONDARY_SYNTAX
# When LV is already raid, this changes the raid layout
# (changing layout of raid0 and raid1 not allowed.)
4 years, 8 months