summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2021-09-28 14:58:03 -0500
committerDavid Teigland <teigland@redhat.com>2021-09-28 15:17:43 -0500
commit939b4bc58719605aa7d348d2b4e0fcf41aad0b17 (patch)
treeeacfa44671b0c0b14036f2b2195e9e5cb55dd6a2
parente3b4c365a4d9fc3f88dcfaca6dff89b924fc4851 (diff)
downloadlvm2-939b4bc58719605aa7d348d2b4e0fcf41aad0b17.tar.gz
handle bad metadata text in vg_read path
Corrupt metadata text (with good mda header) was being handled in the label_scan phase, but not in the vg_read phase. This was sufficient because metadata areas would always be read and checksummed during label_scan (metadata parsing was skipped previously as an optimization.) This changed with the optimization in commit 61a6f9905e87e650f0bddae83fec6923bb100a57 "metadata: optimize reading metadata copies in scan" Now, some metadata areas will not be read and checksummed at all during the label_scan phase, only during the vg_read phase. This means that bad metadata text may first be detected in the vg_read phase. So, add equivalent bad metadata handling to the vg_read path to match the label_scan path.
-rw-r--r--lib/cache/lvmcache.c14
-rw-r--r--lib/cache/lvmcache.h2
-rw-r--r--lib/format_text/format-text.c18
-rw-r--r--lib/format_text/import.c5
-rw-r--r--lib/metadata/metadata.c2
-rw-r--r--test/shell/metadata-bad-text.sh23
6 files changed, 49 insertions, 15 deletions
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 655f34bd8..7a7634074 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -237,6 +237,20 @@ void lvmcache_save_bad_mda(struct lvmcache_info *info, struct metadata_area *mda
dm_list_add(&info->bad_mdas, &mda->list);
}
+void lvmcache_del_save_bad_mda(struct lvmcache_info *info, int mda_num, int bad_mda_flag)
+{
+ struct metadata_area *mda, *mda_safe;
+
+ dm_list_iterate_items_safe(mda, mda_safe, &info->mdas) {
+ if (mda->mda_num == mda_num) {
+ dm_list_del(&mda->list);
+ mda->bad_fields |= bad_mda_flag;
+ lvmcache_save_bad_mda(info, mda);
+ break;
+ }
+ }
+}
+
void lvmcache_get_bad_mdas(struct cmd_context *cmd,
const char *vgname, const char *vgid,
struct dm_list *bad_mda_list)
diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h
index d7e10f4f0..9511bb9e9 100644
--- a/lib/cache/lvmcache.h
+++ b/lib/cache/lvmcache.h
@@ -210,6 +210,8 @@ void lvmcache_del_outdated_devs(struct cmd_context *cmd,
void lvmcache_save_bad_mda(struct lvmcache_info *info, struct metadata_area *mda);
+void lvmcache_del_save_bad_mda(struct lvmcache_info *info, int mda_num, int bad_mda_flag);
+
void lvmcache_get_bad_mdas(struct cmd_context *cmd,
const char *vgname, const char *vgid,
struct dm_list *bad_mda_list);
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index c880f0eb6..6a4cc98d8 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -465,6 +465,24 @@ static struct volume_group *_vg_read_raw(struct cmd_context *cmd,
vg = _vg_read_raw_area(cmd, fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 0, mda_is_primary(mda));
+ if (!vg && !*use_previous_vg) {
+ /*
+ * This condition (corrupt metadata text) is often seen in the
+ * label_scan()/_text_read() phase, where this code corresponds to
+ * the lvmcache_save_bad_mda() in _text_read(). In this case we
+ * have two mda structs to deal with, one in lvmcache from label scan,
+ * and the mda copy on fid->metadata_areas_in_use.
+ */
+ struct device *dev = mdac->area.dev;
+ struct lvmcache_info *info = lvmcache_info_from_pvid(dev->pvid, dev, 0);
+ log_warn("WARNING: reading %s mda%d failed to read metadata.", dev_name(dev), mda_is_primary(mda)?1:2);
+ log_warn("WARNING: repair VG metadata on %s with vgck --updatemetadata.", dev_name(dev));
+ /* remove mda from lvmcache, saving it in info->bad_mdas for possible repair with updatemetadata */
+ lvmcache_del_save_bad_mda(info, mda->mda_num, BAD_MDA_TEXT);
+ /* remove mda from fid */
+ fid_remove_mda(fid, mda, NULL, 0, 0);
+ }
+
return vg;
}
diff --git a/lib/format_text/import.c b/lib/format_text/import.c
index e4e526354..a3735369d 100644
--- a/lib/format_text/import.c
+++ b/lib/format_text/import.c
@@ -157,13 +157,12 @@ struct volume_group *text_read_metadata(struct format_instance *fid,
if (!config_file_read_fd(cft, dev, MDA_CONTENT_REASON(primary_mda), offset, size,
offset2, size2, checksum_fn, checksum,
skip_parse, 1)) {
- /* FIXME: handle errors */
- log_error("Couldn't read volume group metadata from %s.", dev_name(dev));
+ log_warn("WARNING: couldn't read volume group metadata from %s.", dev_name(dev));
goto out;
}
} else {
if (!config_file_read(cft)) {
- log_error("Couldn't read volume group metadata from file.");
+ log_warn("WARNING: couldn't read volume group metadata from file.");
goto out;
}
}
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index b37b91487..9a7d23365 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -4798,7 +4798,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
* fid->metadata_areas_in_use by create_instance above, and here we
* read VG metadata from each of those mdas.
*/
- dm_list_iterate_items(mda, &fid->metadata_areas_in_use) {
+ dm_list_iterate_items_safe(mda, mda2, &fid->metadata_areas_in_use) {
mda_dev = mda_get_device(mda);
/* I don't think this can happen */
diff --git a/test/shell/metadata-bad-text.sh b/test/shell/metadata-bad-text.sh
index 9ccfe5f76..038a88485 100644
--- a/test/shell/metadata-bad-text.sh
+++ b/test/shell/metadata-bad-text.sh
@@ -44,7 +44,7 @@ sed 's/flags =/flagx =/' meta1 > meta1.bad
dd if=meta1.bad of="$dev1"
pvs 2>&1 | tee out
-grep "bad metadata text" out
+grep "Checksum error" out
pvs "$dev1"
pvs "$dev2"
@@ -58,7 +58,7 @@ lvcreate -l1 $vg
vgck --updatemetadata $vg
pvs 2>&1 | tee out
-not grep "bad metadata text" out
+not grep "Checksum error" out
pvs "$dev1"
pvs "$dev2"
@@ -92,7 +92,8 @@ dd if=meta1.bad of="$dev1"
dd if=meta2.bad of="$dev2"
pvs 2>&1 | tee out
-grep "bad metadata text" out > out2
+# FIXME: find a better test than looking for a specific message
+grep "Checksum error" out > out2
grep "$dev1" out2
grep "$dev2" out2
@@ -108,7 +109,7 @@ lvcreate -l1 $vg
vgck --updatemetadata $vg
pvs 2>&1 | tee out
-not grep "bad metadata text" out
+not grep "Checksum error" out
pvs "$dev1"
pvs "$dev2"
@@ -149,7 +150,7 @@ dd if=meta2.bad of="$dev2"
dd if=meta3.bad of="$dev3"
pvs 2>&1 | tee out
-grep "bad metadata text" out > out2
+grep "Checksum error" out > out2
grep "$dev1" out2
grep "$dev2" out2
grep "$dev3" out2
@@ -166,7 +167,7 @@ lvcreate -l1 $vg
vgck --updatemetadata $vg
pvs 2>&1 | tee out
-not grep "bad metadata text" out
+not grep "Checksum error" out
pvs "$dev1"
pvs "$dev2"
@@ -197,7 +198,7 @@ sed 's/READ/RRRR/' meta1 > meta1.bad
dd if=meta1.bad of="$dev1"
pvs 2>&1 | tee out
-grep "bad metadata text" out > out2
+grep "Checksum error" out > out2
grep "$dev1" out2
# We can still use the VG with other available
@@ -224,7 +225,7 @@ aux enable_dev "$dev2"
# Both old and bad metadata are reported.
pvs 2>&1 | tee out
grep "ignoring metadata seqno" out
-grep "bad metadata text" out
+grep "Checksum error" out
pvs "$dev1"
pvs "$dev2"
pvs "$dev3"
@@ -238,7 +239,7 @@ vgck --updatemetadata $vg
pvs 2>&1 | tee out
not grep "ignoring metadata seqno" out
-not grep "bad metadata text" out
+not grep "Checksum error" out
pvs "$dev1"
pvs "$dev2"
pvs "$dev3"
@@ -282,7 +283,7 @@ dd if=meta1.bad of="$dev1"
dd if=meta2.bad of="$dev2"
pvs 2>&1 | tee out
-grep "bad metadata text" out > out2
+grep "Checksum error" out > out2
grep "$dev1" out2
grep "$dev2" out2
@@ -319,7 +320,7 @@ not ls "$RUNDIR/lvm/vgs_online/$vg"
vgck --updatemetadata $vg
pvs 2>&1 | tee out
-not grep "bad metadata text" out
+not grep "Checksum error" out
pvs "$dev1"
pvs "$dev2"