Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 : : * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
4 : : *
5 : : * This file is part of LVM2.
6 : : *
7 : : * This copyrighted material is made available to anyone wishing to use,
8 : : * modify, copy, or redistribute it subject to the terms and conditions
9 : : * of the GNU Lesser General Public License v.2.1.
10 : : *
11 : : * You should have received a copy of the GNU Lesser General Public License
12 : : * along with this program; if not, write to the Free Software Foundation,
13 : : * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 : : */
15 : :
16 : : #include "tools.h"
17 : :
18 : 0 : static struct volume_group *_vgmerge_vg_read(struct cmd_context *cmd,
19 : : const char *vg_name)
20 : : {
21 : : struct volume_group *vg;
22 : 0 : log_verbose("Checking for volume group \"%s\"", vg_name);
23 : 0 : vg = vg_read_for_update(cmd, vg_name, NULL, 0);
24 [ # # ]: 0 : if (vg_read_error(vg)) {
25 : 0 : vg_release(vg);
26 : 0 : return NULL;
27 : : }
28 : 0 : return vg;
29 : : }
30 : :
31 : 0 : static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
32 : : const char *vg_name_from)
33 : : {
34 : : struct volume_group *vg_to, *vg_from;
35 : : struct lv_list *lvl1, *lvl2;
36 : 0 : int r = ECMD_FAILED;
37 : 0 : int lock_vg_from_first = 0;
38 : :
39 [ # # ]: 0 : if (!strcmp(vg_name_to, vg_name_from)) {
40 : 0 : log_error("Duplicate volume group name \"%s\"", vg_name_from);
41 : 0 : return ECMD_FAILED;
42 : : }
43 : :
44 [ # # ]: 0 : if (strcmp(vg_name_to, vg_name_from) > 0)
45 : 0 : lock_vg_from_first = 1;
46 : :
47 [ # # ]: 0 : if (lock_vg_from_first) {
48 : 0 : vg_from = _vgmerge_vg_read(cmd, vg_name_from);
49 [ # # ]: 0 : if (!vg_from) {
50 : 0 : stack;
51 : 0 : return ECMD_FAILED;
52 : : }
53 : 0 : vg_to = _vgmerge_vg_read(cmd, vg_name_to);
54 [ # # ]: 0 : if (!vg_to) {
55 : 0 : stack;
56 : 0 : unlock_and_release_vg(cmd, vg_from, vg_name_from);
57 : 0 : return ECMD_FAILED;
58 : : }
59 : : } else {
60 : 0 : vg_to = _vgmerge_vg_read(cmd, vg_name_to);
61 [ # # ]: 0 : if (!vg_to) {
62 : 0 : stack;
63 : 0 : return ECMD_FAILED;
64 : : }
65 : :
66 : 0 : vg_from = _vgmerge_vg_read(cmd, vg_name_from);
67 [ # # ]: 0 : if (!vg_from) {
68 : 0 : stack;
69 : 0 : unlock_and_release_vg(cmd, vg_to, vg_name_to);
70 : 0 : return ECMD_FAILED;
71 : : }
72 : : }
73 : :
74 [ # # ]: 0 : if (!vgs_are_compatible(cmd, vg_from, vg_to))
75 : 0 : goto_bad;
76 : :
77 : : /* FIXME List arg: vg_show_with_pv_and_lv(vg_to); */
78 : :
79 [ # # ][ # # ]: 0 : if (!archive(vg_from) || !archive(vg_to))
80 : 0 : goto_bad;
81 : :
82 : 0 : drop_cached_metadata(vg_from);
83 : :
84 : : /* Merge volume groups */
85 [ # # ]: 0 : while (!dm_list_empty(&vg_from->pvs)) {
86 : 0 : struct dm_list *pvh = vg_from->pvs.n;
87 : : struct physical_volume *pv;
88 : :
89 : 0 : dm_list_move(&vg_to->pvs, pvh);
90 : :
91 : 0 : pv = dm_list_item(pvh, struct pv_list)->pv;
92 : 0 : pv->vg_name = dm_pool_strdup(cmd->mem, vg_to->name);
93 : : }
94 : 0 : vg_to->pv_count += vg_from->pv_count;
95 : :
96 : : /* Fix up LVIDs */
97 [ # # ]: 0 : dm_list_iterate_items(lvl1, &vg_to->lvs) {
98 : 0 : union lvid *lvid1 = &lvl1->lv->lvid;
99 : : char uuid[64] __attribute((aligned(8)));
100 : :
101 [ # # ]: 0 : dm_list_iterate_items(lvl2, &vg_from->lvs) {
102 : 0 : union lvid *lvid2 = &lvl2->lv->lvid;
103 : :
104 [ # # ]: 0 : if (id_equal(&lvid1->id[1], &lvid2->id[1])) {
105 [ # # ]: 0 : if (!id_create(&lvid2->id[1])) {
106 : 0 : log_error("Failed to generate new "
107 : : "random LVID for %s",
108 : : lvl2->lv->name);
109 : 0 : goto bad;
110 : : }
111 [ # # ]: 0 : if (!id_write_format(&lvid2->id[1], uuid,
112 : : sizeof(uuid)))
113 : 0 : goto_bad;
114 : :
115 : 0 : log_verbose("Changed LVID for %s to %s",
116 : : lvl2->lv->name, uuid);
117 : : }
118 : : }
119 : : }
120 : :
121 [ # # ]: 0 : while (!dm_list_empty(&vg_from->lvs)) {
122 : 0 : struct dm_list *lvh = vg_from->lvs.n;
123 : :
124 : 0 : dm_list_move(&vg_to->lvs, lvh);
125 : : }
126 : :
127 [ # # ]: 0 : while (!dm_list_empty(&vg_from->fid->metadata_areas)) {
128 : 0 : struct dm_list *mdah = vg_from->fid->metadata_areas.n;
129 : :
130 : 0 : dm_list_move(&vg_to->fid->metadata_areas, mdah);
131 : : }
132 : :
133 : 0 : vg_to->extent_count += vg_from->extent_count;
134 : 0 : vg_to->free_count += vg_from->free_count;
135 : :
136 : : /* store it on disks */
137 : 0 : log_verbose("Writing out updated volume group");
138 [ # # # # ]: 0 : if (!vg_write(vg_to) || !vg_commit(vg_to))
139 : 0 : goto_bad;
140 : :
141 : : /* FIXME Remove /dev/vgfrom */
142 : :
143 : 0 : backup(vg_to);
144 : 0 : log_print("Volume group \"%s\" successfully merged into \"%s\"",
145 : : vg_from->name, vg_to->name);
146 : 0 : r = ECMD_PROCESSED;
147 : : bad:
148 [ # # ]: 0 : if (lock_vg_from_first) {
149 : 0 : unlock_and_release_vg(cmd, vg_to, vg_name_to);
150 : 0 : unlock_and_release_vg(cmd, vg_from, vg_name_from);
151 : : } else {
152 : 0 : unlock_and_release_vg(cmd, vg_from, vg_name_from);
153 : 0 : unlock_and_release_vg(cmd, vg_to, vg_name_to);
154 : : }
155 : 0 : return r;
156 : : }
157 : :
158 : 0 : int vgmerge(struct cmd_context *cmd, int argc, char **argv)
159 : : {
160 : : char *vg_name_to, *vg_name_from;
161 : 0 : int opt = 0;
162 : 0 : int ret = 0, ret_max = 0;
163 : :
164 [ # # ]: 0 : if (argc < 2) {
165 : 0 : log_error("Please enter 2 or more volume groups to merge");
166 : 0 : return EINVALID_CMD_LINE;
167 : : }
168 : :
169 : 0 : vg_name_to = skip_dev_dir(cmd, argv[0], NULL);
170 : 0 : argc--;
171 : 0 : argv++;
172 : :
173 [ # # ]: 0 : for (; opt < argc; opt++) {
174 : 0 : vg_name_from = skip_dev_dir(cmd, argv[opt], NULL);
175 : :
176 : 0 : ret = _vgmerge_single(cmd, vg_name_to, vg_name_from);
177 [ # # ]: 0 : if (ret > ret_max)
178 : 0 : ret_max = ret;
179 : : }
180 : :
181 : 0 : return ret_max;
182 : : }
|