From a391248427e83252b87e78f15799f09b09017716 Mon Sep 17 00:00:00 2001 From: Jonathan Earl Brassow Date: Thu, 6 Oct 2011 14:17:45 +0000 Subject: [PATCH] Fix vgsplit when there are mirrors that have mirrored logs. The problem as reported by "ben " on lvm-devel: vgsplit fails with mirrored mirror log #lvs --all -o lv_name,lv_attr,devices LV Attr Devices MyMirror mwi-- [MyMirror_mimage_0] Iwi--- /dev/sdq(0) [MyMirror_mimage_1] Iwi--- /dev/sdo(0) [MyMirror_mimage_2] Iwi--- /dev/sdi(0) [MyMirror_mlog] mwi--- [MyMirror_mlog_mimage_0] Iwi--- /dev/sds(0) [MyMirror_mlog_mimage_1] Iwi--- /dev/sde(0) #vgsplit -v "TestA" "TestB" "/dev/sdq" "/dev/sdo" "/dev/sdi" "/dev/sds" "/dev/sde" Checking for volume group "TestA" Checking for new volume group "TestB" Archiving volume group "TestA" metadata (seqno 213). Can't split mirror MyMirror between two Volume Groups AFTER FIX: [root@bp-01 ~]# lvs -a -o name,vg_name,devices vg new Volume group "new" not found Skipping volume group new LV VG Devices lv vg lv_mimage_0(0),lv_mimage_1(0) [lv_mimage_0] vg /dev/sdb1(0) [lv_mimage_1] vg /dev/sdc1(0) [lv_mlog] vg lv_mlog_mimage_0(0),lv_mlog_mimage_1(0) [lv_mlog_mimage_0] vg /dev/sdh1(0) [lv_mlog_mimage_1] vg /dev/sdi1(0) [root@bp-01 ~]# vgsplit vg new /dev/sd[bchi]1 New volume group "new" successfully split from "vg" [root@bp-01 ~]# lvs -a -o name,vg_name,devices vg new LV VG Devices lv new lv_mimage_0(0),lv_mimage_1(0) [lv_mimage_0] new /dev/sdb1(0) [lv_mimage_1] new /dev/sdc1(0) [lv_mlog] new lv_mlog_mimage_0(0),lv_mlog_mimage_1(0) [lv_mlog_mimage_0] new /dev/sdh1(0) [lv_mlog_mimage_1] new /dev/sdi1(0) --- WHATS_NEW | 1 + test/t-vgsplit-operation.sh | 25 +++++++++++++++++++++++++ tools/vgsplit.c | 17 +++++++++++++++-- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/WHATS_NEW b/WHATS_NEW index 82c586c4e..6ad6384ba 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 2.02.89 - ================================== + Fix vgsplit when there are mirrors that have mirrored logs. Clarify multi-name device filter pattern matching explanation in lvm.conf.5. Introduce lv_send_message and dev_manager_send_message. Introduce revert_lv for better pvmove cleanup. diff --git a/test/t-vgsplit-operation.sh b/test/t-vgsplit-operation.sh index 4ff5bce86..20a5cb255 100755 --- a/test/t-vgsplit-operation.sh +++ b/test/t-vgsplit-operation.sh @@ -93,6 +93,31 @@ COMM "vgsplit correctly splits mirror LV into $i VG ($j args)" fi lvremove -f $vg2/$lv1 vgremove -f $vg2 +# FIXME: ensure split /doesn't/ work when not all devs of mirror specified + +COMM "vgsplit correctly splits mirror LV with mirrored log into $i VG ($j args)" + vgcreate -c n $vg1 $dev1 $dev2 $dev3 $dev4 + if [ $i = existing ]; then + vgcreate -c n $vg2 $dev5 + fi + + lvcreate -l 64 --mirrorlog mirrored -m1 -n $lv1 $vg1 \ + $dev1 $dev2 $dev3 $dev4 + + vgchange -an $vg1 + if [ $j = PV ]; then + vgsplit $vg1 $vg2 $dev1 $dev2 $dev3 $dev4 + else + vgsplit -n $lv1 $vg1 $vg2 + fi + if [ $i = existing ]; then + check pvlv_counts $vg2 5 1 0 + else + check pvlv_counts $vg2 4 1 0 + fi + lvremove -f $vg2/$lv1 + vgremove -f $vg2 +# FIXME: ensure split /doesn't/ work when not all devs of mirror specified COMM "vgsplit correctly splits origin and snapshot LV into $i VG ($j args)" vgcreate -c n $vg1 $dev1 $dev2 diff --git a/tools/vgsplit.c b/tools/vgsplit.c index 95b7d38dc..73f94a8d2 100644 --- a/tools/vgsplit.c +++ b/tools/vgsplit.c @@ -163,7 +163,7 @@ static int _move_mirrors(struct volume_group *vg_from, { struct dm_list *lvh, *lvht; struct logical_volume *lv; - struct lv_segment *seg; + struct lv_segment *seg, *log_seg; unsigned s, seg_in, log_in; dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) { @@ -179,7 +179,20 @@ static int _move_mirrors(struct volume_group *vg_from, if (_lv_is_in_vg(vg_to, seg_lv(seg, s))) seg_in++; - log_in = (!seg->log_lv || _lv_is_in_vg(vg_to, seg->log_lv)); + log_in = !seg->log_lv; + if (seg->log_lv) { + log_seg = first_seg(seg->log_lv); + if (seg_is_mirrored(log_seg)) { + log_in = 1; + + /* Ensure each log dev is in vg_to */ + for (s = 0; s < log_seg->area_count; s++) + log_in = log_in && + _lv_is_in_vg(vg_to, + seg_lv(log_seg, s)); + } else + log_in = _lv_is_in_vg(vg_to, seg->log_lv); + } if ((seg_in && seg_in < seg->area_count) || (seg_in && seg->log_lv && !log_in) ||