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