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