summaryrefslogtreecommitdiff
path: root/lib/format_text/text_label.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/format_text/text_label.c')
-rw-r--r--lib/format_text/text_label.c202
1 files changed, 155 insertions, 47 deletions
diff --git a/lib/format_text/text_label.c b/lib/format_text/text_label.c
index 7d10e065b..f95d3ea61 100644
--- a/lib/format_text/text_label.c
+++ b/lib/format_text/text_label.c
@@ -240,11 +240,10 @@ void del_bas(struct dm_list *bas)
del_das(bas);
}
-/* FIXME: refactor this function with other mda constructor code */
int add_mda(const struct format_type *fmt, struct dm_pool *mem, struct dm_list *mdas,
- struct device *dev, uint64_t start, uint64_t size, unsigned ignored)
+ struct device *dev, uint64_t start, uint64_t size, unsigned ignored,
+ struct metadata_area **mda_new)
{
-/* FIXME List size restricted by pv_header SECTOR_SIZE */
struct metadata_area *mdal, *mda;
struct mda_lists *mda_lists = (struct mda_lists *) fmt->private;
struct mda_context *mdac, *mdac2;
@@ -294,9 +293,18 @@ int add_mda(const struct format_type *fmt, struct dm_pool *mem, struct dm_list *
mda_set_ignored(mdal, ignored);
dm_list_add(mdas, &mdal->list);
+ if (mda_new)
+ *mda_new = mdal;
return 1;
}
+static void _del_mda(struct metadata_area *mda)
+{
+ dm_free(mda->metadata_locn);
+ dm_list_del(&mda->list);
+ dm_free(mda);
+}
+
void del_mdas(struct dm_list *mdas)
{
struct dm_list *mdah, *tmp;
@@ -304,9 +312,7 @@ void del_mdas(struct dm_list *mdas)
dm_list_iterate_safe(mdah, tmp, mdas) {
mda = dm_list_item(mdah, struct metadata_area);
- dm_free(mda->metadata_locn);
- dm_list_del(&mda->list);
- dm_free(mda);
+ _del_mda(mda);
}
}
@@ -318,72 +324,84 @@ static int _text_initialise_label(struct labeller *l __attribute__((unused)),
return 1;
}
-struct _update_mda_baton {
- struct lvmcache_info *info;
- struct label *label;
-};
-
-static int _read_mda_header_and_metadata(struct metadata_area *mda, void *baton)
+static int _read_mda_header_and_metadata(const struct format_type *fmt,
+ struct metadata_area *mda, int mda_num,
+ struct lvmcache_vgsummary *vgsummary)
{
- struct _update_mda_baton *p = baton;
- const struct format_type *fmt = p->label->labeller->fmt;
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
struct mda_header *mdah;
- struct lvmcache_vgsummary vgsummary = { 0 };
if (!(mdah = raw_read_mda_header(fmt, &mdac->area, mda_is_primary(mda)))) {
- log_error("Failed to read mda header from %s", dev_name(mdac->area.dev));
- goto fail;
+ log_warn("WARNING: bad metadata header on %s at %llu.",
+ dev_name(mdac->area.dev),
+ (unsigned long long)mdac->area.start);
+ return 0;
}
+ if (mda)
+ mda->header_start = mdah->start;
+
mda_set_ignored(mda, rlocn_is_ignored(mdah->raw_locns));
if (mda_is_ignored(mda)) {
log_debug_metadata("Ignoring mda on device %s at offset " FMTu64,
dev_name(mdac->area.dev),
mdac->area.start);
+ vgsummary->mda_ignored = 1;
return 1;
}
if (!read_metadata_location_summary(fmt, mdah, mda_is_primary(mda), &mdac->area,
- &vgsummary, &mdac->free_sectors)) {
- if (vgsummary.zero_offset)
+ vgsummary, &mdac->free_sectors)) {
+ if (vgsummary->zero_offset)
return 1;
- log_error("Failed to read metadata summary from %s", dev_name(mdac->area.dev));
- goto fail;
- }
-
- if (!lvmcache_update_vgname_and_id(p->info, &vgsummary)) {
- log_error("Failed to save lvm summary for %s", dev_name(mdac->area.dev));
- goto fail;
+ log_warn("WARNING: bad metadata text on %s in mda%d",
+ dev_name(mdac->area.dev), mda_num);
+ return 0;
}
return 1;
-
-fail:
- lvmcache_del(p->info);
- return 0;
}
-static int _text_read(struct labeller *l, struct device *dev, void *label_buf,
+/*
+ * Used by label_scan to get a summary of the VG that exists on this PV. This
+ * summary is stored in lvmcache vginfo/info/info->mdas and is used later by
+ * vg_read which needs to know which PVs to read for a given VG name, and where
+ * the metadata is at for those PVs.
+ */
+
+static int _text_read(struct labeller *labeller, struct device *dev, void *label_buf,
struct label **label)
{
+ struct lvmcache_vgsummary vgsummary;
+ struct lvmcache_info *info;
+ const struct format_type *fmt = labeller->fmt;
struct label_header *lh = (struct label_header *) label_buf;
struct pv_header *pvhdr;
struct pv_header_extension *pvhdr_ext;
- struct lvmcache_info *info;
+ struct metadata_area *mda;
+ struct metadata_area *mda1 = NULL;
+ struct metadata_area *mda2 = NULL;
struct disk_locn *dlocn_xl;
uint64_t offset;
uint32_t ext_version;
- struct _update_mda_baton baton;
+ int mda_count = 0;
+ int good_mda_count = 0;
+ int bad_mda_count = 0;
+ int mda1_bad = 0;
+ int mda2_bad = 0;
+ int rv1, rv2;
/*
* PV header base
*/
pvhdr = (struct pv_header *) ((char *) label_buf + xlate32(lh->offset_xl));
- if (!(info = lvmcache_add(l, (char *)pvhdr->pv_uuid, dev,
+ /* FIXME: errors from lvmcache_add need to be handled better */
+ /* FIXME: stop pretending that the PV is initially an orphan. */
+
+ if (!(info = lvmcache_add(labeller, (char *)pvhdr->pv_uuid, dev,
FMT_TEXT_ORPHAN_VG_NAME,
FMT_TEXT_ORPHAN_VG_NAME, 0)))
return_0;
@@ -403,11 +421,23 @@ static int _text_read(struct labeller *l, struct device *dev, void *label_buf,
dlocn_xl++;
}
- /* Metadata area headers */
dlocn_xl++;
+
+ /* Metadata areas */
while ((offset = xlate64(dlocn_xl->offset))) {
- lvmcache_add_mda(info, dev, offset, xlate64(dlocn_xl->size), 0);
+
+ /*
+ * This just calls add_mda() above, replacing info with info->mdas.
+ */
+ lvmcache_add_mda(info, dev, offset, xlate64(dlocn_xl->size), 0, &mda);
+
dlocn_xl++;
+ mda_count++;
+
+ if (mda_count == 1)
+ mda1 = mda;
+ else if (mda_count == 2)
+ mda2 = mda;
}
dlocn_xl++;
@@ -417,7 +447,7 @@ static int _text_read(struct labeller *l, struct device *dev, void *label_buf,
*/
pvhdr_ext = (struct pv_header_extension *) ((char *) dlocn_xl);
if (!(ext_version = xlate32(pvhdr_ext->version)))
- goto out;
+ goto scan_mdas;
log_debug_metadata("%s: PV header extension version " FMTu32 " found",
dev_name(dev), ext_version);
@@ -434,22 +464,100 @@ static int _text_read(struct labeller *l, struct device *dev, void *label_buf,
lvmcache_add_ba(info, offset, xlate64(dlocn_xl->size));
dlocn_xl++;
}
-out:
- baton.info = info;
- baton.label = *label;
+
+ scan_mdas:
+ if (!mda_count) {
+ log_debug_metadata("Scanning %s found no mdas.", dev_name(dev));
+ return 1;
+ }
+
+ if (mda1) {
+ log_debug_metadata("Scanning %s mda1 summary.", dev_name(dev));
+ memset(&vgsummary, 0, sizeof(vgsummary));
+ vgsummary.mda_num = 1;
+
+ rv1 = _read_mda_header_and_metadata(fmt, mda1, 1, &vgsummary);
+
+ if (rv1 && !vgsummary.zero_offset && !vgsummary.mda_ignored) {
+ if (!lvmcache_update_vgname_and_id(info, &vgsummary)) {
+ /* I believe this is only an internal error. */
+ log_warn("Scanning %s mda1 failed to save summary.", dev_name(dev));
+ _del_mda(mda1);
+ mda1 = NULL;
+ mda1_bad = 1;
+ bad_mda_count++;
+ } else {
+ log_warn("Scanned %s mda1 seqno %u", dev_name(dev), vgsummary.seqno);
+ good_mda_count++;
+ }
+ }
+
+ if (!rv1) {
+ /* Remove the bad mda so vg_read won't try to read it. */
+ log_warn("WARNING: scanning %s mda1 failed to read metadata summary.", dev_name(dev));
+ log_warn("WARNING: repair VG metadata on %s with vgck --repairmetadata.", dev_name(dev));
+ _del_mda(mda1);
+ mda1 = NULL;
+ mda1_bad = 1;
+ bad_mda_count++;
+ }
+ }
+
+ if (mda2) {
+ log_debug_metadata("Scanning %s mda2 summary.", dev_name(dev));
+ memset(&vgsummary, 0, sizeof(vgsummary));
+ vgsummary.mda_num = 2;
+
+ rv2 = _read_mda_header_and_metadata(fmt, mda2, 2, &vgsummary);
+
+ if (rv2 && !vgsummary.zero_offset && !vgsummary.mda_ignored) {
+ if (!lvmcache_update_vgname_and_id(info, &vgsummary)) {
+ /* I believe this is only an internal error. */
+ log_warn("Scanning %s mda2 failed to save summary.", dev_name(dev));
+ _del_mda(mda2);
+ mda2 = NULL;
+ mda2_bad = 1;
+ bad_mda_count++;
+ } else {
+ log_warn("Scanned %s mda2 seqno %u", dev_name(dev), vgsummary.seqno);
+ good_mda_count++;
+ }
+ }
+
+ if (!rv2) {
+ /* Remove the bad mda so vg_read won't try to read it. */
+ log_warn("WARNING: scanning %s mda2 failed to read metadata summary.", dev_name(dev));
+ log_warn("WARNING: repair VG metadata on %s with vgck --repairmetadata.", dev_name(dev));
+ _del_mda(mda2);
+ mda2 = NULL;
+ mda2_bad = 1;
+ bad_mda_count++;
+ }
+ }
+
+ log_debug_metadata("Scanning %s found mda_count %d mda1_bad %d mda2_bad %d",
+ dev_name(dev), mda_count, mda1_bad, mda2_bad);
/*
- * In the vg_read phase, we compare all mdas and decide which to use
- * which are bad and need repair.
+ * Track which devs have bad metadata so repair can find them
+ * (even if this dev also has good metadata that we are able to use).
*
- * FIXME: this quits if the first mda is bad, but we need something
- * smarter to be able to use the second mda if it's good.
+ * When bad metadata is seen above, the unusable mda struct is
+ * removed from lvmcache info->mdas. This means that vg_read will
+ * skip the bad mda not try to read the bad metadata. It also means
+ * that vg_write will also skip the bad mda and not try to write
+ * new metadata to it.
*/
- if (!lvmcache_foreach_mda(info, _read_mda_header_and_metadata, &baton)) {
- log_error("Failed to scan VG from %s", dev_name(dev));
+ if (mda1_bad || mda2_bad)
+ lvmcache_set_bad_metadata(info, mda1_bad, mda2_bad);
+
+ if (good_mda_count)
+ return 1;
+
+ if (bad_mda_count)
return 0;
- }
+ /* no metadata in the mdas */
return 1;
}