xref: /dragonfly/contrib/lvm2/dist/tools/vgmerge.c (revision 0ca59c34)
1 /*	$NetBSD: vgmerge.c,v 1.1.1.2 2009/12/02 00:25:57 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 static struct volume_group *_vgmerge_vg_read(struct cmd_context *cmd,
21 					     const char *vg_name)
22 {
23 	struct volume_group *vg;
24 	log_verbose("Checking for volume group \"%s\"", vg_name);
25 	vg = vg_read_for_update(cmd, vg_name, NULL, 0);
26 	if (vg_read_error(vg)) {
27 		vg_release(vg);
28 		return NULL;
29 	}
30 	return vg;
31 }
32 
33 static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
34 			   const char *vg_name_from)
35 {
36 	struct volume_group *vg_to, *vg_from;
37 	struct lv_list *lvl1, *lvl2;
38 	int r = ECMD_FAILED;
39 	int lock_vg_from_first = 0;
40 
41 	if (!strcmp(vg_name_to, vg_name_from)) {
42 		log_error("Duplicate volume group name \"%s\"", vg_name_from);
43 		return ECMD_FAILED;
44 	}
45 
46 	if (strcmp(vg_name_to, vg_name_from) > 0)
47 		lock_vg_from_first = 1;
48 
49 	if (lock_vg_from_first) {
50 		vg_from = _vgmerge_vg_read(cmd, vg_name_from);
51 		if (!vg_from) {
52 			stack;
53 			return ECMD_FAILED;
54 		}
55 		vg_to = _vgmerge_vg_read(cmd, vg_name_to);
56 		if (!vg_to) {
57 			stack;
58 			unlock_and_release_vg(cmd, vg_from, vg_name_from);
59 			return ECMD_FAILED;
60 		}
61 	} else {
62 		vg_to = _vgmerge_vg_read(cmd, vg_name_to);
63 		if (!vg_to) {
64 			stack;
65 			return ECMD_FAILED;
66 		}
67 
68 		vg_from = _vgmerge_vg_read(cmd, vg_name_from);
69 		if (!vg_from) {
70 			stack;
71 			unlock_and_release_vg(cmd, vg_to, vg_name_to);
72 			return ECMD_FAILED;
73 		}
74 	}
75 
76 	if (!vgs_are_compatible(cmd, vg_from, vg_to))
77 		goto_bad;
78 
79 	/* FIXME List arg: vg_show_with_pv_and_lv(vg_to); */
80 
81 	if (!archive(vg_from) || !archive(vg_to))
82 		goto_bad;
83 
84 	drop_cached_metadata(vg_from);
85 
86 	/* Merge volume groups */
87 	while (!dm_list_empty(&vg_from->pvs)) {
88 		struct dm_list *pvh = vg_from->pvs.n;
89 		struct physical_volume *pv;
90 
91 		dm_list_move(&vg_to->pvs, pvh);
92 
93 		pv = dm_list_item(pvh, struct pv_list)->pv;
94 		pv->vg_name = dm_pool_strdup(cmd->mem, vg_to->name);
95 	}
96 	vg_to->pv_count += vg_from->pv_count;
97 
98 	/* Fix up LVIDs */
99 	dm_list_iterate_items(lvl1, &vg_to->lvs) {
100 		union lvid *lvid1 = &lvl1->lv->lvid;
101 		char uuid[64] __attribute((aligned(8)));
102 
103 		dm_list_iterate_items(lvl2, &vg_from->lvs) {
104 			union lvid *lvid2 = &lvl2->lv->lvid;
105 
106 			if (id_equal(&lvid1->id[1], &lvid2->id[1])) {
107 				if (!id_create(&lvid2->id[1])) {
108 					log_error("Failed to generate new "
109 						  "random LVID for %s",
110 						  lvl2->lv->name);
111 					goto bad;
112 				}
113 				if (!id_write_format(&lvid2->id[1], uuid,
114 						     sizeof(uuid)))
115 					goto_bad;
116 
117 				log_verbose("Changed LVID for %s to %s",
118 					    lvl2->lv->name, uuid);
119 			}
120 		}
121 	}
122 
123 	while (!dm_list_empty(&vg_from->lvs)) {
124 		struct dm_list *lvh = vg_from->lvs.n;
125 
126 		dm_list_move(&vg_to->lvs, lvh);
127 	}
128 
129 	while (!dm_list_empty(&vg_from->fid->metadata_areas)) {
130 		struct dm_list *mdah = vg_from->fid->metadata_areas.n;
131 
132 		dm_list_move(&vg_to->fid->metadata_areas, mdah);
133 	}
134 
135 	vg_to->extent_count += vg_from->extent_count;
136 	vg_to->free_count += vg_from->free_count;
137 
138 	/* store it on disks */
139 	log_verbose("Writing out updated volume group");
140 	if (!vg_write(vg_to) || !vg_commit(vg_to))
141 		goto_bad;
142 
143 	/* FIXME Remove /dev/vgfrom */
144 
145 	backup(vg_to);
146 	log_print("Volume group \"%s\" successfully merged into \"%s\"",
147 		  vg_from->name, vg_to->name);
148 	r = ECMD_PROCESSED;
149 bad:
150 	if (lock_vg_from_first) {
151 		unlock_and_release_vg(cmd, vg_to, vg_name_to);
152 		unlock_and_release_vg(cmd, vg_from, vg_name_from);
153 	} else {
154 		unlock_and_release_vg(cmd, vg_from, vg_name_from);
155 		unlock_and_release_vg(cmd, vg_to, vg_name_to);
156 	}
157 	return r;
158 }
159 
160 int vgmerge(struct cmd_context *cmd, int argc, char **argv)
161 {
162 	char *vg_name_to, *vg_name_from;
163 	int opt = 0;
164 	int ret = 0, ret_max = 0;
165 
166 	if (argc < 2) {
167 		log_error("Please enter 2 or more volume groups to merge");
168 		return EINVALID_CMD_LINE;
169 	}
170 
171 	vg_name_to = skip_dev_dir(cmd, argv[0], NULL);
172 	argc--;
173 	argv++;
174 
175 	for (; opt < argc; opt++) {
176 		vg_name_from = skip_dev_dir(cmd, argv[opt], NULL);
177 
178 		ret = _vgmerge_single(cmd, vg_name_to, vg_name_from);
179 		if (ret > ret_max)
180 			ret_max = ret;
181 	}
182 
183 	return ret_max;
184 }
185