summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/cache/lvmcache.c31
-rw-r--r--lib/cache/lvmcache.h4
-rw-r--r--lib/format_text/text_label.c18
-rw-r--r--lib/metadata/metadata-exported.h2
-rw-r--r--lib/metadata/metadata.c35
-rw-r--r--tools/vgck.c11
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;
}