]>
Commit | Line | Data |
---|---|---|
da4e57f2 | 1 | /* |
67cdbd7e | 2 | * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. |
5a820745 | 3 | * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved. |
da4e57f2 | 4 | * |
6606c3ae | 5 | * This file is part of LVM2. |
da4e57f2 | 6 | * |
6606c3ae AK |
7 | * This copyrighted material is made available to anyone wishing to use, |
8 | * modify, copy, or redistribute it subject to the terms and conditions | |
be684599 | 9 | * of the GNU Lesser General Public License v.2.1. |
da4e57f2 | 10 | * |
be684599 | 11 | * You should have received a copy of the GNU Lesser General Public License |
6606c3ae AK |
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 | |
da4e57f2 AK |
14 | */ |
15 | ||
16 | #include "tools.h" | |
17 | ||
7c86e390 DW |
18 | static struct volume_group *_vgmerge_vg_read(struct cmd_context *cmd, |
19 | const char *vg_name) | |
af9ded78 | 20 | { |
7c86e390 DW |
21 | struct volume_group *vg; |
22 | log_verbose("Checking for volume group \"%s\"", vg_name); | |
23 | vg = vg_read_for_update(cmd, vg_name, NULL, 0); | |
24 | if (vg_read_error(vg)) { | |
077a6755 | 25 | release_vg(vg); |
af9ded78 DW |
26 | return NULL; |
27 | } | |
7c86e390 | 28 | return vg; |
af9ded78 DW |
29 | } |
30 | ||
8ef2b021 AK |
31 | static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to, |
32 | const char *vg_name_from) | |
da4e57f2 | 33 | { |
0adfbfd5 | 34 | struct pv_list *pvl, *tpvl; |
da4e57f2 | 35 | struct volume_group *vg_to, *vg_from; |
f2b7349e | 36 | struct lv_list *lvl1, *lvl2; |
043b1362 | 37 | int r = ECMD_FAILED; |
115bc65b | 38 | int lock_vg_from_first = 0; |
da4e57f2 AK |
39 | |
40 | if (!strcmp(vg_name_to, vg_name_from)) { | |
08907484 | 41 | log_error("Duplicate volume group name \"%s\"", vg_name_from); |
da4e57f2 AK |
42 | return ECMD_FAILED; |
43 | } | |
44 | ||
3d9c2d86 DW |
45 | if (strcmp(vg_name_to, vg_name_from) > 0) |
46 | lock_vg_from_first = 1; | |
f53c6aa6 | 47 | |
3d9c2d86 DW |
48 | if (lock_vg_from_first) { |
49 | vg_from = _vgmerge_vg_read(cmd, vg_name_from); | |
651ff9b3 AK |
50 | if (!vg_from) { |
51 | stack; | |
3d9c2d86 | 52 | return ECMD_FAILED; |
651ff9b3 | 53 | } |
3d9c2d86 DW |
54 | vg_to = _vgmerge_vg_read(cmd, vg_name_to); |
55 | if (!vg_to) { | |
651ff9b3 | 56 | stack; |
077a6755 | 57 | unlock_and_release_vg(cmd, vg_from, vg_name_from); |
3d9c2d86 DW |
58 | return ECMD_FAILED; |
59 | } | |
60 | } else { | |
61 | vg_to = _vgmerge_vg_read(cmd, vg_name_to); | |
651ff9b3 AK |
62 | if (!vg_to) { |
63 | stack; | |
3d9c2d86 | 64 | return ECMD_FAILED; |
651ff9b3 | 65 | } |
3d9c2d86 DW |
66 | |
67 | vg_from = _vgmerge_vg_read(cmd, vg_name_from); | |
68 | if (!vg_from) { | |
651ff9b3 | 69 | stack; |
077a6755 | 70 | unlock_and_release_vg(cmd, vg_to, vg_name_to); |
3d9c2d86 DW |
71 | return ECMD_FAILED; |
72 | } | |
7d0e6e80 AK |
73 | } |
74 | ||
d865615e | 75 | if (!vgs_are_compatible(cmd, vg_from, vg_to)) |
c51b9fff | 76 | goto_bad; |
352a99b9 | 77 | |
da4e57f2 AK |
78 | /* FIXME List arg: vg_show_with_pv_and_lv(vg_to); */ |
79 | ||
614a4508 | 80 | if (!archive(vg_from) || !archive(vg_to)) |
c51b9fff | 81 | goto_bad; |
614a4508 | 82 | |
de369215 ZK |
83 | if (!drop_cached_metadata(vg_from)) |
84 | stack; | |
aa769723 | 85 | |
da4e57f2 | 86 | /* Merge volume groups */ |
0adfbfd5 DW |
87 | dm_list_iterate_items_safe(pvl, tpvl, &vg_from->pvs) { |
88 | del_pvl_from_vgs(vg_from, pvl); | |
89 | add_pvl_to_vgs(vg_to, pvl); | |
90 | pvl->pv->vg_name = dm_pool_strdup(cmd->mem, vg_to->name); | |
da4e57f2 | 91 | } |
da4e57f2 | 92 | |
21ca3b12 | 93 | /* Fix up LVIDs */ |
2c44337b | 94 | dm_list_iterate_items(lvl1, &vg_to->lvs) { |
21ca3b12 | 95 | union lvid *lvid1 = &lvl1->lv->lvid; |
08f1ddea | 96 | char uuid[64] __attribute__((aligned(8))); |
21ca3b12 | 97 | |
2c44337b | 98 | dm_list_iterate_items(lvl2, &vg_from->lvs) { |
21ca3b12 AK |
99 | union lvid *lvid2 = &lvl2->lv->lvid; |
100 | ||
67cdbd7e | 101 | if (id_equal(&lvid1->id[1], &lvid2->id[1])) { |
21ca3b12 AK |
102 | if (!id_create(&lvid2->id[1])) { |
103 | log_error("Failed to generate new " | |
104 | "random LVID for %s", | |
105 | lvl2->lv->name); | |
c51b9fff | 106 | goto bad; |
21ca3b12 | 107 | } |
67cdbd7e | 108 | if (!id_write_format(&lvid2->id[1], uuid, |
c51b9fff | 109 | sizeof(uuid))) |
67cdbd7e | 110 | goto_bad; |
21ca3b12 AK |
111 | |
112 | log_verbose("Changed LVID for %s to %s", | |
113 | lvl2->lv->name, uuid); | |
114 | } | |
115 | } | |
116 | } | |
67cdbd7e | 117 | |
ebfe96ca PR |
118 | dm_list_iterate_items(lvl1, &vg_from->lvs) { |
119 | lvl1->lv->vg = vg_to; | |
120 | } | |
121 | ||
2c44337b AK |
122 | while (!dm_list_empty(&vg_from->lvs)) { |
123 | struct dm_list *lvh = vg_from->lvs.n; | |
579944d3 | 124 | |
2c44337b | 125 | dm_list_move(&vg_to->lvs, lvh); |
da4e57f2 | 126 | } |
5a52dca9 | 127 | |
f55a20eb DW |
128 | while (!dm_list_empty(&vg_from->fid->metadata_areas_in_use)) { |
129 | struct dm_list *mdah = vg_from->fid->metadata_areas_in_use.n; | |
5a52dca9 | 130 | |
f55a20eb | 131 | dm_list_move(&vg_to->fid->metadata_areas_in_use, mdah); |
5a52dca9 AK |
132 | } |
133 | ||
c6c031e4 DW |
134 | while (!dm_list_empty(&vg_from->fid->metadata_areas_ignored)) { |
135 | struct dm_list *mdah = vg_from->fid->metadata_areas_ignored.n; | |
136 | ||
137 | dm_list_move(&vg_to->fid->metadata_areas_ignored, mdah); | |
138 | } | |
139 | ||
da4e57f2 AK |
140 | vg_to->extent_count += vg_from->extent_count; |
141 | vg_to->free_count += vg_from->free_count; | |
142 | ||
143 | /* store it on disks */ | |
144 | log_verbose("Writing out updated volume group"); | |
c51b9fff AK |
145 | if (!vg_write(vg_to) || !vg_commit(vg_to)) |
146 | goto_bad; | |
da4e57f2 AK |
147 | |
148 | /* FIXME Remove /dev/vgfrom */ | |
149 | ||
197c3f2a | 150 | backup(vg_to); |
08907484 | 151 | log_print("Volume group \"%s\" successfully merged into \"%s\"", |
da4e57f2 | 152 | vg_from->name, vg_to->name); |
043b1362 MB |
153 | r = ECMD_PROCESSED; |
154 | bad: | |
91d865ca ZK |
155 | /* |
156 | * Note: as vg_to is referencing moved elements from vg_from | |
077a6755 | 157 | * the order of release_vg calls is mandatory. |
91d865ca | 158 | */ |
077a6755 ZK |
159 | unlock_and_release_vg(cmd, vg_to, vg_name_to); |
160 | unlock_and_release_vg(cmd, vg_from, vg_name_from); | |
91d865ca | 161 | |
043b1362 | 162 | return r; |
da4e57f2 | 163 | } |
5a52dca9 AK |
164 | |
165 | int vgmerge(struct cmd_context *cmd, int argc, char **argv) | |
166 | { | |
aec21154 | 167 | const char *vg_name_to, *vg_name_from; |
5a52dca9 AK |
168 | int opt = 0; |
169 | int ret = 0, ret_max = 0; | |
170 | ||
171 | if (argc < 2) { | |
172 | log_error("Please enter 2 or more volume groups to merge"); | |
173 | return EINVALID_CMD_LINE; | |
174 | } | |
175 | ||
9397354a | 176 | vg_name_to = skip_dev_dir(cmd, argv[0], NULL); |
5a52dca9 AK |
177 | argc--; |
178 | argv++; | |
179 | ||
180 | for (; opt < argc; opt++) { | |
9397354a | 181 | vg_name_from = skip_dev_dir(cmd, argv[opt], NULL); |
08c060cf AK |
182 | |
183 | ret = _vgmerge_single(cmd, vg_name_to, vg_name_from); | |
5a52dca9 AK |
184 | if (ret > ret_max) |
185 | ret_max = ret; | |
186 | } | |
187 | ||
188 | return ret_max; | |
189 | } |