xref: /dflybsd-src/contrib/lvm2/dist/tools/vgsplit.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1*86d7f5d3SJohn Marino /*	$NetBSD: vgsplit.c,v 1.1.1.2 2009/12/02 00:25:46 haad Exp $	*/
2*86d7f5d3SJohn Marino 
3*86d7f5d3SJohn Marino /*
4*86d7f5d3SJohn Marino  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5*86d7f5d3SJohn Marino  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
6*86d7f5d3SJohn Marino  *
7*86d7f5d3SJohn Marino  * This file is part of LVM2.
8*86d7f5d3SJohn Marino  *
9*86d7f5d3SJohn Marino  * This copyrighted material is made available to anyone wishing to use,
10*86d7f5d3SJohn Marino  * modify, copy, or redistribute it subject to the terms and conditions
11*86d7f5d3SJohn Marino  * of the GNU Lesser General Public License v.2.1.
12*86d7f5d3SJohn Marino  *
13*86d7f5d3SJohn Marino  * You should have received a copy of the GNU Lesser General Public License
14*86d7f5d3SJohn Marino  * along with this program; if not, write to the Free Software Foundation,
15*86d7f5d3SJohn Marino  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16*86d7f5d3SJohn Marino  */
17*86d7f5d3SJohn Marino 
18*86d7f5d3SJohn Marino #include "tools.h"
19*86d7f5d3SJohn Marino 
20*86d7f5d3SJohn Marino /* FIXME Why not (lv->vg == vg) ? */
_lv_is_in_vg(struct volume_group * vg,struct logical_volume * lv)21*86d7f5d3SJohn Marino static int _lv_is_in_vg(struct volume_group *vg, struct logical_volume *lv)
22*86d7f5d3SJohn Marino {
23*86d7f5d3SJohn Marino 	struct lv_list *lvl;
24*86d7f5d3SJohn Marino 
25*86d7f5d3SJohn Marino 	dm_list_iterate_items(lvl, &vg->lvs)
26*86d7f5d3SJohn Marino 		if (lv == lvl->lv)
27*86d7f5d3SJohn Marino 			 return 1;
28*86d7f5d3SJohn Marino 
29*86d7f5d3SJohn Marino 	return 0;
30*86d7f5d3SJohn Marino }
31*86d7f5d3SJohn Marino 
_move_one_lv(struct volume_group * vg_from,struct volume_group * vg_to,struct dm_list * lvh)32*86d7f5d3SJohn Marino static int _move_one_lv(struct volume_group *vg_from,
33*86d7f5d3SJohn Marino 			 struct volume_group *vg_to,
34*86d7f5d3SJohn Marino 			 struct dm_list *lvh)
35*86d7f5d3SJohn Marino {
36*86d7f5d3SJohn Marino 	struct logical_volume *lv = dm_list_item(lvh, struct lv_list)->lv;
37*86d7f5d3SJohn Marino 
38*86d7f5d3SJohn Marino 	dm_list_move(&vg_to->lvs, lvh);
39*86d7f5d3SJohn Marino 
40*86d7f5d3SJohn Marino 	if (lv_is_active(lv)) {
41*86d7f5d3SJohn Marino 		log_error("Logical volume \"%s\" must be inactive", lv->name);
42*86d7f5d3SJohn Marino 		return 0;
43*86d7f5d3SJohn Marino 	}
44*86d7f5d3SJohn Marino 
45*86d7f5d3SJohn Marino 	return 1;
46*86d7f5d3SJohn Marino }
47*86d7f5d3SJohn Marino 
_move_lvs(struct volume_group * vg_from,struct volume_group * vg_to)48*86d7f5d3SJohn Marino static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
49*86d7f5d3SJohn Marino {
50*86d7f5d3SJohn Marino 	struct dm_list *lvh, *lvht;
51*86d7f5d3SJohn Marino 	struct logical_volume *lv;
52*86d7f5d3SJohn Marino 	struct lv_segment *seg;
53*86d7f5d3SJohn Marino 	struct physical_volume *pv;
54*86d7f5d3SJohn Marino 	struct volume_group *vg_with;
55*86d7f5d3SJohn Marino 	unsigned s;
56*86d7f5d3SJohn Marino 
57*86d7f5d3SJohn Marino 	dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) {
58*86d7f5d3SJohn Marino 		lv = dm_list_item(lvh, struct lv_list)->lv;
59*86d7f5d3SJohn Marino 
60*86d7f5d3SJohn Marino 		if ((lv->status & SNAPSHOT))
61*86d7f5d3SJohn Marino 			continue;
62*86d7f5d3SJohn Marino 
63*86d7f5d3SJohn Marino 		if ((lv->status & MIRRORED))
64*86d7f5d3SJohn Marino 			continue;
65*86d7f5d3SJohn Marino 
66*86d7f5d3SJohn Marino 		/* Ensure all the PVs used by this LV remain in the same */
67*86d7f5d3SJohn Marino 		/* VG as each other */
68*86d7f5d3SJohn Marino 		vg_with = NULL;
69*86d7f5d3SJohn Marino 		dm_list_iterate_items(seg, &lv->segments) {
70*86d7f5d3SJohn Marino 			for (s = 0; s < seg->area_count; s++) {
71*86d7f5d3SJohn Marino 				/* FIXME Check AREA_LV too */
72*86d7f5d3SJohn Marino 				if (seg_type(seg, s) != AREA_PV)
73*86d7f5d3SJohn Marino 					continue;
74*86d7f5d3SJohn Marino 
75*86d7f5d3SJohn Marino 				pv = seg_pv(seg, s);
76*86d7f5d3SJohn Marino 				if (vg_with) {
77*86d7f5d3SJohn Marino 					if (!pv_is_in_vg(vg_with, pv)) {
78*86d7f5d3SJohn Marino 						log_error("Can't split Logical "
79*86d7f5d3SJohn Marino 							  "Volume %s between "
80*86d7f5d3SJohn Marino 							  "two Volume Groups",
81*86d7f5d3SJohn Marino 							  lv->name);
82*86d7f5d3SJohn Marino 						return 0;
83*86d7f5d3SJohn Marino 					}
84*86d7f5d3SJohn Marino 					continue;
85*86d7f5d3SJohn Marino 				}
86*86d7f5d3SJohn Marino 
87*86d7f5d3SJohn Marino 				if (pv_is_in_vg(vg_from, pv)) {
88*86d7f5d3SJohn Marino 					vg_with = vg_from;
89*86d7f5d3SJohn Marino 					continue;
90*86d7f5d3SJohn Marino 				}
91*86d7f5d3SJohn Marino 				if (pv_is_in_vg(vg_to, pv)) {
92*86d7f5d3SJohn Marino 					vg_with = vg_to;
93*86d7f5d3SJohn Marino 					continue;
94*86d7f5d3SJohn Marino 				}
95*86d7f5d3SJohn Marino 				log_error("Physical Volume %s not found",
96*86d7f5d3SJohn Marino 					  pv_dev_name(pv));
97*86d7f5d3SJohn Marino 				return 0;
98*86d7f5d3SJohn Marino 			}
99*86d7f5d3SJohn Marino 
100*86d7f5d3SJohn Marino 		}
101*86d7f5d3SJohn Marino 
102*86d7f5d3SJohn Marino 		if (vg_with == vg_from)
103*86d7f5d3SJohn Marino 			continue;
104*86d7f5d3SJohn Marino 
105*86d7f5d3SJohn Marino 		/* Move this LV */
106*86d7f5d3SJohn Marino 		if (!_move_one_lv(vg_from, vg_to, lvh))
107*86d7f5d3SJohn Marino 			return_0;
108*86d7f5d3SJohn Marino 	}
109*86d7f5d3SJohn Marino 
110*86d7f5d3SJohn Marino 	/* FIXME Ensure no LVs contain segs pointing at LVs in the other VG */
111*86d7f5d3SJohn Marino 
112*86d7f5d3SJohn Marino 	return 1;
113*86d7f5d3SJohn Marino }
114*86d7f5d3SJohn Marino 
115*86d7f5d3SJohn Marino /*
116*86d7f5d3SJohn Marino  * Move the hidden / internal "snapshotN" LVs.from 'vg_from' to 'vg_to'.
117*86d7f5d3SJohn Marino  */
_move_snapshots(struct volume_group * vg_from,struct volume_group * vg_to)118*86d7f5d3SJohn Marino static int _move_snapshots(struct volume_group *vg_from,
119*86d7f5d3SJohn Marino 			   struct volume_group *vg_to)
120*86d7f5d3SJohn Marino {
121*86d7f5d3SJohn Marino 	struct dm_list *lvh, *lvht;
122*86d7f5d3SJohn Marino 	struct logical_volume *lv;
123*86d7f5d3SJohn Marino 	struct lv_segment *seg;
124*86d7f5d3SJohn Marino 	int cow_from = 0;
125*86d7f5d3SJohn Marino 	int origin_from = 0;
126*86d7f5d3SJohn Marino 
127*86d7f5d3SJohn Marino 	dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) {
128*86d7f5d3SJohn Marino 		lv = dm_list_item(lvh, struct lv_list)->lv;
129*86d7f5d3SJohn Marino 
130*86d7f5d3SJohn Marino 		if (!(lv->status & SNAPSHOT))
131*86d7f5d3SJohn Marino 			continue;
132*86d7f5d3SJohn Marino 
133*86d7f5d3SJohn Marino 		dm_list_iterate_items(seg, &lv->segments) {
134*86d7f5d3SJohn Marino 			cow_from = _lv_is_in_vg(vg_from, seg->cow);
135*86d7f5d3SJohn Marino 			origin_from = _lv_is_in_vg(vg_from, seg->origin);
136*86d7f5d3SJohn Marino 
137*86d7f5d3SJohn Marino 			if (cow_from && origin_from)
138*86d7f5d3SJohn Marino 				continue;
139*86d7f5d3SJohn Marino 			if ((!cow_from && origin_from) ||
140*86d7f5d3SJohn Marino 			     (cow_from && !origin_from)) {
141*86d7f5d3SJohn Marino 				log_error("Can't split snapshot %s between"
142*86d7f5d3SJohn Marino 					  " two Volume Groups", seg->cow->name);
143*86d7f5d3SJohn Marino 				return 0;
144*86d7f5d3SJohn Marino 			}
145*86d7f5d3SJohn Marino 
146*86d7f5d3SJohn Marino 			/*
147*86d7f5d3SJohn Marino 			 * At this point, the cow and origin should already be
148*86d7f5d3SJohn Marino 			 * in vg_to.
149*86d7f5d3SJohn Marino 			 */
150*86d7f5d3SJohn Marino 			if (_lv_is_in_vg(vg_to, seg->cow) &&
151*86d7f5d3SJohn Marino 			    _lv_is_in_vg(vg_to, seg->origin)) {
152*86d7f5d3SJohn Marino 				if (!_move_one_lv(vg_from, vg_to, lvh))
153*86d7f5d3SJohn Marino 					return_0;
154*86d7f5d3SJohn Marino 			}
155*86d7f5d3SJohn Marino 		}
156*86d7f5d3SJohn Marino 
157*86d7f5d3SJohn Marino 	}
158*86d7f5d3SJohn Marino 
159*86d7f5d3SJohn Marino 	return 1;
160*86d7f5d3SJohn Marino }
161*86d7f5d3SJohn Marino 
_move_mirrors(struct volume_group * vg_from,struct volume_group * vg_to)162*86d7f5d3SJohn Marino static int _move_mirrors(struct volume_group *vg_from,
163*86d7f5d3SJohn Marino 			 struct volume_group *vg_to)
164*86d7f5d3SJohn Marino {
165*86d7f5d3SJohn Marino 	struct dm_list *lvh, *lvht;
166*86d7f5d3SJohn Marino 	struct logical_volume *lv;
167*86d7f5d3SJohn Marino 	struct lv_segment *seg;
168*86d7f5d3SJohn Marino 	unsigned s, seg_in, log_in;
169*86d7f5d3SJohn Marino 
170*86d7f5d3SJohn Marino 	dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) {
171*86d7f5d3SJohn Marino 		lv = dm_list_item(lvh, struct lv_list)->lv;
172*86d7f5d3SJohn Marino 
173*86d7f5d3SJohn Marino 		if (!(lv->status & MIRRORED))
174*86d7f5d3SJohn Marino 			continue;
175*86d7f5d3SJohn Marino 
176*86d7f5d3SJohn Marino 		seg = first_seg(lv);
177*86d7f5d3SJohn Marino 
178*86d7f5d3SJohn Marino 		seg_in = 0;
179*86d7f5d3SJohn Marino 		for (s = 0; s < seg->area_count; s++)
180*86d7f5d3SJohn Marino 			if (_lv_is_in_vg(vg_to, seg_lv(seg, s)))
181*86d7f5d3SJohn Marino 			    seg_in++;
182*86d7f5d3SJohn Marino 
183*86d7f5d3SJohn Marino 		log_in = (!seg->log_lv || _lv_is_in_vg(vg_to, seg->log_lv));
184*86d7f5d3SJohn Marino 
185*86d7f5d3SJohn Marino 		if ((seg_in && seg_in < seg->area_count) ||
186*86d7f5d3SJohn Marino 		    (seg_in && seg->log_lv && !log_in) ||
187*86d7f5d3SJohn Marino 		    (!seg_in && seg->log_lv && log_in)) {
188*86d7f5d3SJohn Marino 			log_error("Can't split mirror %s between "
189*86d7f5d3SJohn Marino 				  "two Volume Groups", lv->name);
190*86d7f5d3SJohn Marino 			return 0;
191*86d7f5d3SJohn Marino 		}
192*86d7f5d3SJohn Marino 
193*86d7f5d3SJohn Marino 		if (seg_in == seg->area_count && log_in) {
194*86d7f5d3SJohn Marino 			if (!_move_one_lv(vg_from, vg_to, lvh))
195*86d7f5d3SJohn Marino 				return_0;
196*86d7f5d3SJohn Marino 		}
197*86d7f5d3SJohn Marino 	}
198*86d7f5d3SJohn Marino 
199*86d7f5d3SJohn Marino 	return 1;
200*86d7f5d3SJohn Marino }
201*86d7f5d3SJohn Marino 
202*86d7f5d3SJohn Marino /*
203*86d7f5d3SJohn Marino  * Create or open the destination of the vgsplit operation.
204*86d7f5d3SJohn Marino  * Returns
205*86d7f5d3SJohn Marino  * - non-NULL: VG handle w/VG lock held
206*86d7f5d3SJohn Marino  * - NULL: no VG lock held
207*86d7f5d3SJohn Marino  */
_vgsplit_to(struct cmd_context * cmd,const char * vg_name_to,int * existing_vg)208*86d7f5d3SJohn Marino static struct volume_group *_vgsplit_to(struct cmd_context *cmd,
209*86d7f5d3SJohn Marino 					const char *vg_name_to,
210*86d7f5d3SJohn Marino 					int *existing_vg)
211*86d7f5d3SJohn Marino {
212*86d7f5d3SJohn Marino 	struct volume_group *vg_to = NULL;
213*86d7f5d3SJohn Marino 
214*86d7f5d3SJohn Marino 	log_verbose("Checking for new volume group \"%s\"", vg_name_to);
215*86d7f5d3SJohn Marino 	/*
216*86d7f5d3SJohn Marino 	 * First try to create a new VG.  If we cannot create it,
217*86d7f5d3SJohn Marino 	 * and we get FAILED_EXIST (we will not be holding a lock),
218*86d7f5d3SJohn Marino 	 * a VG must already exist with this name.  We then try to
219*86d7f5d3SJohn Marino 	 * read the existing VG - the vgsplit will be into an existing VG.
220*86d7f5d3SJohn Marino 	 *
221*86d7f5d3SJohn Marino 	 * Otherwise, if the lock was successful, it must be the case that
222*86d7f5d3SJohn Marino 	 * we obtained a WRITE lock and could not find the vgname in the
223*86d7f5d3SJohn Marino 	 * system.  Thus, the split will be into a new VG.
224*86d7f5d3SJohn Marino 	 */
225*86d7f5d3SJohn Marino 	vg_to = vg_create(cmd, vg_name_to);
226*86d7f5d3SJohn Marino 	if (vg_read_error(vg_to) == FAILED_LOCKING) {
227*86d7f5d3SJohn Marino 		log_error("Can't get lock for %s", vg_name_to);
228*86d7f5d3SJohn Marino 		vg_release(vg_to);
229*86d7f5d3SJohn Marino 		return NULL;
230*86d7f5d3SJohn Marino 	}
231*86d7f5d3SJohn Marino 	if (vg_read_error(vg_to) == FAILED_EXIST) {
232*86d7f5d3SJohn Marino 		*existing_vg = 1;
233*86d7f5d3SJohn Marino 		vg_release(vg_to);
234*86d7f5d3SJohn Marino 		vg_to = vg_read_for_update(cmd, vg_name_to, NULL, 0);
235*86d7f5d3SJohn Marino 
236*86d7f5d3SJohn Marino 		if (vg_read_error(vg_to)) {
237*86d7f5d3SJohn Marino 			vg_release(vg_to);
238*86d7f5d3SJohn Marino 			stack;
239*86d7f5d3SJohn Marino 			return NULL;
240*86d7f5d3SJohn Marino 		}
241*86d7f5d3SJohn Marino 
242*86d7f5d3SJohn Marino 	} else if (vg_read_error(vg_to) == SUCCESS) {
243*86d7f5d3SJohn Marino 		*existing_vg = 0;
244*86d7f5d3SJohn Marino 	}
245*86d7f5d3SJohn Marino 	return vg_to;
246*86d7f5d3SJohn Marino }
247*86d7f5d3SJohn Marino 
248*86d7f5d3SJohn Marino /*
249*86d7f5d3SJohn Marino  * Open the source of the vgsplit operation.
250*86d7f5d3SJohn Marino  * Returns
251*86d7f5d3SJohn Marino  * - non-NULL: VG handle w/VG lock held
252*86d7f5d3SJohn Marino  * - NULL: no VG lock held
253*86d7f5d3SJohn Marino  */
_vgsplit_from(struct cmd_context * cmd,const char * vg_name_from)254*86d7f5d3SJohn Marino static struct volume_group *_vgsplit_from(struct cmd_context *cmd,
255*86d7f5d3SJohn Marino 					  const char *vg_name_from)
256*86d7f5d3SJohn Marino {
257*86d7f5d3SJohn Marino 	struct volume_group *vg_from;
258*86d7f5d3SJohn Marino 
259*86d7f5d3SJohn Marino 	log_verbose("Checking for volume group \"%s\"", vg_name_from);
260*86d7f5d3SJohn Marino 
261*86d7f5d3SJohn Marino 	vg_from = vg_read_for_update(cmd, vg_name_from, NULL, 0);
262*86d7f5d3SJohn Marino 	if (vg_read_error(vg_from)) {
263*86d7f5d3SJohn Marino 		vg_release(vg_from);
264*86d7f5d3SJohn Marino 		return NULL;
265*86d7f5d3SJohn Marino 	}
266*86d7f5d3SJohn Marino 	return vg_from;
267*86d7f5d3SJohn Marino }
268*86d7f5d3SJohn Marino 
269*86d7f5d3SJohn Marino /*
270*86d7f5d3SJohn Marino  * Has the user given an option related to a new vg as the split destination?
271*86d7f5d3SJohn Marino  */
new_vg_option_specified(struct cmd_context * cmd)272*86d7f5d3SJohn Marino static int new_vg_option_specified(struct cmd_context *cmd)
273*86d7f5d3SJohn Marino {
274*86d7f5d3SJohn Marino 	return(arg_count(cmd, clustered_ARG) ||
275*86d7f5d3SJohn Marino 	       arg_count(cmd, alloc_ARG) ||
276*86d7f5d3SJohn Marino 	       arg_count(cmd, maxphysicalvolumes_ARG) ||
277*86d7f5d3SJohn Marino 	       arg_count(cmd, maxlogicalvolumes_ARG));
278*86d7f5d3SJohn Marino }
279*86d7f5d3SJohn Marino 
vgsplit(struct cmd_context * cmd,int argc,char ** argv)280*86d7f5d3SJohn Marino int vgsplit(struct cmd_context *cmd, int argc, char **argv)
281*86d7f5d3SJohn Marino {
282*86d7f5d3SJohn Marino 	struct vgcreate_params vp_new;
283*86d7f5d3SJohn Marino 	struct vgcreate_params vp_def;
284*86d7f5d3SJohn Marino 	char *vg_name_from, *vg_name_to;
285*86d7f5d3SJohn Marino 	struct volume_group *vg_to = NULL, *vg_from = NULL;
286*86d7f5d3SJohn Marino 	int opt;
287*86d7f5d3SJohn Marino 	int existing_vg = 0;
288*86d7f5d3SJohn Marino 	int r = ECMD_FAILED;
289*86d7f5d3SJohn Marino 	const char *lv_name;
290*86d7f5d3SJohn Marino 	int lock_vg_from_first = 1;
291*86d7f5d3SJohn Marino 
292*86d7f5d3SJohn Marino 	if ((arg_count(cmd, name_ARG) + argc) < 3) {
293*86d7f5d3SJohn Marino 		log_error("Existing VG, new VG and either physical volumes "
294*86d7f5d3SJohn Marino 			  "or logical volume required.");
295*86d7f5d3SJohn Marino 		return EINVALID_CMD_LINE;
296*86d7f5d3SJohn Marino 	}
297*86d7f5d3SJohn Marino 
298*86d7f5d3SJohn Marino 	if (arg_count(cmd, name_ARG) && (argc > 2)) {
299*86d7f5d3SJohn Marino 		log_error("A logical volume name cannot be given with "
300*86d7f5d3SJohn Marino 			  "physical volumes.");
301*86d7f5d3SJohn Marino 		return ECMD_FAILED;
302*86d7f5d3SJohn Marino 	}
303*86d7f5d3SJohn Marino 
304*86d7f5d3SJohn Marino 	if (arg_count(cmd, name_ARG))
305*86d7f5d3SJohn Marino 		lv_name = arg_value(cmd, name_ARG);
306*86d7f5d3SJohn Marino 	else
307*86d7f5d3SJohn Marino 		lv_name = NULL;
308*86d7f5d3SJohn Marino 
309*86d7f5d3SJohn Marino 	vg_name_from = skip_dev_dir(cmd, argv[0], NULL);
310*86d7f5d3SJohn Marino 	vg_name_to = skip_dev_dir(cmd, argv[1], NULL);
311*86d7f5d3SJohn Marino 	argc -= 2;
312*86d7f5d3SJohn Marino 	argv += 2;
313*86d7f5d3SJohn Marino 
314*86d7f5d3SJohn Marino 	if (!strcmp(vg_name_to, vg_name_from)) {
315*86d7f5d3SJohn Marino 		log_error("Duplicate volume group name \"%s\"", vg_name_from);
316*86d7f5d3SJohn Marino 		return ECMD_FAILED;
317*86d7f5d3SJohn Marino 	}
318*86d7f5d3SJohn Marino 
319*86d7f5d3SJohn Marino 	if (strcmp(vg_name_to, vg_name_from) < 0)
320*86d7f5d3SJohn Marino 		lock_vg_from_first = 0;
321*86d7f5d3SJohn Marino 
322*86d7f5d3SJohn Marino 	if (lock_vg_from_first) {
323*86d7f5d3SJohn Marino 		vg_from = _vgsplit_from(cmd, vg_name_from);
324*86d7f5d3SJohn Marino 		if (!vg_from) {
325*86d7f5d3SJohn Marino 			stack;
326*86d7f5d3SJohn Marino 			return ECMD_FAILED;
327*86d7f5d3SJohn Marino 		}
328*86d7f5d3SJohn Marino 		/*
329*86d7f5d3SJohn Marino 		 * Set metadata format of original VG.
330*86d7f5d3SJohn Marino 		 * NOTE: We must set the format before calling vg_create()
331*86d7f5d3SJohn Marino 		 * since vg_create() calls the per-format constructor.
332*86d7f5d3SJohn Marino 		 */
333*86d7f5d3SJohn Marino 		cmd->fmt = vg_from->fid->fmt;
334*86d7f5d3SJohn Marino 
335*86d7f5d3SJohn Marino 		vg_to = _vgsplit_to(cmd, vg_name_to, &existing_vg);
336*86d7f5d3SJohn Marino 		if (!vg_to) {
337*86d7f5d3SJohn Marino 			unlock_and_release_vg(cmd, vg_from, vg_name_from);
338*86d7f5d3SJohn Marino 			stack;
339*86d7f5d3SJohn Marino 			return ECMD_FAILED;
340*86d7f5d3SJohn Marino 		}
341*86d7f5d3SJohn Marino 	} else {
342*86d7f5d3SJohn Marino 		vg_to = _vgsplit_to(cmd, vg_name_to, &existing_vg);
343*86d7f5d3SJohn Marino 		if (!vg_to) {
344*86d7f5d3SJohn Marino 			stack;
345*86d7f5d3SJohn Marino 			return ECMD_FAILED;
346*86d7f5d3SJohn Marino 		}
347*86d7f5d3SJohn Marino 		vg_from = _vgsplit_from(cmd, vg_name_from);
348*86d7f5d3SJohn Marino 		if (!vg_from) {
349*86d7f5d3SJohn Marino 			unlock_and_release_vg(cmd, vg_to, vg_name_to);
350*86d7f5d3SJohn Marino 			stack;
351*86d7f5d3SJohn Marino 			return ECMD_FAILED;
352*86d7f5d3SJohn Marino 		}
353*86d7f5d3SJohn Marino 
354*86d7f5d3SJohn Marino 		if (cmd->fmt != vg_from->fid->fmt) {
355*86d7f5d3SJohn Marino 			/* In this case we don't know the vg_from->fid->fmt */
356*86d7f5d3SJohn Marino 			log_error("Unable to set new VG metadata type based on "
357*86d7f5d3SJohn Marino 				  "source VG format - use -M option.");
358*86d7f5d3SJohn Marino 			goto bad;
359*86d7f5d3SJohn Marino 		}
360*86d7f5d3SJohn Marino 	}
361*86d7f5d3SJohn Marino 
362*86d7f5d3SJohn Marino 	if (existing_vg) {
363*86d7f5d3SJohn Marino 		if (new_vg_option_specified(cmd)) {
364*86d7f5d3SJohn Marino 			log_error("Volume group \"%s\" exists, but new VG "
365*86d7f5d3SJohn Marino 				    "option specified", vg_name_to);
366*86d7f5d3SJohn Marino 			goto bad;
367*86d7f5d3SJohn Marino 		}
368*86d7f5d3SJohn Marino 		if (!vgs_are_compatible(cmd, vg_from,vg_to))
369*86d7f5d3SJohn Marino 			goto_bad;
370*86d7f5d3SJohn Marino 	} else {
371*86d7f5d3SJohn Marino 		vgcreate_params_set_defaults(&vp_def, vg_from);
372*86d7f5d3SJohn Marino 		vp_def.vg_name = vg_name_to;
373*86d7f5d3SJohn Marino 		if (vgcreate_params_set_from_args(cmd, &vp_new, &vp_def)) {
374*86d7f5d3SJohn Marino 			r = EINVALID_CMD_LINE;
375*86d7f5d3SJohn Marino 			goto_bad;
376*86d7f5d3SJohn Marino 		}
377*86d7f5d3SJohn Marino 
378*86d7f5d3SJohn Marino 		if (vgcreate_params_validate(cmd, &vp_new)) {
379*86d7f5d3SJohn Marino 			r = EINVALID_CMD_LINE;
380*86d7f5d3SJohn Marino 			goto_bad;
381*86d7f5d3SJohn Marino 		}
382*86d7f5d3SJohn Marino 
383*86d7f5d3SJohn Marino 		if (!vg_set_extent_size(vg_to, vp_new.extent_size) ||
384*86d7f5d3SJohn Marino 		    !vg_set_max_lv(vg_to, vp_new.max_lv) ||
385*86d7f5d3SJohn Marino 		    !vg_set_max_pv(vg_to, vp_new.max_pv) ||
386*86d7f5d3SJohn Marino 		    !vg_set_alloc_policy(vg_to, vp_new.alloc) ||
387*86d7f5d3SJohn Marino 		    !vg_set_clustered(vg_to, vp_new.clustered))
388*86d7f5d3SJohn Marino 			goto_bad;
389*86d7f5d3SJohn Marino 	}
390*86d7f5d3SJohn Marino 
391*86d7f5d3SJohn Marino 	/* Archive vg_from before changing it */
392*86d7f5d3SJohn Marino 	if (!archive(vg_from))
393*86d7f5d3SJohn Marino 		goto_bad;
394*86d7f5d3SJohn Marino 
395*86d7f5d3SJohn Marino 	/* Move PVs across to new structure */
396*86d7f5d3SJohn Marino 	for (opt = 0; opt < argc; opt++) {
397*86d7f5d3SJohn Marino 		if (!move_pv(vg_from, vg_to, argv[opt]))
398*86d7f5d3SJohn Marino 			goto_bad;
399*86d7f5d3SJohn Marino 	}
400*86d7f5d3SJohn Marino 
401*86d7f5d3SJohn Marino 	/* If an LV given on the cmdline, move used_by PVs */
402*86d7f5d3SJohn Marino 	if (lv_name && !move_pvs_used_by_lv(vg_from, vg_to, lv_name))
403*86d7f5d3SJohn Marino 		goto_bad;
404*86d7f5d3SJohn Marino 
405*86d7f5d3SJohn Marino 	/* Move required LVs across, checking consistency */
406*86d7f5d3SJohn Marino 	if (!(_move_lvs(vg_from, vg_to)))
407*86d7f5d3SJohn Marino 		goto_bad;
408*86d7f5d3SJohn Marino 
409*86d7f5d3SJohn Marino 	/* FIXME Separate the 'move' from the 'validation' to fix dev stacks */
410*86d7f5d3SJohn Marino 	/* Move required mirrors across */
411*86d7f5d3SJohn Marino 	if (!(_move_mirrors(vg_from, vg_to)))
412*86d7f5d3SJohn Marino 		goto_bad;
413*86d7f5d3SJohn Marino 
414*86d7f5d3SJohn Marino 	/* Move required snapshots across */
415*86d7f5d3SJohn Marino 	if (!(_move_snapshots(vg_from, vg_to)))
416*86d7f5d3SJohn Marino 		goto_bad;
417*86d7f5d3SJohn Marino 
418*86d7f5d3SJohn Marino 	/* Split metadata areas and check if both vgs have at least one area */
419*86d7f5d3SJohn Marino 	if (!(vg_split_mdas(cmd, vg_from, vg_to)) && vg_from->pv_count) {
420*86d7f5d3SJohn Marino 		log_error("Cannot split: Nowhere to store metadata for new Volume Group");
421*86d7f5d3SJohn Marino 		goto bad;
422*86d7f5d3SJohn Marino 	}
423*86d7f5d3SJohn Marino 
424*86d7f5d3SJohn Marino 	/* Set proper name for all PVs in new VG */
425*86d7f5d3SJohn Marino 	if (!vg_rename(cmd, vg_to, vg_name_to))
426*86d7f5d3SJohn Marino 		goto_bad;
427*86d7f5d3SJohn Marino 
428*86d7f5d3SJohn Marino 	/* store it on disks */
429*86d7f5d3SJohn Marino 	log_verbose("Writing out updated volume groups");
430*86d7f5d3SJohn Marino 
431*86d7f5d3SJohn Marino 	/*
432*86d7f5d3SJohn Marino 	 * First, write out the new VG as EXPORTED.  We do this first in case
433*86d7f5d3SJohn Marino 	 * there is a crash - we will still have the new VG information, in an
434*86d7f5d3SJohn Marino 	 * exported state.  Recovery after this point would be removal of the
435*86d7f5d3SJohn Marino 	 * new VG and redoing the vgsplit.
436*86d7f5d3SJohn Marino 	 * FIXME: recover automatically or instruct the user?
437*86d7f5d3SJohn Marino 	 */
438*86d7f5d3SJohn Marino 	vg_to->status |= EXPORTED_VG;
439*86d7f5d3SJohn Marino 
440*86d7f5d3SJohn Marino 	if (!archive(vg_to))
441*86d7f5d3SJohn Marino 		goto_bad;
442*86d7f5d3SJohn Marino 
443*86d7f5d3SJohn Marino 	if (!vg_write(vg_to) || !vg_commit(vg_to))
444*86d7f5d3SJohn Marino 		goto_bad;
445*86d7f5d3SJohn Marino 
446*86d7f5d3SJohn Marino 	backup(vg_to);
447*86d7f5d3SJohn Marino 
448*86d7f5d3SJohn Marino 	/*
449*86d7f5d3SJohn Marino 	 * Next, write out the updated old VG.  If we crash after this point,
450*86d7f5d3SJohn Marino 	 * recovery is a vgimport on the new VG.
451*86d7f5d3SJohn Marino 	 * FIXME: recover automatically or instruct the user?
452*86d7f5d3SJohn Marino 	 */
453*86d7f5d3SJohn Marino 	if (vg_from->pv_count) {
454*86d7f5d3SJohn Marino 		if (!vg_write(vg_from) || !vg_commit(vg_from))
455*86d7f5d3SJohn Marino 			goto_bad;
456*86d7f5d3SJohn Marino 
457*86d7f5d3SJohn Marino 		backup(vg_from);
458*86d7f5d3SJohn Marino 	}
459*86d7f5d3SJohn Marino 
460*86d7f5d3SJohn Marino 	/*
461*86d7f5d3SJohn Marino 	 * Finally, remove the EXPORTED flag from the new VG and write it out.
462*86d7f5d3SJohn Marino 	 */
463*86d7f5d3SJohn Marino 	if (!test_mode()) {
464*86d7f5d3SJohn Marino 		vg_release(vg_to);
465*86d7f5d3SJohn Marino 		vg_to = vg_read_for_update(cmd, vg_name_to, NULL,
466*86d7f5d3SJohn Marino 					   READ_ALLOW_EXPORTED);
467*86d7f5d3SJohn Marino 		if (vg_read_error(vg_to)) {
468*86d7f5d3SJohn Marino 			log_error("Volume group \"%s\" became inconsistent: "
469*86d7f5d3SJohn Marino 				  "please fix manually", vg_name_to);
470*86d7f5d3SJohn Marino 			goto bad;
471*86d7f5d3SJohn Marino 		}
472*86d7f5d3SJohn Marino 	}
473*86d7f5d3SJohn Marino 
474*86d7f5d3SJohn Marino 	vg_to->status &= ~EXPORTED_VG;
475*86d7f5d3SJohn Marino 
476*86d7f5d3SJohn Marino 	if (!vg_write(vg_to) || !vg_commit(vg_to))
477*86d7f5d3SJohn Marino 		goto_bad;
478*86d7f5d3SJohn Marino 
479*86d7f5d3SJohn Marino 	backup(vg_to);
480*86d7f5d3SJohn Marino 
481*86d7f5d3SJohn Marino 	log_print("%s volume group \"%s\" successfully split from \"%s\"",
482*86d7f5d3SJohn Marino 		  existing_vg ? "Existing" : "New",
483*86d7f5d3SJohn Marino 		  vg_to->name, vg_from->name);
484*86d7f5d3SJohn Marino 
485*86d7f5d3SJohn Marino 	r = ECMD_PROCESSED;
486*86d7f5d3SJohn Marino 
487*86d7f5d3SJohn Marino bad:
488*86d7f5d3SJohn Marino 	if (lock_vg_from_first) {
489*86d7f5d3SJohn Marino 		unlock_and_release_vg(cmd, vg_to, vg_name_to);
490*86d7f5d3SJohn Marino 		unlock_and_release_vg(cmd, vg_from, vg_name_from);
491*86d7f5d3SJohn Marino 	} else {
492*86d7f5d3SJohn Marino 		unlock_and_release_vg(cmd, vg_from, vg_name_from);
493*86d7f5d3SJohn Marino 		unlock_and_release_vg(cmd, vg_to, vg_name_to);
494*86d7f5d3SJohn Marino 	}
495*86d7f5d3SJohn Marino 	return r;
496*86d7f5d3SJohn Marino }
497