Prior to this change, a VG with any active LVs would cause vgsplit to fail. However there should be no reason we cannot split a VG, provided the LVs involved in the split are inactive. Fixes bz 252041. Signed-off-by: Dave Wysochanski --- lib/activate/activate.c | 6 ++-- lib/activate/activate.h | 2 + test/t-vgsplit-operation.sh | 62 +++++++++++++++++++++++++++++++++++++++--- tools/vgchange.c | 8 +++--- tools/vgsplit.c | 54 ++++++++++++++++++++----------------- 5 files changed, 95 insertions(+), 37 deletions(-) diff --git a/lib/activate/activate.c b/lib/activate/activate.c index 7b959cd..fe18a5e 100644 --- a/lib/activate/activate.c +++ b/lib/activate/activate.c @@ -542,8 +542,8 @@ int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv, return r; } -static int _lv_active(struct cmd_context *cmd, struct logical_volume *lv, - unsigned by_uuid_only) +int lv_active(struct cmd_context *cmd, struct logical_volume *lv, + unsigned by_uuid_only) { struct lvinfo info; @@ -641,7 +641,7 @@ static int _lvs_in_vg_activated(struct volume_group *vg, unsigned by_uuid_only) list_iterate_items(lvl, &vg->lvs) { if (lvl->lv->status & VISIBLE_LV) - count += (_lv_active(vg->cmd, lvl->lv, by_uuid_only) == 1); + count += (lv_active(vg->cmd, lvl->lv, by_uuid_only) == 1); } return count; diff --git a/lib/activate/activate.h b/lib/activate/activate.h index ec68251..b86e1b0 100644 --- a/lib/activate/activate.h +++ b/lib/activate/activate.h @@ -91,6 +91,8 @@ int lvs_in_vg_activated(struct volume_group *vg); int lvs_in_vg_activated_by_uuid_only(struct volume_group *vg); int lvs_in_vg_opened(const struct volume_group *vg); +int lv_active(struct cmd_context *cmd, struct logical_volume *lv, + unsigned by_uuid_only); int monitor_dev_for_events(struct cmd_context *cmd, struct logical_volume *lv, int do_reg); diff --git a/test/t-vgsplit-operation.sh b/test/t-vgsplit-operation.sh index 58a054e..3a32141 100755 --- a/test/t-vgsplit-operation.sh +++ b/test/t-vgsplit-operation.sh @@ -222,7 +222,7 @@ test_expect_success \ lvcreate -l 4 -n $lv3 -i 2 $vg1 $d3 $d4 && vgchange -an $vg1 && vgsplit -n $lv1 $vg1 $vg2; - status=$?; echo status=$?; test $status = 5 && + status=$?; echo status=$status; test $status = 5 && vgremove -ff $vg1' test_expect_success \ @@ -234,7 +234,7 @@ test_expect_success \ vg_validate_pvlv_counts_ $vg1 4 1 2 && vgchange -an $vg1 && vgsplit -n $lv1 $vg1 $vg2; - status=$?; echo status=$?; test $status = 5 && + status=$?; echo status=$status; test $status = 5 && lvremove -f $vg1/$lv2 && lvremove -f $vg1/$lv3 && lvremove -f $vg1/$lv1 && @@ -249,7 +249,7 @@ test_expect_success \ vg_validate_pvlv_counts_ $vg1 4 1 2 && vgchange -an $vg1 && vgsplit -n $lv2 $vg1 $vg2; - status=$?; echo status=$?; test $status = 5 && + status=$?; echo status=$status; test $status = 5 && lvremove -f $vg1/$lv2 && lvremove -f $vg1/$lv3 && lvremove -f $vg1/$lv1 && @@ -262,7 +262,7 @@ test_expect_success \ vg_validate_pvlv_counts_ $vg1 4 4 0 && vgchange -an $vg1 && vgsplit $vg1 $vg2 $d2 && - status=$?; echo status=$?; test $status = 5 && + status=$?; echo status=$status; test $status = 5 && vgremove -ff $vg1' test_expect_success \ @@ -273,8 +273,60 @@ test_expect_success \ vg_validate_pvlv_counts_ $vg1 4 5 0 && vgchange -an $vg1 && vgsplit -n $lv2 $vg1 $vg2 2>err; - status=$?; echo status=$?; test $status = 5 && + status=$?; echo status=$status; test $status = 5 && vgremove -ff $vg1' +# +# Verify vgsplit rejects active LVs only when active LVs involved in split +# +test_expect_success \ + "vgsplit fails, active mirror involved in split" \ + 'vgcreate $vg1 $d1 $d2 $d3 $d4 && + lvcreate -l 16 -n $lv1 -m1 $vg1 $d1 $d2 $d3 && + lvcreate -l 16 -n $lv2 $vg1 $d4 && + lvchange -an $vg1/$lv2 && + vg_validate_pvlv_counts_ $vg1 4 5 0 && + vgsplit -n $lv1 $vg1 $vg2; + status=$?; echo status=$status; test $status = 5 && + vgremove -ff $vg1' + +test_expect_success \ + "vgsplit succeeds, active mirror not involved in split" \ + 'vgcreate $vg1 $d1 $d2 $d3 $d4 && + lvcreate -l 16 -n $lv1 -m1 $vg1 $d1 $d2 $d3 && + lvcreate -l 16 -n $lv2 $vg1 $d4 && + lvchange -an $vg1/$lv2 && + vg_validate_pvlv_counts_ $vg1 4 5 0 && + vgsplit -n $lv2 $vg1 $vg2 && + vgremove -ff $vg1 && + vgremove -ff $vg2' + +test_expect_success \ + "vgsplit fails, active snapshot involved in split" \ + 'vgcreate $vg1 $d1 $d2 $d3 $d4 && + lvcreate -l 64 -i 2 -n $lv1 $vg1 $d1 $d2 && + lvcreate -l 4 -i 2 -s -n $lv2 $vg1/$lv1 && + lvcreate -l 64 -i 2 -n $lv3 $vg1 $d3 $d4 && + lvchange -an $vg1/$lv3 && + vg_validate_pvlv_counts_ $vg1 4 2 1 && + vgsplit -n $lv2 $vg1 $vg2; + status=$?; echo status=$status; test $status = 5 && + lvremove -f $vg1/$lv2 && + vgremove -ff $vg1' + +test_expect_success \ + "vgsplit succeeds, active snapshot not involved in split" \ + 'vgcreate $vg1 $d1 $d2 $d3 && + lvcreate -l 64 -i 2 -n $lv1 $vg1 $d1 $d2 && + lvcreate -l 4 -s -n $lv2 $vg1/$lv1 && + vgextend $vg1 $d4 && + lvcreate -l 64 -n $lv3 $vg1 $d4 && + lvchange -an $vg1/$lv3 && + vg_validate_pvlv_counts_ $vg1 4 2 1 && + vgsplit -n $lv3 $vg1 $vg2 && + vgchange -an $vg1 && + lvremove -f $vg1/$lv2 && + vgremove -ff $vg1 && + vgremove -ff $vg2' test_done diff --git a/tools/vgchange.c b/tools/vgchange.c index 634f620..519d7a5 100644 --- a/tools/vgchange.c +++ b/tools/vgchange.c @@ -21,21 +21,21 @@ static int _monitor_lvs_in_vg(struct cmd_context *cmd, struct lv_list *lvl; struct logical_volume *lv; struct lvinfo info; - int lv_active; + int lv_is_active; int count = 0; list_iterate_items(lvl, &vg->lvs) { lv = lvl->lv; if (!lv_info(cmd, lv, &info, 0, 0)) - lv_active = 0; + lv_is_active = 0; else - lv_active = info.exists; + lv_is_active = info.exists; /* * FIXME: Need to consider all cases... PVMOVE, etc */ - if ((lv->status & PVMOVE) || !lv_active) + if ((lv->status & PVMOVE) || !lv_is_active) continue; if (!monitor_dev_for_events(cmd, lv, reg)) { diff --git a/tools/vgsplit.c b/tools/vgsplit.c index c083889..12cf16f 100644 --- a/tools/vgsplit.c +++ b/tools/vgsplit.c @@ -94,6 +94,29 @@ static int _lv_is_in_vg(struct volume_group *vg, struct logical_volume *lv) } +static int _move_one_lv(struct volume_group *vg_from, + struct volume_group *vg_to, + struct list *lvh) +{ + struct logical_volume *lv; + lv = list_item(lvh, struct lv_list)->lv; + if (lv_is_visible(lv) && lv_active(vg_from->cmd, lv, 0)) { + log_error("Logical volume \"%s\" must be inactive", lv->name); + return 0; + } + list_del(lvh); + list_add(&vg_to->lvs, lvh); + + if (lv->status & SNAPSHOT) { + vg_from->snapshot_count--; + vg_to->snapshot_count++; + } else { + vg_from->lv_count--; + vg_to->lv_count++; + } + return 1; +} + static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to) { struct list *lvh, *lvht; @@ -152,11 +175,8 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to) continue; /* Move this LV */ - list_del(lvh); - list_add(&vg_to->lvs, lvh); - - vg_from->lv_count--; - vg_to->lv_count++; + if (!_move_one_lv(vg_from, vg_to, lvh)) + return 0; } /* FIXME Ensure no LVs contain segs pointing at LVs in the other VG */ @@ -201,14 +221,10 @@ static int _move_snapshots(struct volume_group *vg_from, */ if (_lv_is_in_vg(vg_to, seg->cow) && _lv_is_in_vg(vg_to, seg->origin)) { - list_del(lvh); - list_add(&vg_to->lvs, lvh); - - vg_from->snapshot_count--; - vg_to->snapshot_count++; + if (!_move_one_lv(vg_from, vg_to, lvh)) + return 0; } } - } return 1; @@ -246,11 +262,8 @@ static int _move_mirrors(struct volume_group *vg_from, } if (seg_in == seg->area_count && log_in) { - list_del(lvh); - list_add(&vg_to->lvs, lvh); - - vg_from->lv_count--; - vg_to->lv_count++; + if (!_move_one_lv(vg_from, vg_to, lvh)) + return 0; } } @@ -275,7 +288,6 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv) char *vg_name_from, *vg_name_to; struct volume_group *vg_to, *vg_from; int opt; - int active; int existing_vg; int consistent; const char *lv_name; @@ -314,14 +326,6 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv) CORRECT_INCONSISTENT | FAIL_INCONSISTENT))) return ECMD_FAILED; - if ((active = lvs_in_vg_activated(vg_from))) { - /* FIXME Remove this restriction */ - log_error("Logical volumes in \"%s\" must be inactive", - vg_name_from); - unlock_vg(cmd, vg_name_from); - return ECMD_FAILED; - } - log_verbose("Checking for new volume group \"%s\"", vg_name_to); if (!lock_vol(cmd, vg_name_to, LCK_VG_WRITE | LCK_NONBLOCK)) { log_error("Can't get lock for %s", vg_name_to); -- 1.5.3.4 --