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