summaryrefslogtreecommitdiffstats
path: root/tools/lvchange.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/lvchange.c')
-rw-r--r--tools/lvchange.c115
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.");