Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / contrib / lvm2 / dist / tools / vgmerge.c
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 }