Branch data Line data Source code
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 : 0 : static int _remove_pv(struct volume_group *vg, struct pv_list *pvl, int silent)
20 : : {
21 : : char uuid[64] __attribute((aligned(8)));
22 : :
23 [ # # ]: 0 : if (vg->pv_count == 1) {
24 : 0 : log_error("Volume Groups must always contain at least one PV");
25 : 0 : return 0;
26 : : }
27 : :
28 [ # # ]: 0 : if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid)))
29 : 0 : return_0;
30 : :
31 : 0 : log_verbose("Removing PV with UUID %s from VG %s", uuid, vg->name);
32 : :
33 [ # # ]: 0 : if (pvl->pv->pe_alloc_count) {
34 [ # # ]: 0 : if (!silent)
35 : 0 : log_error("LVs still present on PV with UUID %s: "
36 : : "Can't remove from VG %s", uuid, vg->name);
37 : 0 : return 0;
38 : : }
39 : :
40 : 0 : vg->free_count -= pvl->pv->pe_count;
41 : 0 : vg->extent_count -= pvl->pv->pe_count;
42 : 0 : vg->pv_count--;
43 : :
44 : 0 : dm_list_del(&pvl->list);
45 : :
46 : 0 : return 1;
47 : : }
48 : :
49 : 0 : static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
50 : : int *list_unsafe, struct dm_list *lvs_changed)
51 : : {
52 : : struct lv_segment *snap_seg;
53 : : struct dm_list *snh, *snht;
54 : : struct logical_volume *cow;
55 : : struct lv_list *lvl;
56 : : struct lvinfo info;
57 : 0 : int first = 1;
58 : :
59 : 0 : log_verbose("%s/%s has missing extents: removing (including "
60 : : "dependencies)", lv->vg->name, lv->name);
61 : :
62 : : /* FIXME Cope properly with stacked devices & snapshots. */
63 : :
64 : : /* If snapshot device is missing, deactivate origin. */
65 [ # # # # ]: 0 : if (lv_is_cow(lv) && (snap_seg = find_cow(lv))) {
66 : 0 : log_verbose("Deactivating (if active) logical volume %s "
67 : : "(origin of %s)", snap_seg->origin->name, lv->name);
68 : :
69 [ # # # # ]: 0 : if (!test_mode() && !deactivate_lv(cmd, snap_seg->origin)) {
[ # # ][ # # ]
70 : 0 : log_error("Failed to deactivate LV %s",
71 : : snap_seg->origin->name);
72 : 0 : return 0;
73 : : }
74 : :
75 : : /* Use the origin LV */
76 : 0 : lv = snap_seg->origin;
77 : : }
78 : :
79 : : /* Remove snapshot dependencies */
80 [ # # ]: 0 : dm_list_iterate_safe(snh, snht, &lv->snapshot_segs) {
81 : 0 : snap_seg = dm_list_struct_base(snh, struct lv_segment,
82 : : origin_list);
83 : 0 : cow = snap_seg->cow;
84 : :
85 [ # # ][ # # : 0 : if (first && !test_mode() &&
# # # # ]
86 [ # # ]: 0 : !deactivate_lv(cmd, snap_seg->origin)) {
87 : 0 : log_error("Failed to deactivate LV %s",
88 : : snap_seg->origin->name);
89 : 0 : return 0;
90 : : }
91 : :
92 : 0 : *list_unsafe = 1; /* May remove caller's lvht! */
93 [ # # ]: 0 : if (!vg_remove_snapshot(cow))
94 : 0 : return_0;
95 : 0 : log_verbose("Removing LV %s from VG %s", cow->name,
96 : : lv->vg->name);
97 [ # # ]: 0 : if (!lv_remove(cow))
98 : 0 : return_0;
99 : :
100 : 0 : first = 0;
101 : : }
102 : :
103 : : /*
104 : : * If LV is active, replace it with error segment
105 : : * and add to list of LVs to be removed later.
106 : : * Doesn't apply to snapshots/origins yet - they're already deactivated.
107 : : */
108 : : /*
109 : : * If the LV is a part of mirror segment,
110 : : * the mirrored LV also should be cleaned up.
111 : : * Clean-up is currently done by caller (_make_vg_consistent()).
112 : : */
113 [ # # ]: 0 : if ((lv_info(cmd, lv, &info, 0, 0) && info.exists) ||
[ # # # # ]
114 : 0 : find_mirror_seg(first_seg(lv))) {
115 [ # # ]: 0 : if (!replace_lv_with_error_segment(lv))
116 : 0 : return_0;
117 : :
118 [ # # ]: 0 : if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) {
119 : 0 : log_error("lv_list alloc failed");
120 : 0 : return 0;
121 : : }
122 : 0 : lvl->lv = lv;
123 : 0 : dm_list_add(lvs_changed, &lvl->list);
124 : : } else {
125 : : /* Remove LV immediately. */
126 : 0 : log_verbose("Removing LV %s from VG %s", lv->name, lv->vg->name);
127 [ # # ]: 0 : if (!lv_remove(lv))
128 : 0 : return_0;
129 : : }
130 : :
131 : 0 : return 1;
132 : : }
133 : :
134 : 0 : static int _consolidate_vg(struct cmd_context *cmd, struct volume_group *vg)
135 : : {
136 : : struct pv_list *pvl;
137 : : struct lv_list *lvl;
138 : 0 : int r = 1;
139 : :
140 [ # # ]: 0 : dm_list_iterate_items(lvl, &vg->lvs)
141 [ # # ]: 0 : if (lvl->lv->status & PARTIAL_LV) {
142 : 0 : log_warn("WARNING: Partial LV %s needs to be repaired "
143 : : "or removed. ", lvl->lv->name);
144 : 0 : r = 0;
145 : : }
146 : :
147 [ # # ]: 0 : if (!r) {
148 : 0 : cmd->handles_missing_pvs = 1;
149 : 0 : log_warn("WARNING: There are still partial LVs in VG %s.", vg->name);
150 : 0 : log_warn("To remove them unconditionally use: vgreduce --removemissing --force.");
151 : 0 : log_warn("Proceeding to remove empty missing PVs.");
152 : : }
153 : :
154 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs) {
155 [ # # ][ # # ]: 0 : if (pvl->pv->dev && !is_missing_pv(pvl->pv))
156 : 0 : continue;
157 [ # # ][ # # ]: 0 : if (r && !_remove_pv(vg, pvl, 0))
158 : 0 : return_0;
159 : : }
160 : :
161 : 0 : return r;
162 : : }
163 : :
164 : 0 : static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
165 : : {
166 : : struct dm_list *pvh, *pvht;
167 : : struct dm_list *lvh, *lvht;
168 : : struct pv_list *pvl;
169 : : struct lv_list *lvl, *lvl2, *lvlt;
170 : : struct logical_volume *lv;
171 : : struct physical_volume *pv;
172 : : struct lv_segment *seg, *mirrored_seg;
173 : : unsigned s;
174 : : uint32_t mimages, remove_log;
175 : : int list_unsafe, only_mirror_images_found;
176 : 0 : DM_LIST_INIT(lvs_changed);
177 : 0 : only_mirror_images_found = 1;
178 : :
179 : : /* Deactivate & remove necessary LVs */
180 : : restart_loop:
181 : 0 : list_unsafe = 0; /* Set if we delete a different list-member */
182 : :
183 [ # # ]: 0 : dm_list_iterate_safe(lvh, lvht, &vg->lvs) {
184 : 0 : lv = dm_list_item(lvh, struct lv_list)->lv;
185 : :
186 : : /* Are any segments of this LV on missing PVs? */
187 [ # # ]: 0 : dm_list_iterate_items(seg, &lv->segments) {
188 [ # # ]: 0 : for (s = 0; s < seg->area_count; s++) {
189 [ # # ]: 0 : if (seg_type(seg, s) != AREA_PV)
190 : 0 : continue;
191 : :
192 : : /* FIXME Also check for segs on deleted LVs (incl pvmove) */
193 : :
194 : 0 : pv = seg_pv(seg, s);
195 [ # # ]: 0 : if (!pv || !pv_dev(pv) ||
[ # # # # ]
196 : 0 : is_missing_pv(pv)) {
197 [ # # ][ # # ]: 0 : if (arg_count(cmd, mirrorsonly_ARG) &&
198 : 0 : !(lv->status & MIRROR_IMAGE)) {
199 : 0 : log_error("Non-mirror-image LV %s found: can't remove.", lv->name);
200 : 0 : only_mirror_images_found = 0;
201 : 0 : continue;
202 : : }
203 [ # # ]: 0 : if (!_remove_lv(cmd, lv, &list_unsafe, &lvs_changed))
204 : 0 : return_0;
205 [ # # ]: 0 : if (list_unsafe)
206 : 0 : goto restart_loop;
207 : : }
208 : : }
209 : : }
210 : : }
211 : :
212 [ # # ]: 0 : if (!only_mirror_images_found) {
213 : 0 : log_error("Aborting because --mirrorsonly was specified.");
214 : 0 : return 0;
215 : : }
216 : :
217 : : /*
218 : : * Remove missing PVs. FIXME: This duplicates _consolidate_vg above,
219 : : * but we cannot use that right now, since the LV removal code in this
220 : : * function leaves the VG in a "somewhat inconsistent" state and
221 : : * _consolidate_vg doesn't like that -- specifically, mirrors are fixed
222 : : * up *after* the PVs are removed. All this should be gradually
223 : : * superseded by lvconvert --repair.
224 : : */
225 [ # # ]: 0 : dm_list_iterate_safe(pvh, pvht, &vg->pvs) {
226 : 0 : pvl = dm_list_item(pvh, struct pv_list);
227 [ # # ][ # # ]: 0 : if (pvl->pv->dev && !is_missing_pv(pvl->pv))
228 : 0 : continue;
229 [ # # ]: 0 : if (!_remove_pv(vg, pvl, 0))
230 : 0 : return_0;
231 : : }
232 : :
233 : : /* FIXME Recovery. For now people must clean up by hand. */
234 : :
235 [ # # ]: 0 : if (!dm_list_empty(&lvs_changed)) {
236 [ # # ]: 0 : if (!vg_write(vg)) {
237 : 0 : log_error("Failed to write out a consistent VG for %s",
238 : : vg->name);
239 : 0 : return 0;
240 : : }
241 : :
242 [ # # ]: 0 : if (!test_mode()) {
243 : : /* Suspend lvs_changed */
244 [ # # ]: 0 : if (!suspend_lvs(cmd, &lvs_changed)) {
245 : 0 : stack;
246 : 0 : vg_revert(vg);
247 : 0 : return 0;
248 : : }
249 : : }
250 : :
251 [ # # ]: 0 : if (!vg_commit(vg)) {
252 : 0 : log_error("Failed to commit consistent VG for %s",
253 : : vg->name);
254 : 0 : vg_revert(vg);
255 : 0 : return 0;
256 : : }
257 : :
258 [ # # ]: 0 : if (!test_mode()) {
259 [ # # ]: 0 : if (!resume_lvs(cmd, &lvs_changed)) {
260 : 0 : log_error("Failed to resume LVs using error segments.");
261 : 0 : return 0;
262 : : }
263 : : }
264 : :
265 : : lvs_changed_altered:
266 : : /* Remove lost mirror images from mirrors */
267 [ # # ]: 0 : dm_list_iterate_items(lvl, &vg->lvs) {
268 : : mirrored_seg_altered:
269 : 0 : mirrored_seg = first_seg(lvl->lv);
270 [ # # ]: 0 : if (!seg_is_mirrored(mirrored_seg))
271 : 0 : continue;
272 : :
273 : 0 : mimages = mirrored_seg->area_count;
274 : 0 : remove_log = 0;
275 : :
276 [ # # ]: 0 : for (s = 0; s < mirrored_seg->area_count; s++) {
277 [ # # ]: 0 : dm_list_iterate_items_safe(lvl2, lvlt, &lvs_changed) {
278 [ # # ][ # # ]: 0 : if (seg_type(mirrored_seg, s) != AREA_LV ||
279 : 0 : lvl2->lv != seg_lv(mirrored_seg, s))
280 : 0 : continue;
281 : 0 : dm_list_del(&lvl2->list);
282 [ # # ]: 0 : if (!shift_mirror_images(mirrored_seg, s))
283 : 0 : return_0;
284 : 0 : mimages--; /* FIXME Assumes uniqueness */
285 : : }
286 : : }
287 : :
288 [ # # ]: 0 : if (mirrored_seg->log_lv) {
289 [ # # ]: 0 : dm_list_iterate_items(seg, &mirrored_seg->log_lv->segments) {
290 : : /* FIXME: The second test shouldn't be required */
291 [ # # ]: 0 : if ((seg->segtype ==
292 : : get_segtype_from_string(vg->cmd, "error"))) {
293 : 0 : log_print("The log device for %s/%s has failed.",
294 : : vg->name, mirrored_seg->lv->name);
295 : 0 : remove_log = 1;
296 : 0 : break;
297 : : }
298 [ # # ]: 0 : if (!strcmp(seg->segtype->name, "error")) {
299 : 0 : log_print("Log device for %s/%s has failed.",
300 : : vg->name, mirrored_seg->lv->name);
301 : 0 : remove_log = 1;
302 : 0 : break;
303 : : }
304 : : }
305 : : }
306 : :
307 [ # # ][ # # ]: 0 : if ((mimages != mirrored_seg->area_count) || remove_log){
308 [ # # ]: 0 : if (!reconfigure_mirror_images(mirrored_seg, mimages,
309 : : NULL, remove_log))
310 : 0 : return_0;
311 : :
312 [ # # ]: 0 : if (!vg_write(vg)) {
313 : 0 : log_error("Failed to write out updated "
314 : : "VG for %s", vg->name);
315 : 0 : return 0;
316 : : }
317 : :
318 [ # # ]: 0 : if (!vg_commit(vg)) {
319 : 0 : log_error("Failed to commit updated VG "
320 : : "for %s", vg->name);
321 : 0 : vg_revert(vg);
322 : 0 : return 0;
323 : : }
324 : :
325 : : /* mirrored LV no longer has valid mimages.
326 : : * So add it to lvs_changed for removal.
327 : : * For this LV may be an area of other mirror,
328 : : * restart the loop. */
329 [ # # ]: 0 : if (!mimages) {
330 [ # # ]: 0 : if (!_remove_lv(cmd, lvl->lv,
331 : : &list_unsafe, &lvs_changed))
332 : 0 : return_0;
333 : 0 : goto lvs_changed_altered;
334 : : }
335 : :
336 : : /* As a result of reconfigure_mirror_images(),
337 : : * first_seg(lv) may now be different seg.
338 : : * e.g. a temporary layer might be removed.
339 : : * So check the mirrored_seg again. */
340 : 0 : goto mirrored_seg_altered;
341 : : }
342 : : }
343 : :
344 : : /* Deactivate error LVs */
345 [ # # ]: 0 : if (!test_mode()) {
346 [ # # ]: 0 : dm_list_iterate_items_safe(lvl, lvlt, &lvs_changed) {
347 : 0 : log_verbose("Deactivating (if active) logical volume %s",
348 : : lvl->lv->name);
349 : :
350 [ # # # # ]: 0 : if (!deactivate_lv(cmd, lvl->lv)) {
[ # # ]
351 : 0 : log_error("Failed to deactivate LV %s",
352 : : lvl->lv->name);
353 : : /*
354 : : * We failed to deactivate.
355 : : * Probably because this was a mirror log.
356 : : * Don't try to lv_remove it.
357 : : * Continue work on others.
358 : : */
359 : 0 : dm_list_del(&lvl->list);
360 : : }
361 : : }
362 : : }
363 : :
364 : : /* Remove remaining LVs */
365 [ # # ]: 0 : dm_list_iterate_items(lvl, &lvs_changed) {
366 : 0 : log_verbose("Removing LV %s from VG %s", lvl->lv->name,
367 : : lvl->lv->vg->name);
368 : : /* Skip LVs already removed by mirror code */
369 [ # # # # ]: 0 : if (find_lv_in_vg(vg, lvl->lv->name) &&
370 : 0 : !lv_remove(lvl->lv))
371 : 0 : return_0;
372 : : }
373 : : }
374 : :
375 : 0 : return 1;
376 : : }
377 : :
378 : : /* Or take pv_name instead? */
379 : 0 : static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
380 : : struct physical_volume *pv,
381 : : void *handle __attribute((unused)))
382 : : {
383 : : struct pv_list *pvl;
384 : 0 : struct volume_group *orphan_vg = NULL;
385 : 0 : int r = ECMD_FAILED;
386 : 0 : const char *name = pv_dev_name(pv);
387 : :
388 [ # # ]: 0 : if (pv_pe_alloc_count(pv)) {
389 : 0 : log_error("Physical volume \"%s\" still in use", name);
390 : 0 : return ECMD_FAILED;
391 : : }
392 : :
393 [ # # ]: 0 : if (vg->pv_count == 1) {
394 : 0 : log_error("Can't remove final physical volume \"%s\" from "
395 : : "volume group \"%s\"", name, vg->name);
396 : 0 : return ECMD_FAILED;
397 : : }
398 : :
399 [ # # ]: 0 : if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE)) {
400 : 0 : log_error("Can't get lock for orphan PVs");
401 : 0 : return ECMD_FAILED;
402 : : }
403 : :
404 : 0 : pvl = find_pv_in_vg(vg, name);
405 : :
406 [ # # ]: 0 : if (!archive(vg))
407 : 0 : goto_bad;
408 : :
409 : 0 : log_verbose("Removing \"%s\" from volume group \"%s\"", name, vg->name);
410 : :
411 [ # # ]: 0 : if (pvl)
412 : 0 : dm_list_del(&pvl->list);
413 : :
414 : 0 : pv->vg_name = vg->fid->fmt->orphan_vg_name;
415 : 0 : pv->status = ALLOCATABLE_PV;
416 : :
417 [ # # ]: 0 : if (!dev_get_size(pv_dev(pv), &pv->size)) {
418 : 0 : log_error("%s: Couldn't get size.", pv_dev_name(pv));
419 : 0 : goto bad;
420 : : }
421 : :
422 : 0 : vg->pv_count--;
423 : 0 : vg->free_count -= pv_pe_count(pv) - pv_pe_alloc_count(pv);
424 : 0 : vg->extent_count -= pv_pe_count(pv);
425 : :
426 : 0 : orphan_vg = vg_read_for_update(cmd, vg->fid->fmt->orphan_vg_name,
427 : : NULL, 0);
428 : :
429 [ # # ]: 0 : if (vg_read_error(orphan_vg))
430 : 0 : goto bad;
431 : :
432 [ # # ][ # # ]: 0 : if (!vg_split_mdas(cmd, vg, orphan_vg) || !vg->pv_count) {
433 : 0 : log_error("Cannot remove final metadata area on \"%s\" from \"%s\"",
434 : : name, vg->name);
435 : 0 : goto bad;
436 : : }
437 : :
438 [ # # ][ # # ]: 0 : if (!vg_write(vg) || !vg_commit(vg)) {
439 : 0 : log_error("Removal of physical volume \"%s\" from "
440 : : "\"%s\" failed", name, vg->name);
441 : 0 : goto bad;
442 : : }
443 : :
444 [ # # ]: 0 : if (!pv_write(cmd, pv, NULL, INT64_C(-1))) {
445 : 0 : log_error("Failed to clear metadata from physical "
446 : : "volume \"%s\" "
447 : : "after removal from \"%s\"", name, vg->name);
448 : 0 : goto bad;
449 : : }
450 : :
451 : 0 : backup(vg);
452 : :
453 : 0 : log_print("Removed \"%s\" from volume group \"%s\"", name, vg->name);
454 : 0 : r = ECMD_PROCESSED;
455 : : bad:
456 : 0 : unlock_and_release_vg(cmd, orphan_vg, VG_ORPHANS);
457 : 0 : return r;
458 : : }
459 : :
460 : 0 : int vgreduce(struct cmd_context *cmd, int argc, char **argv)
461 : : {
462 : : struct volume_group *vg;
463 : : char *vg_name;
464 : 0 : int ret = ECMD_FAILED;
465 : 0 : int fixed = 1;
466 : 0 : int repairing = arg_count(cmd, removemissing_ARG);
467 : 0 : int saved_ignore_suspended_devices = ignore_suspended_devices();
468 : :
469 [ # # # # ]: 0 : if (!argc && !repairing) {
470 : 0 : log_error("Please give volume group name and "
471 : : "physical volume paths");
472 : 0 : return EINVALID_CMD_LINE;
473 : : }
474 : :
475 [ # # ][ # # ]: 0 : if (!argc && repairing) {
476 : 0 : log_error("Please give volume group name");
477 : 0 : return EINVALID_CMD_LINE;
478 : : }
479 : :
480 [ # # ][ # # ]: 0 : if (arg_count(cmd, mirrorsonly_ARG) && !repairing) {
481 : 0 : log_error("--mirrorsonly requires --removemissing");
482 : 0 : return EINVALID_CMD_LINE;
483 : : }
484 : :
485 [ # # ][ # # ]: 0 : if (argc == 1 && !arg_count(cmd, all_ARG) && !repairing) {
[ # # ]
486 : 0 : log_error("Please enter physical volume paths or option -a");
487 : 0 : return EINVALID_CMD_LINE;
488 : : }
489 : :
490 [ # # ][ # # ]: 0 : if (argc > 1 && arg_count(cmd, all_ARG)) {
491 : 0 : log_error("Option -a and physical volume paths mutually "
492 : : "exclusive");
493 : 0 : return EINVALID_CMD_LINE;
494 : : }
495 : :
496 [ # # ][ # # ]: 0 : if (argc > 1 && repairing) {
497 : 0 : log_error("Please only specify the volume group");
498 : 0 : return EINVALID_CMD_LINE;
499 : : }
500 : :
501 : 0 : vg_name = skip_dev_dir(cmd, argv[0], NULL);
502 : 0 : argv++;
503 : 0 : argc--;
504 : :
505 : 0 : log_verbose("Finding volume group \"%s\"", vg_name);
506 : :
507 [ # # ]: 0 : if (repairing) {
508 : 0 : init_ignore_suspended_devices(1);
509 : 0 : cmd->handles_missing_pvs = 1;
510 : : }
511 : :
512 : 0 : vg = vg_read_for_update(cmd, vg_name, NULL, READ_ALLOW_EXPORTED);
513 [ # # # # ]: 0 : if (vg_read_error(vg) == FAILED_ALLOCATION ||
514 : 0 : vg_read_error(vg) == FAILED_NOTFOUND)
515 : 0 : goto_out;
516 : :
517 : : /* FIXME We want to allow read-only VGs to be changed here? */
518 [ # # # # # : 0 : if (vg_read_error(vg) && vg_read_error(vg) != FAILED_READ_ONLY
# ]
519 : 0 : && !arg_count(cmd, removemissing_ARG))
520 : 0 : goto_out;
521 : :
522 [ # # ]: 0 : if (repairing) {
523 [ # # ][ # # ]: 0 : if (!vg_read_error(vg) && !vg_missing_pv_count(vg)) {
524 : 0 : log_error("Volume group \"%s\" is already consistent",
525 : : vg_name);
526 : 0 : ret = ECMD_PROCESSED;
527 : 0 : goto out;
528 : : }
529 : :
530 : 0 : vg_release(vg);
531 : 0 : log_verbose("Trying to open VG %s for recovery...", vg_name);
532 : :
533 : 0 : vg = vg_read_for_update(cmd, vg_name, NULL,
534 : : READ_ALLOW_INCONSISTENT
535 : : | READ_ALLOW_EXPORTED);
536 : :
537 [ # # # # # : 0 : if (vg_read_error(vg) && vg_read_error(vg) != FAILED_READ_ONLY
# ]
538 : 0 : && vg_read_error(vg) != FAILED_INCONSISTENT)
539 : 0 : goto_out;
540 : :
541 [ # # ]: 0 : if (!archive(vg))
542 : 0 : goto_out;
543 : :
544 [ # # ]: 0 : if (arg_count(cmd, force_ARG)) {
545 [ # # ]: 0 : if (!_make_vg_consistent(cmd, vg))
546 : 0 : goto_out;
547 : : } else
548 : 0 : fixed = _consolidate_vg(cmd, vg);
549 : :
550 [ # # ][ # # ]: 0 : if (!vg_write(vg) || !vg_commit(vg)) {
551 : 0 : log_error("Failed to write out a consistent VG for %s",
552 : : vg_name);
553 : 0 : goto out;
554 : : }
555 : 0 : backup(vg);
556 : :
557 [ # # ]: 0 : if (fixed) {
558 : 0 : log_print("Wrote out consistent volume group %s",
559 : : vg_name);
560 : 0 : ret = ECMD_PROCESSED;
561 : : } else
562 : 0 : ret = ECMD_FAILED;
563 : :
564 : : } else {
565 [ # # ]: 0 : if (!vg_check_status(vg, EXPORTED_VG | LVM_WRITE | RESIZEABLE_VG))
566 : 0 : goto_out;
567 : :
568 : : /* FIXME: Pass private struct through to all these functions */
569 : : /* and update in batch here? */
570 : 0 : ret = process_each_pv(cmd, argc, argv, vg, READ_FOR_UPDATE, 0, NULL,
571 : : _vgreduce_single);
572 : :
573 : : }
574 : : out:
575 : 0 : init_ignore_suspended_devices(saved_ignore_suspended_devices);
576 : 0 : unlock_and_release_vg(cmd, vg, vg_name);
577 : :
578 : 0 : return ret;
579 : :
580 : : /******* FIXME
581 : : log_error ("no empty physical volumes found in volume group \"%s\"", vg_name);
582 : :
583 : : log_verbose
584 : : ("volume group \"%s\" will be reduced by %d physical volume%s",
585 : : vg_name, np, np > 1 ? "s" : "");
586 : : log_verbose ("reducing volume group \"%s\" by physical volume \"%s\"",
587 : : vg_name, pv_names[p]);
588 : :
589 : : log_print
590 : : ("volume group \"%s\" %ssuccessfully reduced by physical volume%s:",
591 : : vg_name, error > 0 ? "NOT " : "", p > 1 ? "s" : "");
592 : : log_print("%s", pv_this[p]->pv_name);
593 : : ********/
594 : :
595 : : }
|