diff options
Diffstat (limited to 'lib/format_text/text_label.c')
-rw-r--r-- | lib/format_text/text_label.c | 202 |
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; } |