Home | History | Annotate | Line # | Download | only in tools
vgreduce.c revision 1.1
      1  1.1  haad /*	$NetBSD: vgreduce.c,v 1.1 2008/12/22 00:19:09 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  haad  * Copyright (C) 2004-2007 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  haad 	struct volume_group *orphan_vg;
    387  1.1  haad 	int consistent = 1;
    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  haad 	if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE | LCK_NONBLOCK)) {
    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  haad 	if (!archive(vg)) {
    409  1.1  haad 		unlock_vg(cmd, VG_ORPHANS);
    410  1.1  haad 		return ECMD_FAILED;
    411  1.1  haad 	}
    412  1.1  haad 
    413  1.1  haad 	log_verbose("Removing \"%s\" from volume group \"%s\"", name, vg->name);
    414  1.1  haad 
    415  1.1  haad 	if (pvl)
    416  1.1  haad 		dm_list_del(&pvl->list);
    417  1.1  haad 
    418  1.1  haad 	pv->vg_name = vg->fid->fmt->orphan_vg_name;
    419  1.1  haad 	pv->status = ALLOCATABLE_PV;
    420  1.1  haad 
    421  1.1  haad 	if (!dev_get_size(pv_dev(pv), &pv->size)) {
    422  1.1  haad 		log_error("%s: Couldn't get size.", pv_dev_name(pv));
    423  1.1  haad 		unlock_vg(cmd, VG_ORPHANS);
    424  1.1  haad 		return ECMD_FAILED;
    425  1.1  haad 	}
    426  1.1  haad 
    427  1.1  haad 	vg->pv_count--;
    428  1.1  haad 	vg->free_count -= pv_pe_count(pv) - pv_pe_alloc_count(pv);
    429  1.1  haad 	vg->extent_count -= pv_pe_count(pv);
    430  1.1  haad 
    431  1.1  haad 	if(!(orphan_vg = vg_read(cmd, vg->fid->fmt->orphan_vg_name, NULL, &consistent)) ||
    432  1.1  haad 	   !consistent) {
    433  1.1  haad 		log_error("Unable to read existing orphan PVs");
    434  1.1  haad 		unlock_vg(cmd, VG_ORPHANS);
    435  1.1  haad 		return ECMD_FAILED;
    436  1.1  haad 	}
    437  1.1  haad 
    438  1.1  haad 	if (!vg_split_mdas(cmd, vg, orphan_vg) || !vg->pv_count) {
    439  1.1  haad 		log_error("Cannot remove final metadata area on \"%s\" from \"%s\"",
    440  1.1  haad 			  name, vg->name);
    441  1.1  haad 		unlock_vg(cmd, VG_ORPHANS);
    442  1.1  haad 		return ECMD_FAILED;
    443  1.1  haad 	}
    444  1.1  haad 
    445  1.1  haad 	if (!vg_write(vg) || !vg_commit(vg)) {
    446  1.1  haad 		log_error("Removal of physical volume \"%s\" from "
    447  1.1  haad 			  "\"%s\" failed", name, vg->name);
    448  1.1  haad 		unlock_vg(cmd, VG_ORPHANS);
    449  1.1  haad 		return ECMD_FAILED;
    450  1.1  haad 	}
    451  1.1  haad 
    452  1.1  haad 	if (!pv_write(cmd, pv, NULL, INT64_C(-1))) {
    453  1.1  haad 		log_error("Failed to clear metadata from physical "
    454  1.1  haad 			  "volume \"%s\" "
    455  1.1  haad 			  "after removal from \"%s\"", name, vg->name);
    456  1.1  haad 		unlock_vg(cmd, VG_ORPHANS);
    457  1.1  haad 		return ECMD_FAILED;
    458  1.1  haad 	}
    459  1.1  haad 
    460  1.1  haad 	unlock_vg(cmd, VG_ORPHANS);
    461  1.1  haad 	backup(vg);
    462  1.1  haad 
    463  1.1  haad 	log_print("Removed \"%s\" from volume group \"%s\"", name, vg->name);
    464  1.1  haad 
    465  1.1  haad 	return ECMD_PROCESSED;
    466  1.1  haad }
    467  1.1  haad 
    468  1.1  haad int vgreduce(struct cmd_context *cmd, int argc, char **argv)
    469  1.1  haad {
    470  1.1  haad 	struct volume_group *vg;
    471  1.1  haad 	char *vg_name;
    472  1.1  haad 	int ret = 1;
    473  1.1  haad 	int consistent = 1;
    474  1.1  haad 	int fixed = 1;
    475  1.1  haad 	int repairing = arg_count(cmd, removemissing_ARG);
    476  1.1  haad 
    477  1.1  haad 	if (!argc && !repairing) {
    478  1.1  haad 		log_error("Please give volume group name and "
    479  1.1  haad 			  "physical volume paths");
    480  1.1  haad 		return EINVALID_CMD_LINE;
    481  1.1  haad 	}
    482  1.1  haad 
    483  1.1  haad 	if (!argc && repairing) {
    484  1.1  haad 		log_error("Please give volume group name");
    485  1.1  haad 		return EINVALID_CMD_LINE;
    486  1.1  haad 	}
    487  1.1  haad 
    488  1.1  haad 	if (arg_count(cmd, mirrorsonly_ARG) && !repairing) {
    489  1.1  haad 		log_error("--mirrorsonly requires --removemissing");
    490  1.1  haad 		return EINVALID_CMD_LINE;
    491  1.1  haad 	}
    492  1.1  haad 
    493  1.1  haad 	if (argc == 1 && !arg_count(cmd, all_ARG) && !repairing) {
    494  1.1  haad 		log_error("Please enter physical volume paths or option -a");
    495  1.1  haad 		return EINVALID_CMD_LINE;
    496  1.1  haad 	}
    497  1.1  haad 
    498  1.1  haad 	if (argc > 1 && arg_count(cmd, all_ARG)) {
    499  1.1  haad 		log_error("Option -a and physical volume paths mutually "
    500  1.1  haad 			  "exclusive");
    501  1.1  haad 		return EINVALID_CMD_LINE;
    502  1.1  haad 	}
    503  1.1  haad 
    504  1.1  haad 	if (argc > 1 && repairing) {
    505  1.1  haad 		log_error("Please only specify the volume group");
    506  1.1  haad 		return EINVALID_CMD_LINE;
    507  1.1  haad 	}
    508  1.1  haad 
    509  1.1  haad 	vg_name = skip_dev_dir(cmd, argv[0], NULL);
    510  1.1  haad 	argv++;
    511  1.1  haad 	argc--;
    512  1.1  haad 
    513  1.1  haad 	if (!validate_name(vg_name)) {
    514  1.1  haad 		log_error("Volume group name \"%s\" is invalid",
    515  1.1  haad 			  vg_name);
    516  1.1  haad 		return ECMD_FAILED;
    517  1.1  haad 	}
    518  1.1  haad 
    519  1.1  haad 	log_verbose("Finding volume group \"%s\"", vg_name);
    520  1.1  haad 	if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
    521  1.1  haad 		log_error("Can't get lock for %s", vg_name);
    522  1.1  haad 		return ECMD_FAILED;
    523  1.1  haad 	}
    524  1.1  haad 
    525  1.1  haad 	if ((!(vg = vg_read(cmd, vg_name, NULL, &consistent)) || !consistent)
    526  1.1  haad 	    && !repairing) {
    527  1.1  haad 		log_error("Volume group \"%s\" doesn't exist", vg_name);
    528  1.1  haad 		unlock_vg(cmd, vg_name);
    529  1.1  haad 		return ECMD_FAILED;
    530  1.1  haad 	}
    531  1.1  haad 
    532  1.1  haad 	if (vg && !vg_check_status(vg, CLUSTERED)) {
    533  1.1  haad 		unlock_vg(cmd, vg_name);
    534  1.1  haad 		return ECMD_FAILED;
    535  1.1  haad 	}
    536  1.1  haad 
    537  1.1  haad 	if (repairing) {
    538  1.1  haad 		if (vg && consistent && !vg_missing_pv_count(vg)) {
    539  1.1  haad 			log_error("Volume group \"%s\" is already consistent",
    540  1.1  haad 				  vg_name);
    541  1.1  haad 			unlock_vg(cmd, vg_name);
    542  1.1  haad 			return ECMD_PROCESSED;
    543  1.1  haad 		}
    544  1.1  haad 
    545  1.1  haad 		consistent = !arg_count(cmd, force_ARG);
    546  1.1  haad 		if (!(vg = vg_read(cmd, vg_name, NULL, &consistent))) {
    547  1.1  haad 			log_error("Volume group \"%s\" not found", vg_name);
    548  1.1  haad 			unlock_vg(cmd, vg_name);
    549  1.1  haad 			return ECMD_FAILED;
    550  1.1  haad 		}
    551  1.1  haad 		if (!vg_check_status(vg, CLUSTERED)) {
    552  1.1  haad 			unlock_vg(cmd, vg_name);
    553  1.1  haad 			return ECMD_FAILED;
    554  1.1  haad 		}
    555  1.1  haad 		if (!archive(vg)) {
    556  1.1  haad 			unlock_vg(cmd, vg_name);
    557  1.1  haad 			return ECMD_FAILED;
    558  1.1  haad 		}
    559  1.1  haad 
    560  1.1  haad 		if (arg_count(cmd, force_ARG)) {
    561  1.1  haad 			if (!_make_vg_consistent(cmd, vg)) {
    562  1.1  haad 				unlock_vg(cmd, vg_name);
    563  1.1  haad 				return ECMD_FAILED;
    564  1.1  haad 			}
    565  1.1  haad 		} else
    566  1.1  haad 			fixed = _consolidate_vg(cmd, vg);
    567  1.1  haad 
    568  1.1  haad 		if (!vg_write(vg) || !vg_commit(vg)) {
    569  1.1  haad 			log_error("Failed to write out a consistent VG for %s",
    570  1.1  haad 				  vg_name);
    571  1.1  haad 			unlock_vg(cmd, vg_name);
    572  1.1  haad 			return ECMD_FAILED;
    573  1.1  haad 		}
    574  1.1  haad 
    575  1.1  haad 		backup(vg);
    576  1.1  haad 
    577  1.1  haad 		if (fixed)
    578  1.1  haad 			log_print("Wrote out consistent volume group %s",
    579  1.1  haad 				  vg_name);
    580  1.1  haad 
    581  1.1  haad 	} else {
    582  1.1  haad 		if (!vg_check_status(vg, EXPORTED_VG | LVM_WRITE | RESIZEABLE_VG)) {
    583  1.1  haad 			unlock_vg(cmd, vg_name);
    584  1.1  haad 			return ECMD_FAILED;
    585  1.1  haad 		}
    586  1.1  haad 
    587  1.1  haad 		/* FIXME: Pass private struct through to all these functions */
    588  1.1  haad 		/* and update in batch here? */
    589  1.1  haad 		ret = process_each_pv(cmd, argc, argv, vg, LCK_NONE, NULL,
    590  1.1  haad 				      _vgreduce_single);
    591  1.1  haad 
    592  1.1  haad 	}
    593  1.1  haad 
    594  1.1  haad 	unlock_vg(cmd, vg_name);
    595  1.1  haad 
    596  1.1  haad 	return ret;
    597  1.1  haad 
    598  1.1  haad /******* FIXME
    599  1.1  haad 	log_error ("no empty physical volumes found in volume group \"%s\"", vg_name);
    600  1.1  haad 
    601  1.1  haad 	log_verbose
    602  1.1  haad 	    ("volume group \"%s\" will be reduced by %d physical volume%s",
    603  1.1  haad 	     vg_name, np, np > 1 ? "s" : "");
    604  1.1  haad 	log_verbose ("reducing volume group \"%s\" by physical volume \"%s\"",
    605  1.1  haad 		     vg_name, pv_names[p]);
    606  1.1  haad 
    607  1.1  haad 	log_print
    608  1.1  haad 	    ("volume group \"%s\" %ssuccessfully reduced by physical volume%s:",
    609  1.1  haad 	     vg_name, error > 0 ? "NOT " : "", p > 1 ? "s" : "");
    610  1.1  haad 		log_print("%s", pv_this[p]->pv_name);
    611  1.1  haad ********/
    612  1.1  haad 
    613  1.1  haad }
    614