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