diff options
author | David Teigland <teigland@redhat.com> | 2021-09-28 14:58:03 -0500 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2021-09-28 15:17:43 -0500 |
commit | 939b4bc58719605aa7d348d2b4e0fcf41aad0b17 (patch) | |
tree | eacfa44671b0c0b14036f2b2195e9e5cb55dd6a2 | |
parent | e3b4c365a4d9fc3f88dcfaca6dff89b924fc4851 (diff) | |
download | lvm2-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.c | 14 | ||||
-rw-r--r-- | lib/cache/lvmcache.h | 2 | ||||
-rw-r--r-- | lib/format_text/format-text.c | 18 | ||||
-rw-r--r-- | lib/format_text/import.c | 5 | ||||
-rw-r--r-- | lib/metadata/metadata.c | 2 | ||||
-rw-r--r-- | 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" |