All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Teigland <teigland@sourceware.org>
To: lvm-devel@redhat.com
Subject: main - handle bad metadata text in vg_read path
Date: Tue, 28 Sep 2021 20:24:08 +0000 (GMT)	[thread overview]
Message-ID: <20210928202408.8DF523858406@sourceware.org> (raw)

Gitweb:        https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=939b4bc58719605aa7d348d2b4e0fcf41aad0b17
Commit:        939b4bc58719605aa7d348d2b4e0fcf41aad0b17
Parent:        e3b4c365a4d9fc3f88dcfaca6dff89b924fc4851
Author:        David Teigland <teigland@redhat.com>
AuthorDate:    Tue Sep 28 14:58:03 2021 -0500
Committer:     David Teigland <teigland@redhat.com>
CommitterDate: Tue Sep 28 15:17:43 2021 -0500

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.
---
 lib/cache/lvmcache.c            | 14 ++++++++++++++
 lib/cache/lvmcache.h            |  2 ++
 lib/format_text/format-text.c   | 18 ++++++++++++++++++
 lib/format_text/import.c        |  5 ++---
 lib/metadata/metadata.c         |  2 +-
 test/shell/metadata-bad-text.sh | 23 ++++++++++++-----------
 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"



                 reply	other threads:[~2021-09-28 20:24 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210928202408.8DF523858406@sourceware.org \
    --to=teigland@sourceware.org \
    --cc=lvm-devel@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.