From 4ca55192e0347c0c5124f7f2d8c1c30aa4d57a43 Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Tue, 12 Jul 2016 16:15:32 +0200 Subject: [PATCH] vgsplit: temporary list pointer may be invalid 4420d41fea8 introduced recursive split of lvs which splits a top-level LV together with it's sub LVs. This lead to invalid temporary list pointers causing hangs/OOM situations. Patch updates the temporary list pointer referencing a moved sub LV. - resolves rhbz1354686 --- tools/vgsplit.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/tools/vgsplit.c b/tools/vgsplit.c index 221600e82..806dafe64 100644 --- a/tools/vgsplit.c +++ b/tools/vgsplit.c @@ -35,6 +35,7 @@ static struct dm_list *_lvh_in_vg(struct logical_volume *lv, struct volume_group } static int _lv_tree_move(struct dm_list *lvh, + struct dm_list **lvht, struct volume_group *vg_from, struct volume_group *vg_to) { @@ -43,6 +44,10 @@ static int _lv_tree_move(struct dm_list *lvh, struct lv_segment *seg = first_seg(lv); struct dm_list *lvh1; + /* Update the list pointer refering to the item moving to @vg_to. */ + if (lvh == *lvht) + *lvht = lvh->n; + dm_list_move(&vg_to->lvs, lvh); lv->vg = vg_to; lv->lvid.id[0] = lv->vg->id; @@ -51,7 +56,7 @@ static int _lv_tree_move(struct dm_list *lvh, for (s = 0; s < seg->area_count; s++) if (seg_type(seg, s) == AREA_LV && seg_lv(seg, s)) { if ((lvh1 = _lvh_in_vg(seg_lv(seg, s), vg_from))) { - if (!_lv_tree_move(lvh1, vg_from, vg_to)) + if (!_lv_tree_move(lvh1, lvht, vg_from, vg_to)) return 0; } else if (!_lvh_in_vg(seg_lv(seg, s), vg_to)) return 0; @@ -62,7 +67,8 @@ static int _lv_tree_move(struct dm_list *lvh, static int _move_one_lv(struct volume_group *vg_from, struct volume_group *vg_to, - struct dm_list *lvh) + struct dm_list *lvh, + struct dm_list **lvht) { struct logical_volume *lv = dm_list_item(lvh, struct lv_list)->lv; struct logical_volume *parent_lv; @@ -82,7 +88,7 @@ static int _move_one_lv(struct volume_group *vg_from, return 0; } - if (!_lv_tree_move(lvh, vg_from, vg_to)) + if (!_lv_tree_move(lvh, lvht, vg_from, vg_to)) return 0; /* Moved pool metadata spare LV */ @@ -163,7 +169,7 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to) continue; /* Move this LV */ - if (!_move_one_lv(vg_from, vg_to, lvh)) + if (!_move_one_lv(vg_from, vg_to, lvh, &lvht)) return_0; } @@ -209,7 +215,7 @@ 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)) { - if (!_move_one_lv(vg_from, vg_to, lvh)) + if (!_move_one_lv(vg_from, vg_to, lvh, &lvht)) return_0; } } @@ -271,7 +277,7 @@ static int _move_mirrors(struct volume_group *vg_from, } if (seg_in == seg->area_count && log_in) { - if (!_move_one_lv(vg_from, vg_to, lvh)) + if (!_move_one_lv(vg_from, vg_to, lvh, &lvht)) return_0; } } @@ -303,7 +309,7 @@ static int _move_raids(struct volume_group *vg_from, continue; /* If allocations are on PVs of @vg_to -> move RAID LV stack across */ - if (!_move_one_lv(vg_from, vg_to, lvh)) + if (!_move_one_lv(vg_from, vg_to, lvh, &lvht)) return_0; } @@ -338,7 +344,7 @@ static int _move_thins(struct volume_group *vg_from, seg->pool_lv->name); return 0; } - if (!_move_one_lv(vg_from, vg_to, lvh)) + if (!_move_one_lv(vg_from, vg_to, lvh, &lvht)) return_0; } } else if (lv_is_thin_pool(lv)) { @@ -358,7 +364,7 @@ static int _move_thins(struct volume_group *vg_from, lv->name); return 0; } - if (!_move_one_lv(vg_from, vg_to, lvh)) + if (!_move_one_lv(vg_from, vg_to, lvh, &lvht)) return_0; } } @@ -439,7 +445,7 @@ static int _move_cache(struct volume_group *vg_from, lv->name, meta->name); return 0; } - if (!_move_one_lv(vg_from, vg_to, lvh)) + if (!_move_one_lv(vg_from, vg_to, lvh, &lvht)) return_0; }