1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

lvmlockd: enable repairing shared VG while reading it

When the lvmlockd lock is shared, upgrade it to ex
when repair (writing) is needed during vg_read.

Pass the lockd state through additional read-related
functions so the instances of repair scattered through
vg_read can be handled.

(Temporary solution until the ad hoc repairs can be
pulled out of vg_read into a top level, centralized
repair function.)
This commit is contained in:
David Teigland 2018-05-30 12:48:18 -05:00
parent 063d065388
commit 6cd0523337
4 changed files with 45 additions and 36 deletions

View File

@ -832,7 +832,7 @@ void lvm_do_backup(const char *vgname)
pthread_mutex_lock(&lvm_lock);
vg = vg_read_internal(cmd, vgname, NULL /*vgid*/, WARN_PV_READ, &consistent);
vg = vg_read_internal(cmd, vgname, NULL /*vgid*/, 0, WARN_PV_READ, &consistent);
if (vg && consistent)
check_current_backup(vg);

View File

@ -652,7 +652,7 @@ int vg_write(struct volume_group *vg);
int vg_commit(struct volume_group *vg);
void vg_revert(struct volume_group *vg);
struct volume_group *vg_read_internal(struct cmd_context *cmd, const char *vg_name,
const char *vgid, uint32_t warn_flags, int *consistent);
const char *vgid, uint32_t lockd_state, uint32_t warn_flags, int *consistent);
#define get_pvs( cmd ) get_pvs_internal((cmd), NULL, NULL)
#define get_pvs_perserve_vg( cmd, pv_list, vg_list ) get_pvs_internal((cmd), (pv_list), (vg_list))

View File

@ -3541,7 +3541,7 @@ static int _is_foreign_vg(struct volume_group *vg)
return vg->cmd->system_id && strcmp(vg->system_id, vg->cmd->system_id);
}
static int _repair_inconsistent_vg(struct volume_group *vg)
static int _repair_inconsistent_vg(struct volume_group *vg, uint32_t lockd_state)
{
unsigned saved_handles_missing_pvs = vg->cmd->handles_missing_pvs;
@ -3556,9 +3556,8 @@ static int _repair_inconsistent_vg(struct volume_group *vg)
return 0;
}
/* FIXME: do this at higher level where lvmlockd lock can be changed. */
if (is_lockd_type(vg->lock_type)) {
log_verbose("Skip metadata repair for shared VG.");
if (is_lockd_type(vg->lock_type) && !(lockd_state & LDST_EX)) {
log_verbose("Skip metadata repair for shared VG without exclusive lock.");
return 0;
}
@ -3581,7 +3580,7 @@ static int _repair_inconsistent_vg(struct volume_group *vg)
return 1;
}
static int _wipe_outdated_pvs(struct cmd_context *cmd, struct volume_group *vg, struct dm_list *to_check)
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)));
@ -3603,14 +3602,8 @@ static int _wipe_outdated_pvs(struct cmd_context *cmd, struct volume_group *vg,
return 0;
}
/*
* FIXME: do this at higher level where lvmlockd lock can be changed.
* Also if we're reading the VG with the --shared option (not using
* lvmlockd), we can see a VG while it's being written by another
* host, same as the foreign VG case.
*/
if (is_lockd_type(vg->lock_type)) {
log_debug_metadata("Skip wiping outdated PVs for shared VG.");
if (is_lockd_type(vg->lock_type) && !(lockd_state & LDST_EX)) {
log_verbose("Skip wiping outdated PVs for shared VG without exclusive lock.");
return 0;
}
@ -3619,6 +3612,8 @@ static int _wipe_outdated_pvs(struct cmd_context *cmd, struct volume_group *vg,
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",
@ -3639,6 +3634,7 @@ next_pv:
static int _check_or_repair_pv_ext(struct cmd_context *cmd,
struct volume_group *vg,
uint32_t lockd_state,
int repair, int *inconsistent_pvs)
{
char uuid[64] __attribute__((aligned(8)));
@ -3688,10 +3684,7 @@ static int _check_or_repair_pv_ext(struct cmd_context *cmd,
"VG %s but not marked as used.",
pv_dev_name(pvl->pv), vg->name);
*inconsistent_pvs = 1;
} else if (is_lockd_type(vg->lock_type)) {
/*
* FIXME: decide how to handle repair for shared VGs.
*/
} else if (is_lockd_type(vg->lock_type) && !(lockd_state & LDST_EX)) {
log_warn("Skip repair of PV %s that is in shared "
"VG %s but not marked as used.",
pv_dev_name(pvl->pv), vg->name);
@ -3715,7 +3708,7 @@ static int _check_or_repair_pv_ext(struct cmd_context *cmd,
r = 1;
out:
if ((pvs_fixed > 0) && !_repair_inconsistent_vg(vg))
if ((pvs_fixed > 0) && !_repair_inconsistent_vg(vg, lockd_state))
return_0;
return r;
@ -3738,6 +3731,7 @@ out:
static struct volume_group *_vg_read(struct cmd_context *cmd,
const char *vgname,
const char *vgid,
uint32_t lockd_state,
uint32_t warn_flags,
int *consistent, unsigned precommitted)
{
@ -3787,10 +3781,10 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
dm_list_iterate_items(pvl, &correct_vg->pvs)
reappeared += _check_reappeared_pv(correct_vg, pvl->pv, *consistent);
if (reappeared && *consistent)
*consistent = _repair_inconsistent_vg(correct_vg);
*consistent = _repair_inconsistent_vg(correct_vg, lockd_state);
else
*consistent = !reappeared;
if (_wipe_outdated_pvs(cmd, correct_vg, &correct_vg->pvs_outdated)) {
if (_wipe_outdated_pvs(cmd, correct_vg, &correct_vg->pvs_outdated, lockd_state)) {
/* clear the list */
dm_list_init(&correct_vg->pvs_outdated);
lvmetad_vg_clear_outdated_pvs(correct_vg);
@ -4310,13 +4304,13 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
dm_list_iterate_items(pvl, &all_pvs)
_check_reappeared_pv(correct_vg, pvl->pv, 1);
if (!_repair_inconsistent_vg(correct_vg)) {
if (!_repair_inconsistent_vg(correct_vg, lockd_state)) {
_free_pv_list(&all_pvs);
release_vg(correct_vg);
return NULL;
}
if (!_wipe_outdated_pvs(cmd, correct_vg, &all_pvs)) {
if (!_wipe_outdated_pvs(cmd, correct_vg, &all_pvs, lockd_state)) {
_free_pv_list(&all_pvs);
release_vg(correct_vg);
return_NULL;
@ -4340,7 +4334,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
}
/* We have the VG now finally, check if PV ext info is in sync with VG metadata. */
if (!cmd->is_clvmd && !_check_or_repair_pv_ext(cmd, correct_vg,
if (!cmd->is_clvmd && !_check_or_repair_pv_ext(cmd, correct_vg, lockd_state,
skipped_rescan ? 0 : *consistent,
&inconsistent_pvs)) {
release_vg(correct_vg);
@ -4502,13 +4496,15 @@ static int _check_devs_used_correspond_with_vg(struct volume_group *vg)
return 1;
}
struct volume_group *vg_read_internal(struct cmd_context *cmd, const char *vgname,
const char *vgid, uint32_t warn_flags, int *consistent)
struct volume_group *vg_read_internal(struct cmd_context *cmd,
const char *vgname, const char *vgid,
uint32_t lockd_state, uint32_t warn_flags,
int *consistent)
{
struct volume_group *vg;
struct lv_list *lvl;
if (!(vg = _vg_read(cmd, vgname, vgid, warn_flags, consistent, 0)))
if (!(vg = _vg_read(cmd, vgname, vgid, lockd_state, warn_flags, consistent, 0)))
goto_out;
if (!check_pv_dev_sizes(vg))
@ -4616,7 +4612,7 @@ struct volume_group *vg_read_by_vgid(struct cmd_context *cmd,
label_scan_setup_bcache();
if (!(vg = _vg_read(cmd, vgname, vgid, warn_flags, &consistent, precommitted))) {
if (!(vg = _vg_read(cmd, vgname, vgid, 0, warn_flags, &consistent, precommitted))) {
log_error("Rescan devices to look for missing VG.");
goto scan;
}
@ -4637,7 +4633,7 @@ struct volume_group *vg_read_by_vgid(struct cmd_context *cmd,
lvmcache_label_scan(cmd);
warn_flags |= SKIP_RESCAN;
if (!(vg = _vg_read(cmd, vgname, vgid, warn_flags, &consistent, precommitted)))
if (!(vg = _vg_read(cmd, vgname, vgid, 0, warn_flags, &consistent, precommitted)))
goto fail;
label_scan_destroy(cmd); /* drop bcache to close devs, keep lvmcache */
@ -4876,7 +4872,7 @@ static int _get_pvs(struct cmd_context *cmd, uint32_t warn_flags,
warn_flags |= WARN_INCONSISTENT;
if (!(vg = vg_read_internal(cmd, vgname, (!vgslist) ? vgid : NULL, warn_flags, &consistent))) {
if (!(vg = vg_read_internal(cmd, vgname, (!vgslist) ? vgid : NULL, 0, warn_flags, &consistent))) {
stack;
continue;
}
@ -5189,17 +5185,30 @@ int vg_check_status(const struct volume_group *vg, uint64_t status)
* VG is left unlocked on failure
*/
static struct volume_group *_recover_vg(struct cmd_context *cmd,
const char *vg_name, const char *vgid)
const char *vg_name, const char *vgid, uint32_t lockd_state)
{
int consistent = 1;
struct volume_group *vg;
uint32_t state = 0;
unlock_vg(cmd, NULL, vg_name);
if (!lock_vol(cmd, vg_name, LCK_VG_WRITE, NULL))
return_NULL;
if (!(vg = vg_read_internal(cmd, vg_name, vgid, WARN_PV_READ, &consistent))) {
/*
* Convert vg lock in lvmlockd from sh to ex.
*/
if (!(lockd_state & LDST_FAIL) && !(lockd_state & LDST_EX)) {
log_debug("Upgrade lvmlockd lock to repair vg %s.", vg_name);
if (!lockd_vg(cmd, vg_name, "ex", 0, &state)) {
log_warn("Skip repair for shared VG without exclusive lock.");
return NULL;
}
lockd_state |= LDST_EX;
}
if (!(vg = vg_read_internal(cmd, vg_name, vgid, lockd_state, WARN_PV_READ, &consistent))) {
unlock_vg(cmd, NULL, vg_name);
return_NULL;
}
@ -5473,7 +5482,7 @@ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const cha
warn_flags |= WARN_INCONSISTENT;
/* If consistent == 1, we get NULL here if correction fails. */
if (!(vg = vg_read_internal(cmd, vg_name, vgid, warn_flags, &consistent))) {
if (!(vg = vg_read_internal(cmd, vg_name, vgid, lockd_state, warn_flags, &consistent))) {
if (consistent_in && !consistent) {
failure |= FAILED_INCONSISTENT;
goto bad;
@ -5490,7 +5499,7 @@ static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const cha
/* consistent == 0 when VG is not found, but failed == FAILED_NOTFOUND */
if (!consistent && !failure) {
release_vg(vg);
if (!(vg = _recover_vg(cmd, vg_name, vgid))) {
if (!(vg = _recover_vg(cmd, vg_name, vgid, lockd_state))) {
if (is_orphan_vg(vg_name))
log_error("Recovery of standalone physical volumes failed.");
else

View File

@ -5730,7 +5730,7 @@ do_command:
if (pp->preserve_existing && pp->orphan_vg_name) {
log_debug("Using existing orphan PVs in %s.", pp->orphan_vg_name);
if (!(orphan_vg = vg_read_internal(cmd, pp->orphan_vg_name, NULL, 0, &consistent))) {
if (!(orphan_vg = vg_read_internal(cmd, pp->orphan_vg_name, NULL, 0, 0, &consistent))) {
log_error("Cannot read orphans VG %s.", pp->orphan_vg_name);
goto bad;
}