diff options
author | David Teigland <teigland@redhat.com> | 2019-02-05 13:09:56 -0600 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2019-04-11 12:03:04 -0500 |
commit | ce8d1ed13011290000bb26bc3de32c1f27a7fd08 (patch) | |
tree | c257dc087c37802c7ede602cfd8fb73043e694b6 | |
parent | a812f98c425821fef85cd973d92071ed5533f7c3 (diff) | |
download | lvm2-ce8d1ed13011290000bb26bc3de32c1f27a7fd08.tar.gz |
keep track of which mdas have old metadata in lvmcache
This will be used for more advanced repair in a
subsequent commit.
-rw-r--r-- | lib/cache/lvmcache.c | 161 | ||||
-rw-r--r-- | lib/cache/lvmcache.h | 8 |
2 files changed, 138 insertions, 31 deletions
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c index e512cc7de..c43a05c02 100644 --- a/lib/cache/lvmcache.c +++ b/lib/cache/lvmcache.c @@ -40,6 +40,10 @@ struct lvmcache_info { uint32_t ext_version; /* Extension version */ uint32_t ext_flags; /* Extension flags */ uint32_t status; + int summary_seqno; /* vg seqno found on this dev during scan */ + int mda1_seqno; + int mda2_seqno; + unsigned summary_seqno_mismatch:1; /* two mdas on this dev has mismatching metadata */ unsigned mda1_bad:1; /* label scan found bad metadata in mda1 */ unsigned mda2_bad:1; /* label scan found bad metadata in mda2 */ }; @@ -1517,12 +1521,9 @@ int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt) } /* - * FIXME: get rid of other callers of this function which call it - * in odd cases to "fix up" some bit of lvmcache state. Make those - * callers fix up what they need to directly, and leave this function - * with one purpose and caller. + * Returning 0 causes the caller to remove the info struct for this + * device from lvmcache, which will make it look like a missing device. */ - int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vgsummary *vgsummary) { const char *vgname = vgsummary->vgname; @@ -1548,6 +1549,7 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vg * Puts the vginfo into the vgname hash table. */ if (!_lvmcache_update_vgname(info, vgname, vgid, vgsummary->vgstatus, vgsummary->creation_host, info->fmt)) { + /* shouldn't happen, internal error */ log_error("Failed to update VG %s info in lvmcache.", vgname); return 0; } @@ -1556,6 +1558,7 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vg * Puts the vginfo into the vgid hash table. */ if (!_lvmcache_update_vgid(info, info->vginfo, vgid)) { + /* shouldn't happen, internal error */ log_error("Failed to update VG %s info in lvmcache.", vgname); return 0; } @@ -1571,50 +1574,114 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vg if (!vgsummary->seqno && !vgsummary->mda_size && !vgsummary->mda_checksum) return 1; + /* + * Keep track of which devs/mdas have old versions of the metadata. + * The values we keep in vginfo are from the metadata with the largest + * seqno. One dev may have more recent metadata than another dev, and + * one mda may have more recent metadata than the other mda on the same + * device. + * + * When a device holds old metadata, the info struct for the device + * remains in lvmcache, so the device is not treated as missing. + * Also the mda struct containing the old metadata is kept on + * info->mdas. This means that vg_read will read metadata from + * the mda again (and probably see the same old metadata). It + * also means that vg_write will use the mda to write new metadata + * into the mda that currently has the old metadata. + */ + if (vgsummary->mda_num == 1) + info->mda1_seqno = vgsummary->seqno; + else if (vgsummary->mda_num == 2) + info->mda2_seqno = vgsummary->seqno; + + if (!info->summary_seqno) + info->summary_seqno = vgsummary->seqno; + else { + if (info->summary_seqno == vgsummary->seqno) { + /* This mda has the same metadata as the prev mda on this dev. */ + return 1; + + } else if (info->summary_seqno > vgsummary->seqno) { + /* This mda has older metadata than the prev mda on this dev. */ + info->summary_seqno_mismatch = 1; + + } else if (info->summary_seqno < vgsummary->seqno) { + /* This mda has newer metadata than the prev mda on this dev. */ + info->summary_seqno_mismatch = 1; + info->summary_seqno = vgsummary->seqno; + } + } + + /* this shouldn't happen */ if (!(vginfo = info->vginfo)) return 1; if (!vginfo->seqno) { vginfo->seqno = vgsummary->seqno; + vginfo->mda_checksum = vgsummary->mda_checksum; + vginfo->mda_size = vgsummary->mda_size; - log_debug_cache("lvmcache %s: VG %s: set seqno to %d", - dev_name(info->dev), vginfo->vgname, vginfo->seqno); + log_debug_cache("lvmcache %s mda%d VG %s set seqno %u checksum %x mda_size %zu", + dev_name(info->dev), vgsummary->mda_num, vgname, + vgsummary->seqno, vgsummary->mda_checksum, vgsummary->mda_size); + goto update_vginfo; - } else if (vgsummary->seqno != vginfo->seqno) { - log_warn("Scan of VG %s from %s found metadata seqno %d vs previous %d.", - vgname, dev_name(info->dev), vgsummary->seqno, vginfo->seqno); + } else if (vgsummary->seqno < vginfo->seqno) { vginfo->scan_summary_mismatch = 1; - /* If we don't return success, this dev info will be removed from lvmcache, - and then we won't be able to rescan it or repair it. */ + + log_debug_cache("lvmcache %s mda%d VG %s older seqno %u checksum %x mda_size %zu", + dev_name(info->dev), vgsummary->mda_num, vgname, + vgsummary->seqno, vgsummary->mda_checksum, vgsummary->mda_size); return 1; - } - if (!vginfo->mda_size) { + } else if (vgsummary->seqno > vginfo->seqno) { + vginfo->scan_summary_mismatch = 1; + + /* Replace vginfo values with values from newer metadata. */ + vginfo->seqno = vgsummary->seqno; vginfo->mda_checksum = vgsummary->mda_checksum; vginfo->mda_size = vgsummary->mda_size; - log_debug_cache("lvmcache %s: VG %s: set mda_checksum to %x mda_size to %zu", - dev_name(info->dev), vginfo->vgname, - vginfo->mda_checksum, vginfo->mda_size); + log_debug_cache("lvmcache %s mda%d VG %s newer seqno %u checksum %x mda_size %zu", + dev_name(info->dev), vgsummary->mda_num, vgname, + vgsummary->seqno, vgsummary->mda_checksum, vgsummary->mda_size); - } else if ((vginfo->mda_size != vgsummary->mda_size) || (vginfo->mda_checksum != vgsummary->mda_checksum)) { - log_warn("Scan of VG %s from %s found mda_checksum %x mda_size %zu vs previous %x %zu", - vgname, dev_name(info->dev), vgsummary->mda_checksum, vgsummary->mda_size, - vginfo->mda_checksum, vginfo->mda_size); - vginfo->scan_summary_mismatch = 1; - /* If we don't return success, this dev info will be removed from lvmcache, - and then we won't be able to rescan it or repair it. */ + goto update_vginfo; + } else { + /* + * Same seqno as previous metadata we saw for this VG. + * If the metadata somehow has a different checksum or size, + * even though it has the same seqno, something has gone wrong. + * FIXME: test this case: VG has two PVs, first goes missing, + * second updated to seqno 4, first comes back and second goes + * missing, first updated to seqno 4, second comes back, now + * both are present with same seqno but different checksums. + */ + + if ((vginfo->mda_size != vgsummary->mda_size) || (vginfo->mda_checksum != vgsummary->mda_checksum)) { + log_warn("WARNING: scan of VG %s from %s mda%d found mda_checksum %x mda_size %zu vs %x %zu", + vgname, dev_name(info->dev), vgsummary->mda_num, + vgsummary->mda_checksum, vgsummary->mda_size, + vginfo->mda_checksum, vginfo->mda_size); + vginfo->scan_summary_mismatch = 1; + return 0; + } + + /* + * The seqno and checksum matches what was previously seen; + * the summary values have already been saved in vginfo. + */ return 1; } - /* - * If a dev has an unmatching checksum, ignore the other - * info from it, keeping the info we already saved. - */ + update_vginfo: if (!_lvmcache_update_vgstatus(info, vgsummary->vgstatus, vgsummary->creation_host, vgsummary->lock_type, vgsummary->system_id)) { + /* + * This shouldn't happen, it's an internal errror, and we can leave + * the info in place without saving the summary values in vginfo. + */ log_error("Failed to update VG %s info in lvmcache.", vgname); - return 0; } return 1; @@ -2366,6 +2433,42 @@ int lvmcache_vginfo_has_pvid(struct lvmcache_vginfo *vginfo, char *pvid) return 0; } +/* + * This is used by the metadata repair command to check if + * the metadata on a dev needs repair because it's old. + */ +int lvmcache_has_old_metadata(struct cmd_context *cmd, const char *vgname, const char *vgid, struct device *dev) +{ + struct lvmcache_vginfo *vginfo; + struct lvmcache_info *info; + + /* shouldn't happen */ + if (!vgname || !vgid) + return 0; + + /* shouldn't happen */ + if (!(vginfo = lvmcache_vginfo_from_vgid(vgid))) + return 0; + + /* shouldn't happen */ + if (!(info = lvmcache_info_from_pvid(dev->pvid, NULL, 0))) + return 0; + + /* writing to a new PV */ + if (!info->summary_seqno) + return 0; + + /* on same dev, one mda has newer metadata than the other */ + if (info->summary_seqno_mismatch) + return 1; + + /* one or both mdas on this dev has older metadata than another dev */ + if (vginfo->seqno > info->summary_seqno) + return 1; + + return 0; +} + void lvmcache_get_outdated_devs(struct cmd_context *cmd, const char *vgname, const char *vgid, struct dm_list *devs) diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h index cccc60c47..c11563396 100644 --- a/lib/cache/lvmcache.h +++ b/lib/cache/lvmcache.h @@ -57,10 +57,12 @@ struct lvmcache_vgsummary { char *creation_host; const char *system_id; const char *lock_type; + uint32_t seqno; uint32_t mda_checksum; size_t mda_size; - int zero_offset; - int seqno; + int mda_num; /* 1 = summary from mda1, 2 = summary from mda2 */ + unsigned mda_ignored:1; + unsigned zero_offset:1; }; int lvmcache_init(struct cmd_context *cmd); @@ -217,6 +219,8 @@ int dev_in_device_list(struct device *dev, struct dm_list *head); int lvmcache_has_bad_metadata(struct device *dev); +int lvmcache_has_old_metadata(struct cmd_context *cmd, const char *vgname, const char *vgid, struct device *dev); + void lvmcache_get_outdated_devs(struct cmd_context *cmd, const char *vgname, const char *vgid, struct dm_list *devs); |