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