]> sourceware.org Git - lvm2.git/blob - tools/vgreduce.c
thin: tighten discard string conversions
[lvm2.git] / tools / vgreduce.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 #include "lv_alloc.h"
18
19 static int _remove_pv(struct volume_group *vg, struct pv_list *pvl, int silent)
20 {
21 char uuid[64] __attribute__((aligned(8)));
22
23 if (vg->pv_count == 1) {
24 log_error("Volume Groups must always contain at least one PV");
25 return 0;
26 }
27
28 if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid)))
29 return_0;
30
31 log_verbose("Removing PV with UUID %s from VG %s", uuid, vg->name);
32
33 if (pvl->pv->pe_alloc_count) {
34 if (!silent)
35 log_error("LVs still present on PV with UUID %s: "
36 "Can't remove from VG %s", uuid, vg->name);
37 return 0;
38 }
39
40 vg->free_count -= pvl->pv->pe_count;
41 vg->extent_count -= pvl->pv->pe_count;
42 del_pvl_from_vgs(vg, pvl);
43 free_pv_fid(pvl->pv);
44
45 return 1;
46 }
47
48 static int _consolidate_vg(struct cmd_context *cmd, struct volume_group *vg)
49 {
50 struct pv_list *pvl;
51 struct lv_list *lvl;
52 int r = 1;
53
54 dm_list_iterate_items(lvl, &vg->lvs)
55 if (lvl->lv->status & PARTIAL_LV) {
56 log_warn("WARNING: Partial LV %s needs to be repaired "
57 "or removed. ", lvl->lv->name);
58 r = 0;
59 }
60
61 if (!r) {
62 cmd->handles_missing_pvs = 1;
63 log_error("There are still partial LVs in VG %s.", vg->name);
64 log_error("To remove them unconditionally use: vgreduce --removemissing --force.");
65 log_warn("Proceeding to remove empty missing PVs.");
66 }
67
68 dm_list_iterate_items(pvl, &vg->pvs) {
69 if (pvl->pv->dev && !is_missing_pv(pvl->pv))
70 continue;
71 if (r && !_remove_pv(vg, pvl, 0))
72 return_0;
73 }
74
75 return r;
76 }
77
78 static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
79 {
80 struct lv_list *lvl;
81 struct logical_volume *lv;
82
83 cmd->partial_activation = 1;
84
85 restart:
86 vg_mark_partial_lvs(vg, 1);
87
88 dm_list_iterate_items(lvl, &vg->lvs) {
89 lv = lvl->lv;
90
91 /* Are any segments of this LV on missing PVs? */
92 if (lv->status & PARTIAL_LV) {
93 if (lv->status & MIRRORED) {
94 if (!mirror_remove_missing(cmd, lv, 1))
95 return_0;
96 goto restart;
97 }
98
99 if (arg_count(cmd, mirrorsonly_ARG) &&!(lv->status & MIRRORED)) {
100 log_error("Non-mirror-image LV %s found: can't remove.", lv->name);
101 continue;
102 }
103
104 if (!lv_is_visible(lv))
105 continue;
106 log_warn("Removing partial LV %s.", lv->name);
107 if (!lv_remove_with_dependencies(cmd, lv, DONT_PROMPT, 0))
108 return_0;
109 goto restart;
110 }
111 }
112
113 _consolidate_vg(cmd, vg);
114
115 return 1;
116 }
117
118 /* Or take pv_name instead? */
119 static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
120 struct physical_volume *pv,
121 void *handle __attribute__((unused)))
122 {
123 struct pv_list *pvl;
124 struct volume_group *orphan_vg = NULL;
125 int r = ECMD_FAILED;
126 const char *name = pv_dev_name(pv);
127
128 if (pv_pe_alloc_count(pv)) {
129 log_error("Physical volume \"%s\" still in use", name);
130 return ECMD_FAILED;
131 }
132
133 if (vg->pv_count == 1) {
134 log_error("Can't remove final physical volume \"%s\" from "
135 "volume group \"%s\"", name, vg->name);
136 return ECMD_FAILED;
137 }
138
139 if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE)) {
140 log_error("Can't get lock for orphan PVs");
141 return ECMD_FAILED;
142 }
143
144 pvl = find_pv_in_vg(vg, name);
145
146 if (!archive(vg))
147 goto_bad;
148
149 log_verbose("Removing \"%s\" from volume group \"%s\"", name, vg->name);
150
151 if (pvl)
152 del_pvl_from_vgs(vg, pvl);
153
154 pv->vg_name = vg->fid->fmt->orphan_vg_name;
155 pv->status = ALLOCATABLE_PV;
156
157 if (!dev_get_size(pv_dev(pv), &pv->size)) {
158 log_error("%s: Couldn't get size.", pv_dev_name(pv));
159 goto bad;
160 }
161
162 vg->free_count -= pv_pe_count(pv) - pv_pe_alloc_count(pv);
163 vg->extent_count -= pv_pe_count(pv);
164
165 orphan_vg = vg_read_for_update(cmd, vg->fid->fmt->orphan_vg_name,
166 NULL, 0);
167
168 if (vg_read_error(orphan_vg))
169 goto bad;
170
171 if (!vg_split_mdas(cmd, vg, orphan_vg) || !vg->pv_count) {
172 log_error("Cannot remove final metadata area on \"%s\" from \"%s\"",
173 name, vg->name);
174 goto bad;
175 }
176
177 if (!vg_write(vg) || !vg_commit(vg)) {
178 log_error("Removal of physical volume \"%s\" from "
179 "\"%s\" failed", name, vg->name);
180 goto bad;
181 }
182
183 if (!pv_write(cmd, pv, 0)) {
184 log_error("Failed to clear metadata from physical "
185 "volume \"%s\" "
186 "after removal from \"%s\"", name, vg->name);
187 goto bad;
188 }
189
190 backup(vg);
191
192 log_print("Removed \"%s\" from volume group \"%s\"", name, vg->name);
193 r = ECMD_PROCESSED;
194 bad:
195 if (pvl)
196 free_pv_fid(pvl->pv);
197 unlock_and_release_vg(cmd, orphan_vg, VG_ORPHANS);
198 return r;
199 }
200
201 int vgreduce(struct cmd_context *cmd, int argc, char **argv)
202 {
203 struct volume_group *vg;
204 const char *vg_name;
205 int ret = ECMD_FAILED;
206 int fixed = 1;
207 int repairing = arg_count(cmd, removemissing_ARG);
208 int saved_ignore_suspended_devices = ignore_suspended_devices();
209 int locked = 0;
210
211 if (!argc && !repairing) {
212 log_error("Please give volume group name and "
213 "physical volume paths");
214 return EINVALID_CMD_LINE;
215 }
216
217 if (!argc) { /* repairing */
218 log_error("Please give volume group name");
219 return EINVALID_CMD_LINE;
220 }
221
222 if (arg_count(cmd, mirrorsonly_ARG) && !repairing) {
223 log_error("--mirrorsonly requires --removemissing");
224 return EINVALID_CMD_LINE;
225 }
226
227 if (argc == 1 && !arg_count(cmd, all_ARG) && !repairing) {
228 log_error("Please enter physical volume paths or option -a");
229 return EINVALID_CMD_LINE;
230 }
231
232 if (argc > 1 && arg_count(cmd, all_ARG)) {
233 log_error("Option -a and physical volume paths mutually "
234 "exclusive");
235 return EINVALID_CMD_LINE;
236 }
237
238 if (argc > 1 && repairing) {
239 log_error("Please only specify the volume group");
240 return EINVALID_CMD_LINE;
241 }
242
243 vg_name = skip_dev_dir(cmd, argv[0], NULL);
244 argv++;
245 argc--;
246
247 log_verbose("Finding volume group \"%s\"", vg_name);
248
249 if (repairing) {
250 init_ignore_suspended_devices(1);
251 cmd->handles_missing_pvs = 1;
252 }
253
254 vg = vg_read_for_update(cmd, vg_name, NULL, READ_ALLOW_EXPORTED);
255 if (vg_read_error(vg) == FAILED_ALLOCATION ||
256 vg_read_error(vg) == FAILED_NOTFOUND)
257 goto_out;
258
259 /* FIXME We want to allow read-only VGs to be changed here? */
260 if (vg_read_error(vg) && vg_read_error(vg) != FAILED_READ_ONLY
261 && !arg_count(cmd, removemissing_ARG))
262 goto_out;
263
264 locked = !vg_read_error(vg);
265
266 if (repairing) {
267 if (!vg_read_error(vg) && !vg_missing_pv_count(vg)) {
268 log_error("Volume group \"%s\" is already consistent",
269 vg_name);
270 ret = ECMD_PROCESSED;
271 goto out;
272 }
273
274 release_vg(vg);
275 log_verbose("Trying to open VG %s for recovery...", vg_name);
276
277 vg = vg_read_for_update(cmd, vg_name, NULL,
278 READ_ALLOW_INCONSISTENT
279 | READ_ALLOW_EXPORTED);
280
281 locked |= !vg_read_error(vg);
282 if (vg_read_error(vg) && vg_read_error(vg) != FAILED_READ_ONLY
283 && vg_read_error(vg) != FAILED_INCONSISTENT)
284 goto_out;
285
286 if (!archive(vg))
287 goto_out;
288
289 if (arg_count(cmd, force_ARG)) {
290 if (!_make_vg_consistent(cmd, vg))
291 goto_out;
292 } else
293 fixed = _consolidate_vg(cmd, vg);
294
295 if (!vg_write(vg) || !vg_commit(vg)) {
296 log_error("Failed to write out a consistent VG for %s",
297 vg_name);
298 goto out;
299 }
300 backup(vg);
301
302 if (fixed) {
303 log_print("Wrote out consistent volume group %s",
304 vg_name);
305 ret = ECMD_PROCESSED;
306 } else
307 ret = ECMD_FAILED;
308
309 } else {
310 if (!vg_check_status(vg, EXPORTED_VG | LVM_WRITE | RESIZEABLE_VG))
311 goto_out;
312
313 /* FIXME: Pass private struct through to all these functions */
314 /* and update in batch here? */
315 ret = process_each_pv(cmd, argc, argv, vg, READ_FOR_UPDATE, 0, NULL,
316 _vgreduce_single);
317
318 }
319 out:
320 init_ignore_suspended_devices(saved_ignore_suspended_devices);
321 if (locked)
322 unlock_vg(cmd, vg_name);
323
324 release_vg(vg);
325
326 return ret;
327
328 /******* FIXME
329 log_error ("no empty physical volumes found in volume group \"%s\"", vg_name);
330
331 log_verbose
332 ("volume group \"%s\" will be reduced by %d physical volume%s",
333 vg_name, np, np > 1 ? "s" : "");
334 log_verbose ("reducing volume group \"%s\" by physical volume \"%s\"",
335 vg_name, pv_names[p]);
336
337 log_print
338 ("volume group \"%s\" %ssuccessfully reduced by physical volume%s:",
339 vg_name, error > 0 ? "NOT " : "", p > 1 ? "s" : "");
340 log_print("%s", pv_this[p]->pv_name);
341 ********/
342
343 }
This page took 0.052493 seconds and 5 git commands to generate.