xref: /dflybsd-src/contrib/lvm2/dist/tools/vgmerge.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /*	$NetBSD: vgmerge.c,v 1.1.1.2 2009/12/02 00:25:57 haad Exp $	*/
286d7f5d3SJohn Marino 
386d7f5d3SJohn Marino /*
486d7f5d3SJohn Marino  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
586d7f5d3SJohn Marino  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
686d7f5d3SJohn Marino  *
786d7f5d3SJohn Marino  * This file is part of LVM2.
886d7f5d3SJohn Marino  *
986d7f5d3SJohn Marino  * This copyrighted material is made available to anyone wishing to use,
1086d7f5d3SJohn Marino  * modify, copy, or redistribute it subject to the terms and conditions
1186d7f5d3SJohn Marino  * of the GNU Lesser General Public License v.2.1.
1286d7f5d3SJohn Marino  *
1386d7f5d3SJohn Marino  * You should have received a copy of the GNU Lesser General Public License
1486d7f5d3SJohn Marino  * along with this program; if not, write to the Free Software Foundation,
1586d7f5d3SJohn Marino  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1686d7f5d3SJohn Marino  */
1786d7f5d3SJohn Marino 
1886d7f5d3SJohn Marino #include "tools.h"
1986d7f5d3SJohn Marino 
_vgmerge_vg_read(struct cmd_context * cmd,const char * vg_name)2086d7f5d3SJohn Marino static struct volume_group *_vgmerge_vg_read(struct cmd_context *cmd,
2186d7f5d3SJohn Marino 					     const char *vg_name)
2286d7f5d3SJohn Marino {
2386d7f5d3SJohn Marino 	struct volume_group *vg;
2486d7f5d3SJohn Marino 	log_verbose("Checking for volume group \"%s\"", vg_name);
2586d7f5d3SJohn Marino 	vg = vg_read_for_update(cmd, vg_name, NULL, 0);
2686d7f5d3SJohn Marino 	if (vg_read_error(vg)) {
2786d7f5d3SJohn Marino 		vg_release(vg);
2886d7f5d3SJohn Marino 		return NULL;
2986d7f5d3SJohn Marino 	}
3086d7f5d3SJohn Marino 	return vg;
3186d7f5d3SJohn Marino }
3286d7f5d3SJohn Marino 
_vgmerge_single(struct cmd_context * cmd,const char * vg_name_to,const char * vg_name_from)3386d7f5d3SJohn Marino static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
3486d7f5d3SJohn Marino 			   const char *vg_name_from)
3586d7f5d3SJohn Marino {
3686d7f5d3SJohn Marino 	struct volume_group *vg_to, *vg_from;
3786d7f5d3SJohn Marino 	struct lv_list *lvl1, *lvl2;
3886d7f5d3SJohn Marino 	int r = ECMD_FAILED;
3986d7f5d3SJohn Marino 	int lock_vg_from_first = 0;
4086d7f5d3SJohn Marino 
4186d7f5d3SJohn Marino 	if (!strcmp(vg_name_to, vg_name_from)) {
4286d7f5d3SJohn Marino 		log_error("Duplicate volume group name \"%s\"", vg_name_from);
4386d7f5d3SJohn Marino 		return ECMD_FAILED;
4486d7f5d3SJohn Marino 	}
4586d7f5d3SJohn Marino 
4686d7f5d3SJohn Marino 	if (strcmp(vg_name_to, vg_name_from) > 0)
4786d7f5d3SJohn Marino 		lock_vg_from_first = 1;
4886d7f5d3SJohn Marino 
4986d7f5d3SJohn Marino 	if (lock_vg_from_first) {
5086d7f5d3SJohn Marino 		vg_from = _vgmerge_vg_read(cmd, vg_name_from);
5186d7f5d3SJohn Marino 		if (!vg_from) {
5286d7f5d3SJohn Marino 			stack;
5386d7f5d3SJohn Marino 			return ECMD_FAILED;
5486d7f5d3SJohn Marino 		}
5586d7f5d3SJohn Marino 		vg_to = _vgmerge_vg_read(cmd, vg_name_to);
5686d7f5d3SJohn Marino 		if (!vg_to) {
5786d7f5d3SJohn Marino 			stack;
5886d7f5d3SJohn Marino 			unlock_and_release_vg(cmd, vg_from, vg_name_from);
5986d7f5d3SJohn Marino 			return ECMD_FAILED;
6086d7f5d3SJohn Marino 		}
6186d7f5d3SJohn Marino 	} else {
6286d7f5d3SJohn Marino 		vg_to = _vgmerge_vg_read(cmd, vg_name_to);
6386d7f5d3SJohn Marino 		if (!vg_to) {
6486d7f5d3SJohn Marino 			stack;
6586d7f5d3SJohn Marino 			return ECMD_FAILED;
6686d7f5d3SJohn Marino 		}
6786d7f5d3SJohn Marino 
6886d7f5d3SJohn Marino 		vg_from = _vgmerge_vg_read(cmd, vg_name_from);
6986d7f5d3SJohn Marino 		if (!vg_from) {
7086d7f5d3SJohn Marino 			stack;
7186d7f5d3SJohn Marino 			unlock_and_release_vg(cmd, vg_to, vg_name_to);
7286d7f5d3SJohn Marino 			return ECMD_FAILED;
7386d7f5d3SJohn Marino 		}
7486d7f5d3SJohn Marino 	}
7586d7f5d3SJohn Marino 
7686d7f5d3SJohn Marino 	if (!vgs_are_compatible(cmd, vg_from, vg_to))
7786d7f5d3SJohn Marino 		goto_bad;
7886d7f5d3SJohn Marino 
7986d7f5d3SJohn Marino 	/* FIXME List arg: vg_show_with_pv_and_lv(vg_to); */
8086d7f5d3SJohn Marino 
8186d7f5d3SJohn Marino 	if (!archive(vg_from) || !archive(vg_to))
8286d7f5d3SJohn Marino 		goto_bad;
8386d7f5d3SJohn Marino 
8486d7f5d3SJohn Marino 	drop_cached_metadata(vg_from);
8586d7f5d3SJohn Marino 
8686d7f5d3SJohn Marino 	/* Merge volume groups */
8786d7f5d3SJohn Marino 	while (!dm_list_empty(&vg_from->pvs)) {
8886d7f5d3SJohn Marino 		struct dm_list *pvh = vg_from->pvs.n;
8986d7f5d3SJohn Marino 		struct physical_volume *pv;
9086d7f5d3SJohn Marino 
9186d7f5d3SJohn Marino 		dm_list_move(&vg_to->pvs, pvh);
9286d7f5d3SJohn Marino 
9386d7f5d3SJohn Marino 		pv = dm_list_item(pvh, struct pv_list)->pv;
9486d7f5d3SJohn Marino 		pv->vg_name = dm_pool_strdup(cmd->mem, vg_to->name);
9586d7f5d3SJohn Marino 	}
9686d7f5d3SJohn Marino 	vg_to->pv_count += vg_from->pv_count;
9786d7f5d3SJohn Marino 
9886d7f5d3SJohn Marino 	/* Fix up LVIDs */
9986d7f5d3SJohn Marino 	dm_list_iterate_items(lvl1, &vg_to->lvs) {
10086d7f5d3SJohn Marino 		union lvid *lvid1 = &lvl1->lv->lvid;
10186d7f5d3SJohn Marino 		char uuid[64] __attribute((aligned(8)));
10286d7f5d3SJohn Marino 
10386d7f5d3SJohn Marino 		dm_list_iterate_items(lvl2, &vg_from->lvs) {
10486d7f5d3SJohn Marino 			union lvid *lvid2 = &lvl2->lv->lvid;
10586d7f5d3SJohn Marino 
10686d7f5d3SJohn Marino 			if (id_equal(&lvid1->id[1], &lvid2->id[1])) {
10786d7f5d3SJohn Marino 				if (!id_create(&lvid2->id[1])) {
10886d7f5d3SJohn Marino 					log_error("Failed to generate new "
10986d7f5d3SJohn Marino 						  "random LVID for %s",
11086d7f5d3SJohn Marino 						  lvl2->lv->name);
11186d7f5d3SJohn Marino 					goto bad;
11286d7f5d3SJohn Marino 				}
11386d7f5d3SJohn Marino 				if (!id_write_format(&lvid2->id[1], uuid,
11486d7f5d3SJohn Marino 						     sizeof(uuid)))
11586d7f5d3SJohn Marino 					goto_bad;
11686d7f5d3SJohn Marino 
11786d7f5d3SJohn Marino 				log_verbose("Changed LVID for %s to %s",
11886d7f5d3SJohn Marino 					    lvl2->lv->name, uuid);
11986d7f5d3SJohn Marino 			}
12086d7f5d3SJohn Marino 		}
12186d7f5d3SJohn Marino 	}
12286d7f5d3SJohn Marino 
12386d7f5d3SJohn Marino 	while (!dm_list_empty(&vg_from->lvs)) {
12486d7f5d3SJohn Marino 		struct dm_list *lvh = vg_from->lvs.n;
12586d7f5d3SJohn Marino 
12686d7f5d3SJohn Marino 		dm_list_move(&vg_to->lvs, lvh);
12786d7f5d3SJohn Marino 	}
12886d7f5d3SJohn Marino 
12986d7f5d3SJohn Marino 	while (!dm_list_empty(&vg_from->fid->metadata_areas)) {
13086d7f5d3SJohn Marino 		struct dm_list *mdah = vg_from->fid->metadata_areas.n;
13186d7f5d3SJohn Marino 
13286d7f5d3SJohn Marino 		dm_list_move(&vg_to->fid->metadata_areas, mdah);
13386d7f5d3SJohn Marino 	}
13486d7f5d3SJohn Marino 
13586d7f5d3SJohn Marino 	vg_to->extent_count += vg_from->extent_count;
13686d7f5d3SJohn Marino 	vg_to->free_count += vg_from->free_count;
13786d7f5d3SJohn Marino 
13886d7f5d3SJohn Marino 	/* store it on disks */
13986d7f5d3SJohn Marino 	log_verbose("Writing out updated volume group");
14086d7f5d3SJohn Marino 	if (!vg_write(vg_to) || !vg_commit(vg_to))
14186d7f5d3SJohn Marino 		goto_bad;
14286d7f5d3SJohn Marino 
14386d7f5d3SJohn Marino 	/* FIXME Remove /dev/vgfrom */
14486d7f5d3SJohn Marino 
14586d7f5d3SJohn Marino 	backup(vg_to);
14686d7f5d3SJohn Marino 	log_print("Volume group \"%s\" successfully merged into \"%s\"",
14786d7f5d3SJohn Marino 		  vg_from->name, vg_to->name);
14886d7f5d3SJohn Marino 	r = ECMD_PROCESSED;
14986d7f5d3SJohn Marino bad:
15086d7f5d3SJohn Marino 	if (lock_vg_from_first) {
15186d7f5d3SJohn Marino 		unlock_and_release_vg(cmd, vg_to, vg_name_to);
15286d7f5d3SJohn Marino 		unlock_and_release_vg(cmd, vg_from, vg_name_from);
15386d7f5d3SJohn Marino 	} else {
15486d7f5d3SJohn Marino 		unlock_and_release_vg(cmd, vg_from, vg_name_from);
15586d7f5d3SJohn Marino 		unlock_and_release_vg(cmd, vg_to, vg_name_to);
15686d7f5d3SJohn Marino 	}
15786d7f5d3SJohn Marino 	return r;
15886d7f5d3SJohn Marino }
15986d7f5d3SJohn Marino 
vgmerge(struct cmd_context * cmd,int argc,char ** argv)16086d7f5d3SJohn Marino int vgmerge(struct cmd_context *cmd, int argc, char **argv)
16186d7f5d3SJohn Marino {
16286d7f5d3SJohn Marino 	char *vg_name_to, *vg_name_from;
16386d7f5d3SJohn Marino 	int opt = 0;
16486d7f5d3SJohn Marino 	int ret = 0, ret_max = 0;
16586d7f5d3SJohn Marino 
16686d7f5d3SJohn Marino 	if (argc < 2) {
16786d7f5d3SJohn Marino 		log_error("Please enter 2 or more volume groups to merge");
16886d7f5d3SJohn Marino 		return EINVALID_CMD_LINE;
16986d7f5d3SJohn Marino 	}
17086d7f5d3SJohn Marino 
17186d7f5d3SJohn Marino 	vg_name_to = skip_dev_dir(cmd, argv[0], NULL);
17286d7f5d3SJohn Marino 	argc--;
17386d7f5d3SJohn Marino 	argv++;
17486d7f5d3SJohn Marino 
17586d7f5d3SJohn Marino 	for (; opt < argc; opt++) {
17686d7f5d3SJohn Marino 		vg_name_from = skip_dev_dir(cmd, argv[opt], NULL);
17786d7f5d3SJohn Marino 
17886d7f5d3SJohn Marino 		ret = _vgmerge_single(cmd, vg_name_to, vg_name_from);
17986d7f5d3SJohn Marino 		if (ret > ret_max)
18086d7f5d3SJohn Marino 			ret_max = ret;
18186d7f5d3SJohn Marino 	}
18286d7f5d3SJohn Marino 
18386d7f5d3SJohn Marino 	return ret_max;
18486d7f5d3SJohn Marino }
185