xref: /netbsd-src/external/gpl2/lvm2/dist/tools/vgmerge.c (revision 10ad5ffa714ce1a679dcc9dd8159648df2d67b5a)
1 /*	$NetBSD: vgmerge.c,v 1.1.1.1 2008/12/22 00:19:09 haad Exp $	*/
2 
3 /*
4  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5  * Copyright (C) 2004-2007 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 static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
21 			   const char *vg_name_from)
22 {
23 	struct volume_group *vg_to, *vg_from;
24 	struct lv_list *lvl1, *lvl2;
25 
26 	if (!strcmp(vg_name_to, vg_name_from)) {
27 		log_error("Duplicate volume group name \"%s\"", vg_name_from);
28 		return ECMD_FAILED;
29 	}
30 
31 	log_verbose("Checking for volume group \"%s\"", vg_name_to);
32 	if (!(vg_to = vg_lock_and_read(cmd, vg_name_to, NULL, LCK_VG_WRITE,
33 				       CLUSTERED | EXPORTED_VG | LVM_WRITE,
34 				       CORRECT_INCONSISTENT | FAIL_INCONSISTENT)))
35 		 return ECMD_FAILED;
36 
37 	log_verbose("Checking for volume group \"%s\"", vg_name_from);
38 	if (!(vg_from = vg_lock_and_read(cmd, vg_name_from, NULL,
39 					 LCK_VG_WRITE | LCK_NONBLOCK,
40 					 CLUSTERED | EXPORTED_VG | LVM_WRITE,
41 					 CORRECT_INCONSISTENT | FAIL_INCONSISTENT))) {
42 		unlock_vg(cmd, vg_name_to);
43 		return ECMD_FAILED;
44 	}
45 
46 	if (!vgs_are_compatible(cmd, vg_from, vg_to))
47 		goto_bad;
48 
49 	/* FIXME List arg: vg_show_with_pv_and_lv(vg_to); */
50 
51 	if (!archive(vg_from) || !archive(vg_to))
52 		goto_bad;
53 
54 	drop_cached_metadata(vg_from);
55 
56 	/* Merge volume groups */
57 	while (!dm_list_empty(&vg_from->pvs)) {
58 		struct dm_list *pvh = vg_from->pvs.n;
59 		struct physical_volume *pv;
60 
61 		dm_list_move(&vg_to->pvs, pvh);
62 
63 		pv = dm_list_item(pvh, struct pv_list)->pv;
64 		pv->vg_name = dm_pool_strdup(cmd->mem, vg_to->name);
65 	}
66 	vg_to->pv_count += vg_from->pv_count;
67 
68 	/* Fix up LVIDs */
69 	dm_list_iterate_items(lvl1, &vg_to->lvs) {
70 		union lvid *lvid1 = &lvl1->lv->lvid;
71 		char uuid[64] __attribute((aligned(8)));
72 
73 		dm_list_iterate_items(lvl2, &vg_from->lvs) {
74 			union lvid *lvid2 = &lvl2->lv->lvid;
75 
76 			if (id_equal(&lvid1->id[1], &lvid2->id[1])) {
77 				if (!id_create(&lvid2->id[1])) {
78 					log_error("Failed to generate new "
79 						  "random LVID for %s",
80 						  lvl2->lv->name);
81 					goto bad;
82 				}
83 				if (!id_write_format(&lvid2->id[1], uuid,
84 						     sizeof(uuid)))
85 					goto_bad;
86 
87 				log_verbose("Changed LVID for %s to %s",
88 					    lvl2->lv->name, uuid);
89 			}
90 		}
91 	}
92 
93 	while (!dm_list_empty(&vg_from->lvs)) {
94 		struct dm_list *lvh = vg_from->lvs.n;
95 
96 		dm_list_move(&vg_to->lvs, lvh);
97 	}
98 
99 	while (!dm_list_empty(&vg_from->fid->metadata_areas)) {
100 		struct dm_list *mdah = vg_from->fid->metadata_areas.n;
101 
102 		dm_list_move(&vg_to->fid->metadata_areas, mdah);
103 	}
104 
105 	vg_to->lv_count += vg_from->lv_count;
106 	vg_to->snapshot_count += vg_from->snapshot_count;
107 
108 	vg_to->extent_count += vg_from->extent_count;
109 	vg_to->free_count += vg_from->free_count;
110 
111 	/* store it on disks */
112 	log_verbose("Writing out updated volume group");
113 	if (!vg_write(vg_to) || !vg_commit(vg_to))
114 		goto_bad;
115 
116 	/* FIXME Remove /dev/vgfrom */
117 
118 	backup(vg_to);
119 
120 	unlock_vg(cmd, vg_name_from);
121 	unlock_vg(cmd, vg_name_to);
122 
123 	log_print("Volume group \"%s\" successfully merged into \"%s\"",
124 		  vg_from->name, vg_to->name);
125 	return ECMD_PROCESSED;
126 
127       bad:
128 	unlock_vg(cmd, vg_name_from);
129 	unlock_vg(cmd, vg_name_to);
130 	return ECMD_FAILED;
131 }
132 
133 int vgmerge(struct cmd_context *cmd, int argc, char **argv)
134 {
135 	char *vg_name_to, *vg_name_from;
136 	int opt = 0;
137 	int ret = 0, ret_max = 0;
138 
139 	if (argc < 2) {
140 		log_error("Please enter 2 or more volume groups to merge");
141 		return EINVALID_CMD_LINE;
142 	}
143 
144 	vg_name_to = skip_dev_dir(cmd, argv[0], NULL);
145 	argc--;
146 	argv++;
147 
148 	for (; opt < argc; opt++) {
149 		vg_name_from = skip_dev_dir(cmd, argv[opt], NULL);
150 
151 		ret = _vgmerge_single(cmd, vg_name_to, vg_name_from);
152 		if (ret > ret_max)
153 			ret_max = ret;
154 	}
155 
156 	return ret_max;
157 }
158