mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-03 05:18:29 +03:00
move wipe_outdated_pvs to vg_write
and implement it based on a device, not based on a pv struct (which is not available when the device is not a part of the vg.) currently only the vgremove command wipes outdated pvs until more advanced recovery is added in a subsequent commit
This commit is contained in:
parent
45b164f62c
commit
ab61a6d85d
@ -179,6 +179,7 @@ struct cmd_context {
|
||||
unsigned use_hints:1; /* if hints are enabled this cmd can use them */
|
||||
unsigned pvscan_recreate_hints:1; /* enable special case hint handling for pvscan --cache */
|
||||
unsigned scan_lvs:1;
|
||||
unsigned wipe_outdated_pvs:1;
|
||||
|
||||
/*
|
||||
* Devices and filtering.
|
||||
|
@ -2463,3 +2463,36 @@ bad:
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int text_wipe_outdated_pv_mda(struct cmd_context *cmd, struct device *dev,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
struct mda_context *mdac = mda->metadata_locn;
|
||||
uint64_t start_byte = mdac->area.start;
|
||||
struct mda_header *mdab;
|
||||
struct raw_locn *rlocn_slot0;
|
||||
struct raw_locn *rlocn_slot1;
|
||||
uint32_t bad_fields = 0;
|
||||
|
||||
if (!(mdab = raw_read_mda_header(cmd->fmt, &mdac->area, mda_is_primary(mda), 0, &bad_fields))) {
|
||||
log_error("Failed to read outdated pv mda header on %s", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
rlocn_slot0 = &mdab->raw_locns[0];
|
||||
rlocn_slot1 = &mdab->raw_locns[1];
|
||||
|
||||
rlocn_slot0->offset = 0;
|
||||
rlocn_slot0->size = 0;
|
||||
rlocn_slot0->checksum = 0;
|
||||
rlocn_slot1->offset = 0;
|
||||
rlocn_slot1->size = 0;
|
||||
rlocn_slot1->checksum = 0;
|
||||
|
||||
if (!_raw_write_mda_header(cmd->fmt, dev, mda_is_primary(mda), start_byte, mdab)) {
|
||||
log_error("Failed to write outdated pv mda header on %s", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -77,4 +77,7 @@ struct data_area_list {
|
||||
struct disk_locn disk_locn;
|
||||
};
|
||||
|
||||
int text_wipe_outdated_pv_mda(struct cmd_context *cmd, struct device *dev,
|
||||
struct metadata_area *mda);
|
||||
|
||||
#endif
|
||||
|
@ -28,11 +28,14 @@
|
||||
#include "lib/display/display.h"
|
||||
#include "lib/locking/locking.h"
|
||||
#include "lib/format_text/archiver.h"
|
||||
#include "lib/format_text/format-text.h"
|
||||
#include "lib/format_text/layout.h"
|
||||
#include "lib/format_text/import-export.h"
|
||||
#include "lib/config/defaults.h"
|
||||
#include "lib/locking/lvmlockd.h"
|
||||
#include "time.h"
|
||||
#include "lib/notify/lvmnotify.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
|
||||
static struct physical_volume *_pv_read(struct cmd_context *cmd,
|
||||
@ -2922,6 +2925,69 @@ static int _handle_historical_lvs(struct volume_group *vg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _wipe_outdated_pvs(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
struct dm_list devs;
|
||||
struct dm_list *mdas = NULL;
|
||||
struct device_list *devl;
|
||||
struct device *dev;
|
||||
struct metadata_area *mda;
|
||||
struct label *label;
|
||||
struct lvmcache_info *info;
|
||||
uint32_t ext_flags;
|
||||
|
||||
dm_list_init(&devs);
|
||||
|
||||
/*
|
||||
* When vg_read selected a good copy of the metadata, it used it to
|
||||
* update the lvmcache representation of the VG (lvmcache_update_vg).
|
||||
* At that point outdated PVs were recognized and moved into the
|
||||
* vginfo->outdated_infos list. Here we clear the PVs on that list.
|
||||
*/
|
||||
|
||||
lvmcache_get_outdated_devs(cmd, vg->name, (const char *)&vg->id, &devs);
|
||||
|
||||
dm_list_iterate_items(devl, &devs) {
|
||||
dev = devl->dev;
|
||||
|
||||
lvmcache_get_outdated_mdas(cmd, vg->name, (const char *)&vg->id, dev, &mdas);
|
||||
|
||||
if (mdas) {
|
||||
dm_list_iterate_items(mda, mdas) {
|
||||
log_warn("WARNING: wiping mda on outdated PV %s", dev_name(dev));
|
||||
|
||||
if (!text_wipe_outdated_pv_mda(cmd, dev, mda))
|
||||
log_warn("WARNING: failed to wipe mda on outdated PV %s", dev_name(dev));
|
||||
}
|
||||
}
|
||||
|
||||
if (!(label = lvmcache_get_dev_label(dev))) {
|
||||
log_error("_wipe_outdated_pvs no label for %s", dev_name(dev));
|
||||
continue;
|
||||
}
|
||||
|
||||
info = label->info;
|
||||
ext_flags = lvmcache_ext_flags(info);
|
||||
ext_flags &= ~PV_EXT_USED;
|
||||
lvmcache_set_ext_version(info, PV_HEADER_EXTENSION_VSN);
|
||||
lvmcache_set_ext_flags(info, ext_flags);
|
||||
|
||||
log_warn("WARNING: wiping header on outdated PV %s", dev_name(dev));
|
||||
|
||||
if (!label_write(dev, label))
|
||||
log_warn("WARNING: failed to wipe header on outdated PV %s", dev_name(dev));
|
||||
|
||||
lvmcache_del(info);
|
||||
}
|
||||
|
||||
/*
|
||||
* A vgremove will involve many vg_write() calls (one for each lv
|
||||
* removed) but we only need to wipe pvs once, so clear the outdated
|
||||
* list so it won't be wiped again.
|
||||
*/
|
||||
lvmcache_del_outdated_devs(cmd, vg->name, (const char *)&vg->id);
|
||||
}
|
||||
|
||||
/*
|
||||
* After vg_write() returns success,
|
||||
* caller MUST call either vg_commit() or vg_revert()
|
||||
@ -2986,6 +3052,9 @@ int vg_write(struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vg->cmd->wipe_outdated_pvs)
|
||||
_wipe_outdated_pvs(vg->cmd, vg);
|
||||
|
||||
if (critical_section())
|
||||
log_error(INTERNAL_ERROR
|
||||
"Writing metadata in critical section.");
|
||||
@ -3538,52 +3607,6 @@ static int _repair_inconsistent_vg(struct volume_group *vg, uint32_t lockd_state
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _wipe_outdated_pvs(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *to_check, uint32_t lockd_state)
|
||||
{
|
||||
struct pv_list *pvl, *pvl2;
|
||||
char uuid[64] __attribute__((aligned(8)));
|
||||
|
||||
if (lvmcache_found_duplicate_pvs()) {
|
||||
log_debug_metadata("Skip wiping outdated PVs with duplicates.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cannot write foreign VGs, the owner will repair it.
|
||||
* Also, if another host is updating its VG, we may read
|
||||
* the PVs while some are written but not others, making
|
||||
* some PVs look outdated to us just because we're reading
|
||||
* the VG while it's only partially written out.
|
||||
*/
|
||||
if (_is_foreign_vg(vg)) {
|
||||
log_debug_metadata("Skip wiping outdated PVs for foreign VG.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vg_is_shared(vg) && !(lockd_state & LDST_EX)) {
|
||||
log_verbose("Skip wiping outdated PVs for shared VG without exclusive lock.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(pvl, to_check) {
|
||||
dm_list_iterate_items(pvl2, &vg->pvs) {
|
||||
if (pvl->pv->dev == pvl2->pv->dev)
|
||||
goto next_pv;
|
||||
}
|
||||
|
||||
|
||||
if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid)))
|
||||
return_0;
|
||||
log_warn("WARNING: Removing PV %s (%s) that no longer belongs to VG %s",
|
||||
pv_dev_name(pvl->pv), uuid, vg->name);
|
||||
if (!pv_write_orphan(cmd, pvl->pv))
|
||||
return_0;
|
||||
next_pv:
|
||||
;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _check_or_repair_pv_ext(struct cmd_context *cmd,
|
||||
struct volume_group *vg,
|
||||
uint32_t lockd_state,
|
||||
@ -4217,12 +4240,6 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
release_vg(correct_vg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_wipe_outdated_pvs(cmd, correct_vg, &all_pvs, lockd_state)) {
|
||||
_free_pv_list(&all_pvs);
|
||||
release_vg(correct_vg);
|
||||
return_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
_free_pv_list(&all_pvs);
|
||||
|
@ -99,6 +99,8 @@ int vgremove(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
clear_hint_file(cmd);
|
||||
|
||||
cmd->wipe_outdated_pvs = 1;
|
||||
|
||||
cmd->handles_missing_pvs = 1;
|
||||
ret = process_each_vg(cmd, argc, argv, NULL, NULL,
|
||||
READ_FOR_UPDATE, 0,
|
||||
|
Loading…
Reference in New Issue
Block a user