goto fail;
}
+ if (mda)
+ mda->header_start = mdah->start;
+
mda_set_ignored(mda, rlocn_is_ignored(mdah->raw_locns));
if (mda_is_ignored(mda)) {
int vg_is_foreign(struct volume_group *vg);
+void vg_write_commit_bad_mdas(struct cmd_context *cmd, struct volume_group *vg);
+
#endif
return _is_foreign_vg(vg);
}
+void vg_write_commit_bad_mdas(struct cmd_context *cmd, struct volume_group *vg)
+{
+ struct dm_list bad_mda_list;
+ struct mda_list *mdal;
+ struct metadata_area *mda;
+ struct device *dev;
+
+ dm_list_init(&bad_mda_list);
+
+ lvmcache_get_bad_mdas(cmd, vg->name, (const char *)&vg->id, &bad_mda_list);
+
+ dm_list_iterate_items(mdal, &bad_mda_list) {
+ mda = mdal->mda;
+ dev = mda_get_device(mda);
+
+ /*
+ * bad_fields:
+ *
+ * 0: shouldn't happen
+ *
+ * READ|INTERNAL: there's probably nothing wrong on disk
+ *
+ * MAGIC|START: there's a good chance that we were
+ * reading the mda_header from the wrong location; maybe
+ * the pv_header location was wrong. We don't want to
+ * write new metadata to the wrong location. To handle
+ * this we would want to do some further verification that
+ * we have the mda location correct.
+ *
+ * VERSION|CHECKSUM: when the others are correct these
+ * look safe to repair.
+ *
+ * HEADER: general error related to header, covered by fields
+ * above.
+ *
+ * TEXT: general error related to text metadata, we can repair.
+ */
+ if (!mda->bad_fields ||
+ (mda->bad_fields & BAD_MDA_READ) ||
+ (mda->bad_fields & BAD_MDA_INTERNAL) ||
+ (mda->bad_fields & BAD_MDA_MAGIC) ||
+ (mda->bad_fields & BAD_MDA_START)) {
+ log_warn("WARNING: not repairing bad metadata (0x%x) for mda%d on %s",
+ mda->bad_fields, mda->mda_num, dev_name(dev));
+ continue;
+ }
+
+ /*
+ * vg_write/vg_commit reread the mda_header which checks the
+ * mda header fields and fails if any are bad, which stops
+ * vg_write/vg_commit from continuing. Suppress these header
+ * field checks when we know the field is bad and we are going
+ * to replace it. FIXME: do vg_write/vg_commit really need to
+ * reread and recheck the mda_header again (probably not)?
+ */
+
+ if (mda->bad_fields & BAD_MDA_CHECKSUM)
+ mda->ignore_bad_fields |= BAD_MDA_CHECKSUM;
+ if (mda->bad_fields & BAD_MDA_VERSION)
+ mda->ignore_bad_fields |= BAD_MDA_VERSION;
+
+ log_warn("WARNING: repairing bad metadata (0x%x) in mda%d at %llu on %s.",
+ mda->bad_fields, mda->mda_num, (unsigned long long)mda->header_start, dev_name(dev));
+
+ if (!mda->ops->vg_write(vg->fid, vg, mda)) {
+ log_warn("WARNING: failed to write VG %s metadata to bad mda%d at %llu on %s.",
+ vg->name, mda->mda_num, (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%d at %llu on %s.",
+ vg->name, mda->mda_num, (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%d at %llu on %s.",
+ vg->name, mda->mda_num, (unsigned long long)mda->header_start, dev_name(dev));
+ continue;
+ }
+ }
+}
struct metadata_area_ops *ops;
void *metadata_locn;
uint32_t status;
+ uint64_t header_start; /* mda_header.start */
int mda_num;
uint32_t bad_fields; /* BAD_MDA_ flags are set to indicate errors found when reading */
uint32_t ignore_bad_fields; /* BAD_MDA_ flags are set to indicate errors to ignore */
"See --type thin, --type thin-pool, and --virtualsize.\n"
"See \\fBlvmthin\\fP(7) for more information about LVM thin provisioning.\n")
+arg(updatemetadata_ARG, '\0', "updatemetadata", 0, 0, 0,
+ "Update VG metadata to correct problems.\n")
+
arg(uuid_ARG, 'u', "uuid", 0, 0, 0,
"#pvchange\n"
"Generate new random UUID for specified PVs.\n"
OO: --reportformat ReportFmt
OP: VG|Tag ...
ID: vgck_general
+DESC: Read and display information about a VG.
+
+vgck --updatemetadata VG
+ID: vgck_update_metadata
+DESC: Rewrite VG metadata to correct problems.
---
xx(vgck,
"Check the consistency of volume group(s)",
- ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | ALLOW_HINTS)
+ ALL_VGS_IS_DEFAULT | LOCKD_VG_SH)
xx(vgconvert,
"Change volume group metadata format",
#include "tools.h"
+/*
+ * TODO: we cannot yet repair corruption in label_header, pv_header/locations,
+ * or corruption of some mda_header fields.
+ */
+
+static int _update_metadata_single(struct cmd_context *cmd __attribute__((unused)),
+ const char *vg_name,
+ struct volume_group *vg,
+ struct processing_handle *handle __attribute__((unused)))
+{
+
+ /*
+ * Simply calling vg_write can correct or clean up various things:
+ * . some mda's have old versions of metdadata
+ * . wipe outdated PVs
+ * . fix pv_header used flag and version
+ * . strip historical lvs
+ * . clear missing pv flag on unused PV
+ */
+ if (!vg_write(vg)) {
+ log_error("Failed to write VG.");
+ return 0;
+ }
+
+ if (!vg_commit(vg)) {
+ log_error("Failed to commit VG.");
+ return 0;
+ }
+
+ /*
+ * vg_write does not write to "bad" mdas (where "bad" is corrupt, can't
+ * be processed when reading). bad mdas are not kept in
+ * fid->metadata_areas_in_use so vg_read and vg_write ignore them, but
+ * they are saved in lvmcache. this gets them from lvmcache and tries
+ * to write this metadata to them.
+ */
+ vg_write_commit_bad_mdas(cmd, vg);
+
+ return 1;
+}
+
+static int _update_metadata(struct cmd_context *cmd, int argc, char **argv)
+{
+ cmd->handles_missing_pvs = 1;
+ cmd->wipe_outdated_pvs = 1;
+ cmd->handles_unknown_segments = 1;
+
+ return process_each_vg(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, 0, NULL,
+ &_update_metadata_single);
+}
+
static int vgck_single(struct cmd_context *cmd __attribute__((unused)),
const char *vg_name,
struct volume_group *vg,
int vgck(struct cmd_context *cmd, int argc, char **argv)
{
+ if (arg_is_set(cmd, updatemetadata_ARG))
+ return _update_metadata(cmd, argc, argv);
+
return process_each_vg(cmd, argc, argv, NULL, NULL, 0, 0, NULL,
&vgck_single);
}