diff options
-rw-r--r-- | lib/cache/lvmcache.c | 31 | ||||
-rw-r--r-- | lib/cache/lvmcache.h | 4 | ||||
-rw-r--r-- | lib/format_text/text_label.c | 18 | ||||
-rw-r--r-- | lib/metadata/metadata-exported.h | 2 | ||||
-rw-r--r-- | lib/metadata/metadata.c | 35 | ||||
-rw-r--r-- | tools/vgck.c | 11 |
6 files changed, 88 insertions, 13 deletions
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c index 99e36eed5..12fee84a0 100644 --- a/lib/cache/lvmcache.c +++ b/lib/cache/lvmcache.c @@ -31,6 +31,7 @@ struct lvmcache_info { struct dm_list mdas; /* list head for metadata areas */ struct dm_list das; /* list head for data areas */ struct dm_list bas; /* list head for bootloader areas */ + struct dm_list bad_mdas;/* list head for bad metadata areas */ struct lvmcache_vginfo *vginfo; /* NULL == unknown */ struct label *label; const struct format_type *fmt; @@ -209,6 +210,32 @@ void lvmcache_set_bad_metadata(struct lvmcache_info *info, int mda1_bad, int mda info->mda2_bad = 1; } +void lvmcache_save_bad_mda(struct lvmcache_info *info, struct metadata_area *mda) +{ + dm_list_add(&info->bad_mdas, &mda->list); +} + +void lvmcache_get_bad_mdas(struct cmd_context *cmd, + const char *vgname, const char *vgid, + struct dm_list *bad_mdas) +{ + struct lvmcache_vginfo *vginfo; + struct lvmcache_info *info; + struct metadata_area *mda, *mda2; + + if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid))) { + log_error(INTERNAL_ERROR "lvmcache_get_bad_mdas no vginfo %s", vgname); + return; + } + + dm_list_iterate_items(info, &vginfo->infos) { + dm_list_iterate_items_safe(mda, mda2, &info->bad_mdas) { + dm_list_del(&mda->list); + dm_list_add(bad_mdas, &mda->list); + } + } +} + static void _vginfo_attach_info(struct lvmcache_vginfo *vginfo, struct lvmcache_info *info) { @@ -2186,6 +2213,10 @@ void lvmcache_del_mdas(struct lvmcache_info *info) if (info->mdas.n) del_mdas(&info->mdas); dm_list_init(&info->mdas); + + if (info->bad_mdas.n) + del_mdas(&info->bad_mdas); + dm_list_init(&info->bad_mdas); } void lvmcache_del_das(struct lvmcache_info *info) diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h index daff75b62..bc9e3ab61 100644 --- a/lib/cache/lvmcache.h +++ b/lib/cache/lvmcache.h @@ -235,4 +235,8 @@ int lvmcache_is_outdated_dev(struct cmd_context *cmd, void lvmcache_del_outdated_devs(struct cmd_context *cmd, const char *vgname, const char *vgid); +void lvmcache_get_bad_mdas(struct cmd_context *cmd, + const char *vgname, const char *vgid, + struct dm_list *bad_mdas); + #endif diff --git a/lib/format_text/text_label.c b/lib/format_text/text_label.c index c8a8329f4..fd0072b97 100644 --- a/lib/format_text/text_label.c +++ b/lib/format_text/text_label.c @@ -492,7 +492,8 @@ static int _text_read(struct labeller *labeller, struct device *dev, void *label 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); + dm_list_del(&mda1->list); + lvmcache_save_bad_mda(info, mda1); mda1 = NULL; mda1_bad = 1; bad_mda_count++; @@ -505,8 +506,10 @@ static int _text_read(struct labeller *labeller, struct device *dev, void *label 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); + log_warn("WARNING: repair VG metadata on %s with vgck --updatemetadata.", dev_name(dev)); + /* save it so we can find it to repair it later if needed */ + dm_list_del(&mda1->list); + lvmcache_save_bad_mda(info, mda1); mda1 = NULL; mda1_bad = 1; bad_mda_count++; @@ -524,7 +527,8 @@ static int _text_read(struct labeller *labeller, struct device *dev, void *label 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); + dm_list_del(&mda2->list); + lvmcache_save_bad_mda(info, mda2); mda2 = NULL; mda2_bad = 1; bad_mda_count++; @@ -537,8 +541,10 @@ static int _text_read(struct labeller *labeller, struct device *dev, void *label 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); + log_warn("WARNING: repair VG metadata on %s with vgck --updatemetadata.", dev_name(dev)); + /* save it so we can find it to repair it later if needed */ + dm_list_del(&mda2->list); + lvmcache_save_bad_mda(info, mda2); mda2 = NULL; mda2_bad = 1; bad_mda_count++; diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h index 0fabaf703..6691bd17a 100644 --- a/lib/metadata/metadata-exported.h +++ b/lib/metadata/metadata-exported.h @@ -1367,4 +1367,6 @@ int vg_strip_outdated_historical_lvs(struct volume_group *vg); int lv_on_pmem(struct logical_volume *lv); +void update_bad_mdas(struct cmd_context *cmd, struct volume_group *vg); + #endif diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index ce430799e..6672feb8c 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -5148,3 +5148,38 @@ struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_ return vg; } +void update_bad_mdas(struct cmd_context *cmd, struct volume_group *vg) +{ + struct dm_list bad_mdas; + struct metadata_area *mda; + struct device *dev; + + dm_list_init(&bad_mdas); + + lvmcache_get_bad_mdas(cmd, vg->name, (const char *)&vg->id, &bad_mdas); + + /* FIXME: validate that mda locations are sane before trying to write them */ + + dm_list_iterate_items(mda, &bad_mdas) { + dev = mda_get_device(mda); + + if (!mda->ops->vg_write(vg->fid, vg, mda)) { + log_warn("WARNING: failed to write VG %s metadata to bad mda at %llu on %s.", + vg->name, (unsigned long long)mda->header_start, dev_name(dev)); + continue; + } + + if (!mda->ops->vg_precommit(vg->fid, vg, mda)) { + log_warn("WARNING: failed to precommit VG %s metadata to bad mda at %llu on %s.", + vg->name, (unsigned long long)mda->header_start, dev_name(dev)); + continue; + } + + if (!mda->ops->vg_commit(vg->fid, vg, mda)) { + log_warn("WARNING: failed to commit VG %s metadata to bad mda at %llu on %s.", + vg->name, (unsigned long long)mda->header_start, dev_name(dev)); + continue; + } + } +} + diff --git a/tools/vgck.c b/tools/vgck.c index 7cdd5ff5f..d71fcee24 100644 --- a/tools/vgck.c +++ b/tools/vgck.c @@ -28,13 +28,6 @@ static int _update_metadata_single(struct cmd_context *cmd __attribute__((unused struct volume_group *vg, struct processing_handle *handle __attribute__((unused))) { - /* - * TODO: when bad mda's are seen, remove them from info->mdas - * as we do already, but then save the mda in a new info->bad_mdas - * list. Then when we get here we can check if the mdas on the - * bad_mdas list look sensible enough to write to. - */ - if (!vg_write(vg)) { log_error("Failed to write VG."); return 0; @@ -45,6 +38,10 @@ static int _update_metadata_single(struct cmd_context *cmd __attribute__((unused return 0; } + /* bad mdas are not in fid->metadata_areas_in_use, this + function gets them from lvmcache and tries to write this metadata to them */ + update_bad_mdas(cmd, vg); + return 1; } |