]> sourceware.org Git - lvm2.git/commitdiff
vgck --updatemetadata is a new command
authorDavid Teigland <teigland@redhat.com>
Wed, 6 Feb 2019 19:39:41 +0000 (13:39 -0600)
committerDavid Teigland <teigland@redhat.com>
Fri, 7 Jun 2019 20:54:04 +0000 (15:54 -0500)
uses vg_write to correct more common or less severe issues,
and also adds the ability to repair some metadata corruption
that couldn't be handled previously.

lib/format_text/text_label.c
lib/metadata/metadata-exported.h
lib/metadata/metadata.c
lib/metadata/metadata.h
tools/args.h
tools/command-lines.in
tools/commands.h
tools/vgck.c

index 42184dec73552fac7e5dbe6922e383ccb8dcfd32..170293409c61e6db3815aaa3647cafdfe2107c83 100644 (file)
@@ -341,6 +341,9 @@ static int _read_mda_header_and_metadata(struct metadata_area *mda, void *baton)
                goto fail;
        }
 
+       if (mda)
+               mda->header_start = mdah->start;
+
        mda_set_ignored(mda, rlocn_is_ignored(mdah->raw_locns));
 
        if (mda_is_ignored(mda)) {
index 219c784e9496501517f0de47237c469c6a04d4ca..3af89061dde40a6bec59b0497bda6ea6a73a7579 100644 (file)
@@ -1381,4 +1381,6 @@ int lv_on_pmem(struct logical_volume *lv);
 
 int vg_is_foreign(struct volume_group *vg);
 
+void vg_write_commit_bad_mdas(struct cmd_context *cmd, struct volume_group *vg);
+
 #endif
index 804d0cf4a8711c06b3232001c1ccadf7b4c024b6..5eabfa68f4b0f27f8493cb56edac5ba888024f1c 100644 (file)
@@ -5597,3 +5597,86 @@ int vg_is_foreign(struct volume_group *vg)
        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;
+               }
+       }
+}
index 6d158fe8a3cb81acc0c7247754e240f51c589428..63ee4a619bce2c6045d12969d33c3175d2c83034 100644 (file)
@@ -185,6 +185,7 @@ struct metadata_area {
        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 */
index 69f7e079023a20f4ac26d524a4669d4c587c667e..e972c7dd9e6fafd4dc4a2903bb73620ef4196c83 100644 (file)
@@ -1393,6 +1393,9 @@ arg(thin_ARG, 'T', "thin", 0, 0, 0,
     "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"
index 03dbf571df9e954edb68a3de3bbef40a5e62749d..4601239f2968c490b2f9abf89f2803c56ff26937 100644 (file)
@@ -1624,6 +1624,11 @@ vgck
 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.
 
 ---
 
index 612182b45837ebb6c7c54f1997b0e73683019f5d..4006fab216ddd59a668ab40f6d8376a8fa6ec142 100644 (file)
@@ -177,7 +177,7 @@ xx(vgchange,
 
 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",
index a126c29247f2f2455b84f3a4de314669a086c12e..90fc5a3aa29277180ccd6babcec4e1b1abdc88b3 100644 (file)
 
 #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,
@@ -37,6 +88,9 @@ static int vgck_single(struct cmd_context *cmd __attribute__((unused)),
 
 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);
 }
This page took 0.050127 seconds and 5 git commands to generate.