summaryrefslogtreecommitdiffstats
path: root/lib/metadata/mirror.c
diff options
context:
space:
mode:
authorJonathan Earl Brassow <jbrassow@redhat.com>2011-10-06 14:55:39 +0000
committerJonathan Earl Brassow <jbrassow@redhat.com>2011-10-06 14:55:39 +0000
commitb19f01212e3bf47b6d41568b0b3567106c87f99b (patch)
treebb2af2283dbc6b235237c02ad55476759c587d96 /lib/metadata/mirror.c
parent6c0b0e5d9a79349fb3acd03780c184f72da62e55 (diff)
downloadlvm2-b19f01212e3bf47b6d41568b0b3567106c87f99b.tar.gz
lvm2-b19f01212e3bf47b6d41568b0b3567106c87f99b.tar.xz
lvm2-b19f01212e3bf47b6d41568b0b3567106c87f99b.zip
Fix splitmirror in cluster having different DM/LVM views of storage.
This patch also does some clean-up of the splitmirrors code. I've attempted to clean-up the splitmirrors code to make it easier to understand with fewer operations. I've tried to reduce the number of metadata operations without compromising the intermediate stages which are necessary for easy clean-up in the even of failure. These changes now correctly handle cluster situations - including exclusive cluster mirrors. Whereas before, a splitmirror operation would result in remote nodes having LVM commands report the newly split LV with a proper name while DM commands would report the old (pre-split) names of the device. IOW, there was a kernel/userspace mismatch.
Diffstat (limited to 'lib/metadata/mirror.c')
-rw-r--r--lib/metadata/mirror.c205
1 files changed, 102 insertions, 103 deletions
diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c
index 6fffd7b0..877bb660 100644
--- a/lib/metadata/mirror.c
+++ b/lib/metadata/mirror.c
@@ -395,6 +395,22 @@ activate_lv:
}
/*
+ * Activate an LV similarly (i.e. SH or EX) to a given "model" LV
+ */
+static int _activate_lv_like_model(struct logical_volume *model,
+ struct logical_volume *lv)
+{
+ if (lv_is_active_exclusive(model)) {
+ if (!activate_lv_excl(lv->vg->cmd, lv))
+ return_0;
+ } else {
+ if (!activate_lv(lv->vg->cmd, lv))
+ return_0;
+ }
+ return 1;
+}
+
+/*
* Delete independent/orphan LV, it must acquire lock.
*/
static int _delete_lv(struct logical_volume *mirror_lv, struct logical_volume *lv)
@@ -417,13 +433,9 @@ static int _delete_lv(struct logical_volume *mirror_lv, struct logical_volume *l
}
}
- if (lv_is_active_exclusive_locally(lv)) {
- if (!activate_lv_excl(cmd, lv))
- return_0;
- } else {
- if (!activate_lv(cmd, lv))
- return_0;
- }
+ // FIXME: shouldn't the activation type be based on mirror_lv, not lv?
+ if (!_activate_lv_like_model(lv, lv))
+ return_0;
sync_local_dev_names(lv->vg->cmd);
if (!deactivate_lv(cmd, lv))
@@ -560,8 +572,14 @@ static int _mirrored_lv_in_sync(struct logical_volume *lv)
if (!lv_mirror_percent(lv->vg->cmd, lv, 0, &sync_percent,
NULL)) {
- log_error("Unable to determine mirror sync status of %s/%s.",
- lv->vg->name, lv->name);
+ if (lv_is_active_but_not_locally(lv))
+ log_error("Unable to determine mirror sync status of"
+ " remotely active LV, %s/%s",
+ lv->vg->name, lv->name);
+ else
+ log_error("Unable to determine mirror "
+ "sync status of %s/%s.",
+ lv->vg->name, lv->name);
return 0;
}
@@ -584,7 +602,7 @@ static int _split_mirror_images(struct logical_volume *lv,
struct logical_volume *detached_log_lv = NULL;
struct lv_segment *mirrored_seg = first_seg(lv);
struct dm_list split_images;
- struct lv_list *lvl, *new_lvl = NULL;
+ struct lv_list *lvl;
struct cmd_context *cmd = lv->vg->cmd;
if (!(lv->status & MIRRORED)) {
@@ -626,12 +644,18 @@ static int _split_mirror_images(struct logical_volume *lv,
sub_lv = seg_lv(mirrored_seg, mirrored_seg->area_count);
sub_lv->status &= ~MIRROR_IMAGE;
- lv_set_visible(sub_lv);
release_lv_segment_area(mirrored_seg, mirrored_seg->area_count,
mirrored_seg->area_len);
log_very_verbose("%s assigned to be split", sub_lv->name);
+ if (!new_lv) {
+ lv_set_visible(sub_lv);
+ new_lv = sub_lv;
+ continue;
+ }
+
+ /* If there is more than one image being split, add to list */
lvl = dm_pool_alloc(lv->vg->vgmem, sizeof(*lvl));
if (!lvl) {
log_error("lv_list alloc failed");
@@ -640,90 +664,7 @@ static int _split_mirror_images(struct logical_volume *lv,
lvl->lv = sub_lv;
dm_list_add(&split_images, &lvl->list);
}
- sub_lv = NULL;
-
- /*
- * If no more mirrors, remove mirror layer.
- * The sub_lv is removed entirely later - leaving
- * only the top-level (now linear) LV.
- */
- if (mirrored_seg->area_count == 1) {
- sub_lv = seg_lv(mirrored_seg, 0);
- sub_lv->status &= ~MIRROR_IMAGE;
- lv_set_visible(sub_lv);
- detached_log_lv = detach_mirror_log(mirrored_seg);
- if (!remove_layer_from_lv(lv, sub_lv))
- return_0;
- lv->status &= ~MIRRORED;
- lv->status &= ~LV_NOTSYNCED;
- }
-
- if (!vg_write(mirrored_seg->lv->vg)) {
- log_error("Intermediate VG metadata write failed.");
- return 0;
- }
-
- /*
- * Suspend the mirror - this includes all the sub-LVs and
- * soon-to-be-split sub-LVs
- */
- if (!suspend_lv(cmd, mirrored_seg->lv)) {
- log_error("Failed to lock %s", mirrored_seg->lv->name);
- vg_revert(mirrored_seg->lv->vg);
- return 0;
- }
-
- if (!vg_commit(mirrored_seg->lv->vg)) {
- resume_lv(cmd, mirrored_seg->lv);
- return 0;
- }
-
- log_very_verbose("Updating \"%s\" in kernel", mirrored_seg->lv->name);
-
- /*
- * Resume the mirror - this also activates the visible, independent
- * soon-to-be-split sub-LVs
- */
- if (!resume_lv(cmd, mirrored_seg->lv)) {
- log_error("Problem resuming %s", mirrored_seg->lv->name);
- return 0;
- }
-
- /* Remove original mirror layer if it has been converted to linear */
- if (sub_lv && !_delete_lv(lv, sub_lv))
- return_0;
-
- /* Remove the log if it has been converted to linear */
- if (detached_log_lv && !_delete_lv(lv, detached_log_lv))
- return_0;
-
- /*
- * Step 2:
- * The original mirror has been changed and we now have visible,
- * independent, not-yet-renamed, active sub-LVs. We must:
- * - deactivate the split sub-LVs
- * - rename them
- * - form new mirror if necessary
- * - commit VG changes
- * - activate the new LV
- */
- sync_local_dev_names(lv->vg->cmd);
- dm_list_iterate_items(lvl, &split_images) {
- if (!new_lv) {
- /* Grab 1st sub-LV for later */
- new_lvl = lvl;
- new_lv = lvl->lv;
- }
-
- sub_lv = lvl->lv;
- if (!deactivate_lv(cmd, sub_lv)) {
- log_error("Failed to deactivate former mirror image, %s",
- sub_lv->name);
- return 0;
- }
- }
- dm_list_del(&new_lvl->list);
new_lv->name = dm_pool_strdup(lv->vg->vgmem, split_name);
if (!new_lv->name) {
log_error("Unable to rename newly split LV");
@@ -780,19 +721,77 @@ static int _split_mirror_images(struct logical_volume *lv,
init_mirror_in_sync(1);
}
- if (!vg_write(mirrored_seg->lv->vg) ||
- !vg_commit(mirrored_seg->lv->vg))
- return_0;
+ sub_lv = NULL;
+
+ /*
+ * If no more mirrors, remove mirror layer.
+ * The sub_lv is removed entirely later - leaving
+ * only the top-level (now linear) LV.
+ */
+ if (mirrored_seg->area_count == 1) {
+ sub_lv = seg_lv(mirrored_seg, 0);
+ sub_lv->status &= ~MIRROR_IMAGE;
+ lv_set_visible(sub_lv);
+ detached_log_lv = detach_mirror_log(mirrored_seg);
+ if (!remove_layer_from_lv(lv, sub_lv))
+ return_0;
+ lv->status &= ~MIRRORED;
+ lv->status &= ~LV_NOTSYNCED;
+ }
+
+ if (!vg_write(mirrored_seg->lv->vg)) {
+ log_error("Intermediate VG metadata write failed.");
+ return 0;
+ }
- /* Bring newly split-off LV into existence */
- if (!activate_lv(cmd, new_lv)) {
- log_error("Failed to activate newly split LV, %s",
- new_lv->name);
+ /*
+ * Suspend the mirror - this includes all the sub-LVs and
+ * soon-to-be-split sub-LVs
+ */
+ if (!suspend_lv(cmd, mirrored_seg->lv)) {
+ log_error("Failed to lock %s", mirrored_seg->lv->name);
+ vg_revert(mirrored_seg->lv->vg);
return 0;
}
- log_very_verbose("%" PRIu32 " image(s) detached from %s",
- split_count, lv->name);
+ if (!vg_commit(mirrored_seg->lv->vg)) {
+ resume_lv(cmd, mirrored_seg->lv);
+ return 0;
+ }
+
+ log_very_verbose("Updating \"%s\" in kernel", mirrored_seg->lv->name);
+
+ /*
+ * Resume the mirror - this also activates the visible, independent
+ * soon-to-be-split sub-LVs
+ */
+ if (!resume_lv(cmd, mirrored_seg->lv)) {
+ log_error("Problem resuming %s", mirrored_seg->lv->name);
+ return 0;
+ }
+
+ /*
+ * Recycle newly split LV so it is properly renamed.
+ * Cluster requires the extra deactivate/activate calls.
+ */
+ if (vg_is_clustered(lv->vg) &&
+ (!deactivate_lv(cmd, new_lv) ||
+ !_activate_lv_like_model(lv, new_lv))) {
+ log_error("Failed to rename newly split LV in the kernel");
+ return 0;
+ }
+ if (!suspend_lv(cmd, new_lv) || !resume_lv(cmd, new_lv)) {
+ log_error("Failed to rename newly split LV in the kernel");
+ return 0;
+ }
+
+ /* Remove original mirror layer if it has been converted to linear */
+ if (sub_lv && !_delete_lv(lv, sub_lv))
+ return_0;
+
+ /* Remove the log if it has been converted to linear */
+ if (detached_log_lv && !_delete_lv(lv, detached_log_lv))
+ return_0;
return 1;
}