diff options
Diffstat (limited to 'tools/lvchange.c')
-rw-r--r-- | tools/lvchange.c | 115 |
1 files changed, 86 insertions, 29 deletions
diff --git a/tools/lvchange.c b/tools/lvchange.c index cbdb3535..6972aac2 100644 --- a/tools/lvchange.c +++ b/tools/lvchange.c @@ -256,13 +256,57 @@ static int lvchange_refresh(struct cmd_context *cmd, struct logical_volume *lv) return lv_refresh(cmd, lv); } +static int detach_metadata_devices(struct lv_segment *seg, struct dm_list *list) +{ + struct cmd_context *cmd = seg->lv->vg->cmd; + struct lv_list *lvl; + + if (seg_is_raid(seg)) { + return 0; + } + + if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) + return_0; + + lvl->lv = detach_mirror_log(seg); + dm_list_add(list, &lvl->list); + + return 1; +} + +static int attach_metadata_devices(struct lv_segment *seg, struct dm_list *list) +{ + struct cmd_context *cmd = seg->lv->vg->cmd; + struct lv_list *lvl; + + if (seg_is_raid(seg)) { + return 0; + } + + dm_list_iterate_items(lvl, list) + break; /* get first item */ + + if (!attach_mirror_log(seg, lvl->lv)) { + dm_pool_free(cmd->mem, lvl); + return_0; + } + + dm_pool_free(cmd->mem, lvl); + + return 1; +} + static int lvchange_resync(struct cmd_context *cmd, struct logical_volume *lv) { int active = 0; int monitored; struct lvinfo info; - struct logical_volume *log_lv; + struct lv_segment *seg = first_seg(lv); + struct dm_list device_list; + struct lv_list *lvl; + + dm_list_init(&device_list); if (!(lv->status & MIRRORED)) { log_error("Unable to resync %s because it is not mirrored.", @@ -321,21 +365,19 @@ static int lvchange_resync(struct cmd_context *cmd, init_dmeventd_monitor(monitored); - log_lv = first_seg(lv)->log_lv; - log_very_verbose("Starting resync of %s%s%s mirror \"%s\"", (active) ? "active " : "", vg_is_clustered(lv->vg) ? "clustered " : "", - (log_lv) ? "disk-logged" : "core-logged", + (seg->log_lv) ? "disk-logged" : "core-logged", lv->name); /* - * If this mirror has a core log (i.e. !log_lv), + * If this mirror has a core log (i.e. !seg->log_lv), * then simply deactivating/activating will cause * it to reset the sync status. We only need to * worry about persistent logs. */ - if (!log_lv) { + if (!seg->log_lv) { if (!(lv->status & LV_NOTSYNCED)) { lv->status &= ~LV_NOTSYNCED; log_very_verbose("Updating logical volume \"%s\"" @@ -360,12 +402,17 @@ static int lvchange_resync(struct cmd_context *cmd, */ lv->status &= ~LV_NOTSYNCED; - /* Separate mirror log so we can clear it */ - detach_mirror_log(first_seg(lv)); + /* Separate mirror log or metadata devices so we can clear them */ + if (!detach_metadata_devices(seg, &device_list)) { + log_error("Failed to clear %s %s for %s", + seg->segtype->name, seg_is_raid(seg) ? + "metadata area" : "mirror log", lv->name); + return 0; + } if (!vg_write(lv->vg)) { log_error("Failed to write intermediate VG metadata."); - if (!attach_mirror_log(first_seg(lv), log_lv)) + if (!attach_metadata_devices(seg, &device_list)) stack; if (active && !activate_lv(cmd, lv)) stack; @@ -374,7 +421,7 @@ static int lvchange_resync(struct cmd_context *cmd, if (!vg_commit(lv->vg)) { log_error("Failed to commit intermediate VG metadata."); - if (!attach_mirror_log(first_seg(lv), log_lv)) + if (!attach_metadata_devices(seg, &device_list)) stack; if (active && !activate_lv(cmd, lv)) stack; @@ -383,31 +430,41 @@ static int lvchange_resync(struct cmd_context *cmd, backup(lv->vg); - if (!activate_lv(cmd, log_lv)) { - log_error("Unable to activate %s for mirror log resync", - log_lv->name); - return 0; - } + dm_list_iterate_items(lvl, &device_list) { + if (!activate_lv(cmd, lvl->lv)) { + log_error("Unable to activate %s for mirror log resync", + lvl->lv->name); + return 0; + } - log_very_verbose("Clearing log device %s", log_lv->name); - if (!set_lv(cmd, log_lv, log_lv->size, 0)) { - log_error("Unable to reset sync status for %s", lv->name); - if (!deactivate_lv(cmd, log_lv)) - log_error("Failed to deactivate log LV after " - "wiping failed"); - return 0; + log_very_verbose("Clearing %s device %s", + (seg_is_raid(seg)) ? "metadata" : "log", + lvl->lv->name); + if (!set_lv(cmd, lvl->lv, lvl->lv->size, 0)) { + log_error("Unable to reset sync status for %s", + lv->name); + if (!deactivate_lv(cmd, lvl->lv)) + log_error("Failed to deactivate log LV after " + "wiping failed"); + return 0; + } + + if (!deactivate_lv(cmd, lvl->lv)) { + log_error("Unable to deactivate %s LV %s " + "after wiping for resync", + (seg_is_raid(seg)) ? "metadata" : "log", + lvl->lv->name); + return 0; + } } - if (!deactivate_lv(cmd, log_lv)) { - log_error("Unable to deactivate log LV %s after wiping " - "for resync", log_lv->name); + /* Put metadata sub-LVs back in place */ + if (!attach_metadata_devices(seg, &device_list)) { + log_error("Failed to reattach %s device after clearing", + (seg_is_raid(seg)) ? "metadata" : "log"); return 0; } - /* Put mirror log back in place */ - if (!attach_mirror_log(first_seg(lv), log_lv)) - stack; - log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name); if (!vg_write(lv->vg) || !vg_commit(lv->vg)) { log_error("Failed to update metadata on disk."); |