Swap lvids of the underlying devices "-cow" and "-real". This is tricky. Motivation: the underlying devices must have the same dlids as they had before the merging started --- so that they will be allocated the same minor number and the kernel will do exception handover. If the dlids were different, lvm would allocate new DM nodes for "-cow" and "-real", they get new minor numbers, the kernel won't notice that they correspond to the old devices and won't hand over the exceptions table --- the result would be silent data corruption. Signed-off-by: Mikulas Patocka --- lib/activate/dev_manager.c | 68 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 11 deletions(-) Index: LVM2.2.02.45/lib/activate/dev_manager.c =================================================================== --- LVM2.2.02.45.orig/lib/activate/dev_manager.c 2009-05-11 13:09:03.000000000 +0200 +++ LVM2.2.02.45/lib/activate/dev_manager.c 2009-05-11 13:09:09.000000000 +0200 @@ -836,19 +836,24 @@ int add_areas_line(struct dev_manager *d } static int _add_origin_target_to_dtree(struct dev_manager *dm, - struct dm_tree_node *dnode, - struct logical_volume *lv) + struct dm_tree_node *dnode, + struct logical_volume *lv, + int swap_snap_lvids) { const char *real_dlid, *cow_dlid; - if (!(real_dlid = build_dlid(dm, lv->lvid.s, "real"))) + if (!(real_dlid = build_dlid(dm, !swap_snap_lvids ? lv->lvid.s : + lv->merging_snapshot->cow->lvid.s, + "real"))) return_0; if (!lv->merging_snapshot) { if (!dm_tree_node_add_snapshot_origin_target(dnode, lv->size, real_dlid)) return_0; } else { - if (!(cow_dlid = build_dlid(dm, lv->merging_snapshot->cow->lvid.s, "cow"))) + if (!(cow_dlid = build_dlid(dm, !swap_snap_lvids ? + lv->merging_snapshot->cow->lvid.s : + lv->merging_snapshot->origin->lvid.s, "cow"))) return_0; if (!dm_tree_node_add_snapshot_merge_target(dnode, lv->size, real_dlid, cow_dlid, lv->merging_snapshot->chunk_size)) return_0; @@ -859,7 +864,8 @@ static int _add_origin_target_to_dtree(s static int _add_snapshot_target_to_dtree(struct dev_manager *dm, struct dm_tree_node *dnode, - struct logical_volume *lv) + struct logical_volume *lv, + int swap_snap_lvids) { const char *origin_dlid; const char *cow_dlid; @@ -875,7 +881,10 @@ static int _add_snapshot_target_to_dtree return 1; } - if (!(origin_dlid = build_dlid(dm, snap_seg->origin->lvid.s, "real"))) + if (!(origin_dlid = build_dlid(dm, !swap_snap_lvids ? + snap_seg->origin->lvid.s : + snap_seg->origin->merging_snapshot->cow->lvid.s, + "real"))) return_0; if (!(cow_dlid = build_dlid(dm, snap_seg->cow->lvid.s, "cow"))) @@ -908,6 +917,15 @@ static int _add_target_to_dtree(struct d &dm-> pvmove_mirror_count); } +static int check_if_exists(struct dev_manager *dm, struct dm_tree *dtree, + const char *lvid, const char *layer) +{ + char *dlid; + if (!(dlid = build_dlid(dm, lvid, layer))) + return 0; + return !!dm_tree_find_node_by_uuid(dtree, dlid); +} + static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, struct logical_volume *lv, const char *lv_name, const char *layer); @@ -922,6 +940,8 @@ static int _add_segment_to_dtree(struct struct dm_list *snh; struct lv_segment *seg_present; + int swap_snap_lvids = 0; + /* Ensure required device-mapper targets are loaded */ seg_present = find_cow(seg->lv) ? : seg; @@ -942,6 +962,23 @@ static int _add_segment_to_dtree(struct !_add_new_lv_to_dtree(dm, dtree, seg->log_lv, NULL, NULL)) return_0; + if (!layer) { +/* + * Possibly swap lvids of underlying -cow and -real devices, if they + * were swapped when merging started. + */ + struct logical_volume *origin = NULL; + if (lv_is_origin(seg->lv)) origin = seg->lv; + if (lv_is_cow(seg->lv)) origin = origin_from_cow(seg->lv); + if (origin && origin->merging_snapshot) { + if (check_if_exists(dm, dtree, + origin->merging_snapshot->origin->lvid.s, "cow") && + check_if_exists(dm, dtree, + origin->merging_snapshot->cow->lvid.s, "real")) + swap_snap_lvids = 1; + } + } + /* If this is a snapshot origin, add real LV */ if (lv_is_origin(seg->lv) && !layer) { if (vg_is_clustered(seg->lv->vg)) { @@ -950,12 +987,19 @@ static int _add_segment_to_dtree(struct } if (seg->lv->merging_snapshot) { if (!_add_new_lv_to_dtree(dm, dtree, - seg->lv->merging_snapshot->cow, + !swap_snap_lvids ? seg->lv->merging_snapshot->cow : + seg->lv->merging_snapshot->origin, seg->lv->merging_snapshot->origin->name, "cow")) return_0; + if (!_add_new_lv_to_dtree(dm, dtree, !swap_snap_lvids ? + seg->lv->merging_snapshot->origin : + seg->lv->merging_snapshot->cow, + seg->lv->name, "real")) + return_0; + } else { + if (!_add_new_lv_to_dtree(dm, dtree, seg->lv, NULL, "real")) + return_0; } - if (!_add_new_lv_to_dtree(dm, dtree, seg->lv, NULL, "real")) - return_0; } else if (lv_is_cow(seg->lv) && !layer) { if (!_add_new_lv_to_dtree(dm, dtree, seg->lv, NULL, "cow")) return_0; @@ -970,10 +1014,12 @@ static int _add_segment_to_dtree(struct /* Now we've added its dependencies, we can add the target itself */ if (lv_is_origin(seg->lv) && !layer) { - if (!_add_origin_target_to_dtree(dm, dnode, seg->lv)) + if (!_add_origin_target_to_dtree(dm, dnode, seg->lv, + swap_snap_lvids)) return_0; } else if (lv_is_cow(seg->lv) && !layer) { - if (!_add_snapshot_target_to_dtree(dm, dnode, seg->lv)) + if (!_add_snapshot_target_to_dtree(dm, dnode, seg->lv, + swap_snap_lvids)) return_0; } else if (!_add_target_to_dtree(dm, dnode, seg)) return_0;