mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-02 01:18:26 +03:00
Remove empty "repaired" devices if empty in lvconvert.
The logic was that lvconvert repair volumes, marking PV as MISSING and following vgreduce --removemissing removes these missing devices. Previously dmeventd mirror DSO removed all LV and PV from VG by simply relying on vgreduce --removemissing --force. Now, there are two subsequent calls: lvconvert --repair --use-policies vgreduce --removemissing So the VG is locked twice, opening space for all races between other running lvm processes. If the PV reappears with old metadata on it (so the winner performs autorepair, if locking VG for update) the situation is even worse. Patch simply adds removemissing PV functionality into lvconcert BUT ONLY if running with --repair and --use-policies and removing only these empty missing PVs which are involved in repair. (This combination is expected to run only from dmeventd.)
This commit is contained in:
parent
5d196aa430
commit
bf8c8a6d61
@ -1,5 +1,6 @@
|
|||||||
Version 2.02.57 -
|
Version 2.02.57 -
|
||||||
====================================
|
====================================
|
||||||
|
Remove empty PV devices if lvconvert --repair is using defined policies.
|
||||||
Use fixed buffer to prevent stack overflow in persistent filter dump.
|
Use fixed buffer to prevent stack overflow in persistent filter dump.
|
||||||
Use snapshot metadata usage to determine if a snapshot is empty.
|
Use snapshot metadata usage to determine if a snapshot is empty.
|
||||||
Insert missing stack macros to all activate_lv and deactivate_lv callers.
|
Insert missing stack macros to all activate_lv and deactivate_lv callers.
|
||||||
|
@ -193,11 +193,7 @@ static int _remove_failed_devices(const char *device)
|
|||||||
|
|
||||||
r = lvm2_run(_lvm_handle, cmd_str);
|
r = lvm2_run(_lvm_handle, cmd_str);
|
||||||
|
|
||||||
if (r == ECMD_PROCESSED) {
|
syslog(LOG_INFO, "Repair of mirrored LV %s/%s %s.", vg, lv, (r == ECMD_PROCESSED) ? "finished successfully" : "failed");
|
||||||
snprintf(cmd_str, CMD_SIZE, "vgreduce --removemissing %s", vg);
|
|
||||||
if (lvm2_run(_lvm_handle, cmd_str) != 1)
|
|
||||||
syslog(LOG_ERR, "Unable to remove failed PVs from VG %s", vg);
|
|
||||||
}
|
|
||||||
|
|
||||||
dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */
|
dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */
|
||||||
return (r == ECMD_PROCESSED) ? 0 : -1;
|
return (r == ECMD_PROCESSED) ? 0 : -1;
|
||||||
|
@ -428,6 +428,16 @@ static struct dm_list *_failed_pv_list(struct volume_group *vg)
|
|||||||
if (!(pvl->pv->status & MISSING_PV))
|
if (!(pvl->pv->status & MISSING_PV))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finally, --repair will remove empty PVs.
|
||||||
|
* But we only want remove these which are output of repair,
|
||||||
|
* Do not count these which are already empty here.
|
||||||
|
* FIXME: code should traverse PV in LV not in whole VG.
|
||||||
|
* FIXME: layer violation? should it depend on vgreduce --removemising?
|
||||||
|
*/
|
||||||
|
if (pvl->pv->pe_alloc_count == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!(new_pvl = dm_pool_alloc(vg->vgmem, sizeof(*new_pvl)))) {
|
if (!(new_pvl = dm_pool_alloc(vg->vgmem, sizeof(*new_pvl)))) {
|
||||||
log_error("Allocation of failed_pvs list entry failed.");
|
log_error("Allocation of failed_pvs list entry failed.");
|
||||||
return_NULL;
|
return_NULL;
|
||||||
@ -522,6 +532,44 @@ static int _lv_update_log_type(struct cmd_context *cmd,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reomove missing and empty PVs from VG, if are also in provided list
|
||||||
|
*/
|
||||||
|
static void _remove_missing_empty_pv(struct volume_group *vg, struct dm_list *remove_pvs)
|
||||||
|
{
|
||||||
|
struct pv_list *pvl, *pvl_vg, *pvlt;
|
||||||
|
int removed = 0;
|
||||||
|
|
||||||
|
if (!remove_pvs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dm_list_iterate_items(pvl, remove_pvs) {
|
||||||
|
dm_list_iterate_items_safe(pvl_vg, pvlt, &vg->pvs) {
|
||||||
|
if (!id_equal(&pvl->pv->id, &pvl_vg->pv->id) ||
|
||||||
|
!(pvl_vg->pv->status & MISSING_PV) ||
|
||||||
|
pvl_vg->pv->pe_alloc_count != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* FIXME: duplication of vgreduce code, move this to library */
|
||||||
|
vg->free_count -= pvl_vg->pv->pe_count;
|
||||||
|
vg->extent_count -= pvl_vg->pv->pe_count;
|
||||||
|
vg->pv_count--;
|
||||||
|
dm_list_del(&pvl_vg->list);
|
||||||
|
|
||||||
|
removed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removed) {
|
||||||
|
if (!vg_write(vg) || !vg_commit(vg)) {
|
||||||
|
stack;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warn("%d missing and now unallocated Physical Volumes removed from VG.", removed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
|
static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv,
|
||||||
struct lvconvert_params *lp)
|
struct lvconvert_params *lp)
|
||||||
{
|
{
|
||||||
@ -532,7 +580,7 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv
|
|||||||
int r = 0;
|
int r = 0;
|
||||||
struct logical_volume *log_lv, *layer_lv;
|
struct logical_volume *log_lv, *layer_lv;
|
||||||
int failed_mirrors = 0, failed_log = 0;
|
int failed_mirrors = 0, failed_log = 0;
|
||||||
struct dm_list *old_pvh = NULL, *remove_pvs = NULL;
|
struct dm_list *old_pvh = NULL, *remove_pvs = NULL, *failed_pvs = NULL;
|
||||||
|
|
||||||
int repair = arg_count(cmd, repair_ARG);
|
int repair = arg_count(cmd, repair_ARG);
|
||||||
int replace_log = 1, replace_mirrors = 1;
|
int replace_log = 1, replace_mirrors = 1;
|
||||||
@ -593,6 +641,7 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv
|
|||||||
old_pvh = lp->pvh;
|
old_pvh = lp->pvh;
|
||||||
if (!(lp->pvh = _failed_pv_list(lv->vg)))
|
if (!(lp->pvh = _failed_pv_list(lv->vg)))
|
||||||
return_0;
|
return_0;
|
||||||
|
failed_pvs = lp->pvh;
|
||||||
log_lv=first_seg(lv)->log_lv;
|
log_lv=first_seg(lv)->log_lv;
|
||||||
if (!log_lv || log_lv->status & PARTIAL_LV)
|
if (!log_lv || log_lv->status & PARTIAL_LV)
|
||||||
failed_log = corelog = 1;
|
failed_log = corelog = 1;
|
||||||
@ -821,6 +870,10 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, struct logical_volume *lv
|
|||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If repairing and using policies, remove missing PVs from VG */
|
||||||
|
if (repair && arg_count(cmd, use_policies_ARG))
|
||||||
|
_remove_missing_empty_pv(lv->vg, failed_pvs);
|
||||||
|
|
||||||
if (!lp->need_polling)
|
if (!lp->need_polling)
|
||||||
log_print("Logical volume %s converted.", lv->name);
|
log_print("Logical volume %s converted.", lv->name);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user