vgmerge.c revision 1.1 1 /* $NetBSD: vgmerge.c,v 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