import source from lvm2 2.02.79
[external/device-mapper.git] / tools / vgconvert.c
1 /*
2  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3  * Copyright (C) 2004-2007 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 int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
19                             struct volume_group *vg,
20                             void *handle __attribute__((unused)))
21 {
22         struct physical_volume *pv, *existing_pv;
23         struct logical_volume *lv;
24         struct lv_list *lvl;
25         uint64_t size = 0;
26         struct dm_list mdas;
27         int pvmetadatacopies = 0;
28         uint64_t pvmetadatasize = 0;
29         uint64_t pe_end = 0, pe_start = 0;
30         struct pv_list *pvl;
31         int change_made = 0;
32         struct lvinfo info;
33         int active = 0;
34
35         if (!vg_check_status(vg, LVM_WRITE | EXPORTED_VG)) {
36                 stack;
37                 return ECMD_FAILED;
38         }
39
40         if (vg->fid->fmt == cmd->fmt) {
41                 log_error("Volume group \"%s\" already uses format %s",
42                           vg_name, cmd->fmt->name);
43                 return ECMD_FAILED;
44         }
45
46         if (cmd->fmt->features & FMT_MDAS) {
47                 if (arg_sign_value(cmd, metadatasize_ARG, 0) == SIGN_MINUS) {
48                         log_error("Metadata size may not be negative");
49                         return EINVALID_CMD_LINE;
50                 }
51
52                 pvmetadatasize = arg_uint64_value(cmd, metadatasize_ARG,
53                                                   UINT64_C(0));
54                 if (!pvmetadatasize)
55                         pvmetadatasize =
56                             find_config_tree_int(cmd,
57                                             "metadata/pvmetadatasize",
58                                             DEFAULT_PVMETADATASIZE);
59
60                 pvmetadatacopies = arg_int_value(cmd, pvmetadatacopies_ARG, -1);
61                 if (pvmetadatacopies < 0)
62                         pvmetadatacopies =
63                             find_config_tree_int(cmd,
64                                             "metadata/pvmetadatacopies",
65                                              DEFAULT_PVMETADATACOPIES);
66         }
67
68         if (!archive(vg)) {
69                 log_error("Archive of \"%s\" metadata failed.", vg_name);
70                 return ECMD_FAILED;
71         }
72
73         /* Set PV/LV limit if converting from unlimited metadata format */
74         if (vg->fid->fmt->features & FMT_UNLIMITED_VOLS &&
75             !(cmd->fmt->features & FMT_UNLIMITED_VOLS)) {
76                 if (!vg->max_lv)
77                         vg->max_lv = 255;
78                 if (!vg->max_pv)
79                         vg->max_pv = 255;
80         }
81
82         /* If converting to restricted lvid, check if lvid is compatible */
83         if (!(vg->fid->fmt->features & FMT_RESTRICTED_LVIDS) &&
84             cmd->fmt->features & FMT_RESTRICTED_LVIDS)
85                 dm_list_iterate_items(lvl, &vg->lvs)
86                         if (!lvid_in_restricted_range(&lvl->lv->lvid)) {
87                                 log_error("Logical volume %s lvid format is"
88                                           " incompatible with requested"
89                                           " metadata format.", lvl->lv->name);
90                                 return ECMD_FAILED;
91                         }
92
93         /* Attempt to change any LVIDs that are too big */
94         if (cmd->fmt->features & FMT_RESTRICTED_LVIDS) {
95                 dm_list_iterate_items(lvl, &vg->lvs) {
96                         lv = lvl->lv;
97                         if (lv->status & SNAPSHOT)
98                                 continue;
99                         if (lvnum_from_lvid(&lv->lvid) < MAX_RESTRICTED_LVS)
100                                 continue;
101                         if (lv_info(cmd, lv, 0, &info, 0, 0) && info.exists) {
102                                 log_error("Logical volume %s must be "
103                                           "deactivated before conversion.",
104                                            lv->name);
105                                 active++;
106                                 continue;
107                         }
108                         lvid_from_lvnum(&lv->lvid, &lv->vg->id, find_free_lvnum(lv));
109
110                 }
111         }
112
113         if (active) {
114                 stack;
115                 return ECMD_FAILED;
116         }
117
118         dm_list_iterate_items(pvl, &vg->pvs) {
119                 existing_pv = pvl->pv;
120
121                 pe_start = pv_pe_start(existing_pv);
122                 pe_end = pv_pe_count(existing_pv) * pv_pe_size(existing_pv)
123                     + pe_start - 1;
124
125                 dm_list_init(&mdas);
126                 if (!(pv = pv_create(cmd, pv_dev(existing_pv),
127                                      &existing_pv->id, size, 0, 0,
128                                      pe_start, pv_pe_count(existing_pv),
129                                      pv_pe_size(existing_pv), pvmetadatacopies,
130                                      pvmetadatasize, 0, &mdas))) {
131                         log_error("Failed to setup physical volume \"%s\"",
132                                   pv_dev_name(existing_pv));
133                         if (change_made)
134                                 log_error("Use pvcreate and vgcfgrestore to "
135                                           "repair from archived metadata.");
136                         return ECMD_FAILED;
137                 }
138
139                 /* Need to revert manually if it fails after this point */
140                 change_made = 1;
141
142                 log_verbose("Set up physical volume for \"%s\" with %" PRIu64
143                             " available sectors", pv_dev_name(pv), pv_size(pv));
144
145                 /* Wipe existing label first */
146                 if (!label_remove(pv_dev(pv))) {
147                         log_error("Failed to wipe existing label on %s",
148                                   pv_dev_name(pv));
149                         log_error("Use pvcreate and vgcfgrestore to repair "
150                                   "from archived metadata.");
151                         return ECMD_FAILED;
152                 }
153
154                 log_very_verbose("Writing physical volume data to disk \"%s\"",
155                                  pv_dev_name(pv));
156                 if (!(pv_write(cmd, pv, &mdas,
157                                arg_int64_value(cmd, labelsector_ARG,
158                                                DEFAULT_LABELSECTOR)))) {
159                         log_error("Failed to write physical volume \"%s\"",
160                                   pv_dev_name(pv));
161                         log_error("Use pvcreate and vgcfgrestore to repair "
162                                   "from archived metadata.");
163                         return ECMD_FAILED;
164                 }
165                 log_verbose("Physical volume \"%s\" successfully created",
166                             pv_dev_name(pv));
167
168         }
169
170         log_verbose("Deleting existing metadata for VG %s", vg_name);
171         if (!vg_remove_mdas(vg)) {
172                 log_error("Removal of existing metadata for %s failed.",
173                           vg_name);
174                 log_error("Use pvcreate and vgcfgrestore to repair "
175                           "from archived metadata.");
176                 return ECMD_FAILED;
177         }
178
179         /* FIXME Cache the label format change so we don't have to skip this */
180         if (test_mode()) {
181                 log_verbose("Test mode: Skipping metadata writing for VG %s in"
182                             " format %s", vg_name, cmd->fmt->name);
183                 return ECMD_PROCESSED;
184         }
185
186         log_verbose("Writing metadata for VG %s using format %s", vg_name,
187                     cmd->fmt->name);
188         if (!backup_restore_vg(cmd, vg)) {
189                 log_error("Conversion failed for volume group %s.", vg_name);
190                 log_error("Use pvcreate and vgcfgrestore to repair from "
191                           "archived metadata.");
192                 return ECMD_FAILED;
193         }
194         log_print("Volume group %s successfully converted", vg_name);
195
196         backup(vg);
197
198         return ECMD_PROCESSED;
199 }
200
201 int vgconvert(struct cmd_context *cmd, int argc, char **argv)
202 {
203         if (!argc) {
204                 log_error("Please enter volume group(s)");
205                 return EINVALID_CMD_LINE;
206         }
207
208         if (arg_int_value(cmd, labelsector_ARG, 0) >= LABEL_SCAN_SECTORS) {
209                 log_error("labelsector must be less than %lu",
210                           LABEL_SCAN_SECTORS);
211                 return EINVALID_CMD_LINE;
212         }
213
214         if (arg_count(cmd, metadatacopies_ARG)) {
215                 log_error("Invalid option --metadatacopies, "
216                           "use --pvmetadatacopies instead.");
217                 return EINVALID_CMD_LINE;
218         }
219         if (!(cmd->fmt->features & FMT_MDAS) &&
220             (arg_count(cmd, pvmetadatacopies_ARG) ||
221              arg_count(cmd, metadatasize_ARG))) {
222                 log_error("Metadata parameters only apply to text format");
223                 return EINVALID_CMD_LINE;
224         }
225
226         if (arg_count(cmd, pvmetadatacopies_ARG) &&
227             arg_int_value(cmd, pvmetadatacopies_ARG, -1) > 2) {
228                 log_error("Metadatacopies may only be 0, 1 or 2");
229                 return EINVALID_CMD_LINE;
230         }
231
232         return process_each_vg(cmd, argc, argv, READ_FOR_UPDATE, NULL,
233                                &vgconvert_single);
234 }