Home | History | Annotate | Line # | Download | only in tools
vgchange.c revision 1.1.1.3
      1 /*	$NetBSD: vgchange.c,v 1.1.1.3 2009/12/02 00:25:51 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 
     20 static int _monitor_lvs_in_vg(struct cmd_context *cmd,
     21 			       struct volume_group *vg, int reg)
     22 {
     23 	struct lv_list *lvl;
     24 	struct logical_volume *lv;
     25 	struct lvinfo info;
     26 	int lv_active;
     27 	int count = 0;
     28 
     29 	dm_list_iterate_items(lvl, &vg->lvs) {
     30 		lv = lvl->lv;
     31 
     32 		if (!lv_info(cmd, lv, &info, 0, 0))
     33 			lv_active = 0;
     34 		else
     35 			lv_active = info.exists;
     36 
     37 		/*
     38 		 * FIXME: Need to consider all cases... PVMOVE, etc
     39 		 */
     40 		if ((lv->status & PVMOVE) || !lv_active)
     41 			continue;
     42 
     43 		if (!monitor_dev_for_events(cmd, lv, reg)) {
     44 			continue;
     45 		} else
     46 			count++;
     47 	}
     48 
     49 	/*
     50 	 * returns the number of _new_ monitored devices
     51 	 */
     52 
     53 	return count;
     54 }
     55 
     56 static int _activate_lvs_in_vg(struct cmd_context *cmd,
     57 			       struct volume_group *vg, int activate)
     58 {
     59 	struct lv_list *lvl;
     60 	struct logical_volume *lv;
     61 	int count = 0, expected_count = 0;
     62 
     63 	dm_list_iterate_items(lvl, &vg->lvs) {
     64 		lv = lvl->lv;
     65 
     66 		if (!lv_is_visible(lv))
     67 			continue;
     68 
     69 		/* Only request activation of snapshot origin devices */
     70 		if ((lv->status & SNAPSHOT) || lv_is_cow(lv))
     71 			continue;
     72 
     73 		/* Only request activation of mirror LV */
     74 		if ((lv->status & MIRROR_IMAGE) || (lv->status & MIRROR_LOG))
     75 			continue;
     76 
     77 		/* Can't deactivate a pvmove LV */
     78 		/* FIXME There needs to be a controlled way of doing this */
     79 		if (((activate == CHANGE_AN) || (activate == CHANGE_ALN)) &&
     80 		    ((lv->status & PVMOVE) ))
     81 			continue;
     82 
     83 		expected_count++;
     84 
     85 		if (activate == CHANGE_AN) {
     86 			if (!deactivate_lv(cmd, lv))
     87 				continue;
     88 		} else if (activate == CHANGE_ALN) {
     89 			if (!deactivate_lv_local(cmd, lv))
     90 				continue;
     91 		} else if (lv_is_origin(lv) || (activate == CHANGE_AE)) {
     92 			if (!activate_lv_excl(cmd, lv))
     93 				continue;
     94 		} else if (activate == CHANGE_ALY) {
     95 			if (!activate_lv_local(cmd, lv))
     96 				continue;
     97 		} else if (!activate_lv(cmd, lv))
     98 			continue;
     99 
    100 		if (activate != CHANGE_AN && activate != CHANGE_ALN &&
    101 		    (lv->status & (PVMOVE|CONVERTING)))
    102 			lv_spawn_background_polling(cmd, lv);
    103 
    104 		count++;
    105 	}
    106 
    107 	if (expected_count)
    108 		log_verbose("%s %d logical volumes in volume group %s",
    109 			    activate ? "Activated" : "Deactivated",
    110 			    count, vg->name);
    111 
    112 	return (expected_count != count) ? ECMD_FAILED : ECMD_PROCESSED;
    113 }
    114 
    115 static int _vgchange_monitoring(struct cmd_context *cmd, struct volume_group *vg)
    116 {
    117 	int active, monitored;
    118 
    119 	if ((active = lvs_in_vg_activated(vg)) &&
    120 	    dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) {
    121 		monitored = _monitor_lvs_in_vg(cmd, vg, dmeventd_monitor_mode());
    122 		log_print("%d logical volume(s) in volume group "
    123 			    "\"%s\" %smonitored",
    124 			    monitored, vg->name, (dmeventd_monitor_mode()) ? "" : "un");
    125 	}
    126 
    127 	return ECMD_PROCESSED;
    128 }
    129 
    130 static int _vgchange_available(struct cmd_context *cmd, struct volume_group *vg)
    131 {
    132 	int lv_open, active, monitored;
    133 	int available, ret;
    134 	int activate = 1;
    135 
    136 	/*
    137 	 * Safe, since we never write out new metadata here. Required for
    138 	 * partial activation to work.
    139 	 */
    140 	cmd->handles_missing_pvs = 1;
    141 
    142 	available = arg_uint_value(cmd, available_ARG, 0);
    143 
    144 	if ((available == CHANGE_AN) || (available == CHANGE_ALN))
    145 		activate = 0;
    146 
    147 	/* FIXME: Force argument to deactivate them? */
    148 	if (!activate && (lv_open = lvs_in_vg_opened(vg))) {
    149 		log_error("Can't deactivate volume group \"%s\" with %d open "
    150 			  "logical volume(s)", vg->name, lv_open);
    151 		return ECMD_FAILED;
    152 	}
    153 
    154 	/* FIXME Move into library where clvmd can use it */
    155 	if (activate)
    156 		check_current_backup(vg);
    157 
    158 	if (activate && (active = lvs_in_vg_activated(vg))) {
    159 		log_verbose("%d logical volume(s) in volume group \"%s\" "
    160 			    "already active", active, vg->name);
    161 		if (dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) {
    162 			monitored = _monitor_lvs_in_vg(cmd, vg, dmeventd_monitor_mode());
    163 			log_verbose("%d existing logical volume(s) in volume "
    164 				    "group \"%s\" %smonitored",
    165 				    monitored, vg->name,
    166 				    dmeventd_monitor_mode() ? "" : "un");
    167 		}
    168 	}
    169 
    170 	ret = _activate_lvs_in_vg(cmd, vg, available);
    171 
    172 	log_print("%d logical volume(s) in volume group \"%s\" now active",
    173 		  lvs_in_vg_activated(vg), vg->name);
    174 	return ret;
    175 }
    176 
    177 static int _vgchange_alloc(struct cmd_context *cmd, struct volume_group *vg)
    178 {
    179 	alloc_policy_t alloc;
    180 
    181 	alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_NORMAL);
    182 
    183 	if (!archive(vg)) {
    184 		stack;
    185 		return ECMD_FAILED;
    186 	}
    187 
    188 	/* FIXME: make consistent with vg_set_alloc_policy() */
    189 	if (alloc == vg->alloc) {
    190 		log_error("Volume group allocation policy is already %s",
    191 			  get_alloc_string(vg->alloc));
    192 		return ECMD_FAILED;
    193 	}
    194 	if (!vg_set_alloc_policy(vg, alloc)) {
    195 		stack;
    196 		return ECMD_FAILED;
    197 	}
    198 
    199 	if (!vg_write(vg) || !vg_commit(vg)) {
    200 		stack;
    201 		return ECMD_FAILED;
    202 	}
    203 
    204 	backup(vg);
    205 
    206 	log_print("Volume group \"%s\" successfully changed", vg->name);
    207 
    208 	return ECMD_PROCESSED;
    209 }
    210 
    211 static int _vgchange_resizeable(struct cmd_context *cmd,
    212 				struct volume_group *vg)
    213 {
    214 	int resizeable = !strcmp(arg_str_value(cmd, resizeable_ARG, "n"), "y");
    215 
    216 	if (resizeable && vg_is_resizeable(vg)) {
    217 		log_error("Volume group \"%s\" is already resizeable",
    218 			  vg->name);
    219 		return ECMD_FAILED;
    220 	}
    221 
    222 	if (!resizeable && !vg_is_resizeable(vg)) {
    223 		log_error("Volume group \"%s\" is already not resizeable",
    224 			  vg->name);
    225 		return ECMD_FAILED;
    226 	}
    227 
    228 	if (!archive(vg)) {
    229 		stack;
    230 		return ECMD_FAILED;
    231 	}
    232 
    233 	if (resizeable)
    234 		vg->status |= RESIZEABLE_VG;
    235 	else
    236 		vg->status &= ~RESIZEABLE_VG;
    237 
    238 	if (!vg_write(vg) || !vg_commit(vg)) {
    239 		stack;
    240 		return ECMD_FAILED;
    241 	}
    242 
    243 	backup(vg);
    244 
    245 	log_print("Volume group \"%s\" successfully changed", vg->name);
    246 
    247 	return ECMD_PROCESSED;
    248 }
    249 
    250 static int _vgchange_clustered(struct cmd_context *cmd,
    251 			       struct volume_group *vg)
    252 {
    253 	int clustered = !strcmp(arg_str_value(cmd, clustered_ARG, "n"), "y");
    254 
    255 	if (clustered && (vg_is_clustered(vg))) {
    256 		log_error("Volume group \"%s\" is already clustered",
    257 			  vg->name);
    258 		return ECMD_FAILED;
    259 	}
    260 
    261 	if (!clustered && !(vg_is_clustered(vg))) {
    262 		log_error("Volume group \"%s\" is already not clustered",
    263 			  vg->name);
    264 		return ECMD_FAILED;
    265 	}
    266 
    267 	if (!archive(vg)) {
    268 		stack;
    269 		return ECMD_FAILED;
    270 	}
    271 
    272 	if (!vg_set_clustered(vg, clustered))
    273 		return ECMD_FAILED;
    274 
    275 	if (!vg_write(vg) || !vg_commit(vg)) {
    276 		stack;
    277 		return ECMD_FAILED;
    278 	}
    279 
    280 	backup(vg);
    281 
    282 	log_print("Volume group \"%s\" successfully changed", vg->name);
    283 
    284 	return ECMD_PROCESSED;
    285 }
    286 
    287 static int _vgchange_logicalvolume(struct cmd_context *cmd,
    288 				   struct volume_group *vg)
    289 {
    290 	uint32_t max_lv = arg_uint_value(cmd, logicalvolume_ARG, 0);
    291 
    292 	if (!archive(vg)) {
    293 		stack;
    294 		return ECMD_FAILED;
    295 	}
    296 
    297 	if (!vg_set_max_lv(vg, max_lv)) {
    298 		stack;
    299 		return ECMD_FAILED;
    300 	}
    301 
    302 	if (!vg_write(vg) || !vg_commit(vg)) {
    303 		stack;
    304 		return ECMD_FAILED;
    305 	}
    306 
    307 	backup(vg);
    308 
    309 	log_print("Volume group \"%s\" successfully changed", vg->name);
    310 
    311 	return ECMD_PROCESSED;
    312 }
    313 
    314 static int _vgchange_physicalvolumes(struct cmd_context *cmd,
    315 				     struct volume_group *vg)
    316 {
    317 	uint32_t max_pv = arg_uint_value(cmd, maxphysicalvolumes_ARG, 0);
    318 
    319 	if (arg_sign_value(cmd, maxphysicalvolumes_ARG, 0) == SIGN_MINUS) {
    320 		log_error("MaxPhysicalVolumes may not be negative");
    321 		return EINVALID_CMD_LINE;
    322 	}
    323 
    324 	if (!archive(vg)) {
    325 		stack;
    326 		return ECMD_FAILED;
    327 	}
    328 
    329 	if (!vg_set_max_pv(vg, max_pv)) {
    330 		stack;
    331 		return ECMD_FAILED;
    332 	}
    333 
    334 	if (!vg_write(vg) || !vg_commit(vg)) {
    335 		stack;
    336 		return ECMD_FAILED;
    337 	}
    338 
    339 	backup(vg);
    340 
    341 	log_print("Volume group \"%s\" successfully changed", vg->name);
    342 
    343 	return ECMD_PROCESSED;
    344 }
    345 
    346 static int _vgchange_pesize(struct cmd_context *cmd, struct volume_group *vg)
    347 {
    348 	uint32_t extent_size;
    349 
    350 	if (arg_sign_value(cmd, physicalextentsize_ARG, 0) == SIGN_MINUS) {
    351 		log_error("Physical extent size may not be negative");
    352 		return EINVALID_CMD_LINE;
    353 	}
    354 
    355 	extent_size = arg_uint_value(cmd, physicalextentsize_ARG, 0);
    356 	/* FIXME: remove check - redundant with vg_change_pesize */
    357 	if (extent_size == vg->extent_size) {
    358 		log_error("Physical extent size of VG %s is already %s",
    359 			  vg->name, display_size(cmd, (uint64_t) extent_size));
    360 		return ECMD_PROCESSED;
    361 	}
    362 
    363 	if (!archive(vg)) {
    364 		stack;
    365 		return ECMD_FAILED;
    366 	}
    367 
    368 	if (!vg_set_extent_size(vg, extent_size)) {
    369 		stack;
    370 		return EINVALID_CMD_LINE;
    371 	}
    372 
    373 	if (!vg_write(vg) || !vg_commit(vg)) {
    374 		stack;
    375 		return ECMD_FAILED;
    376 	}
    377 
    378 	backup(vg);
    379 
    380 	log_print("Volume group \"%s\" successfully changed", vg->name);
    381 
    382 	return ECMD_PROCESSED;
    383 }
    384 
    385 static int _vgchange_tag(struct cmd_context *cmd, struct volume_group *vg,
    386 			 int arg)
    387 {
    388 	const char *tag;
    389 
    390 	if (!(tag = arg_str_value(cmd, arg, NULL))) {
    391 		log_error("Failed to get tag");
    392 		return ECMD_FAILED;
    393 	}
    394 
    395 	if (!(vg->fid->fmt->features & FMT_TAGS)) {
    396 		log_error("Volume group %s does not support tags", vg->name);
    397 		return ECMD_FAILED;
    398 	}
    399 
    400 	if (!archive(vg)) {
    401 		stack;
    402 		return ECMD_FAILED;
    403 	}
    404 
    405 	if ((arg == addtag_ARG)) {
    406 		if (!str_list_add(cmd->mem, &vg->tags, tag)) {
    407 			log_error("Failed to add tag %s to volume group %s",
    408 				  tag, vg->name);
    409 			return ECMD_FAILED;
    410 		}
    411 	} else {
    412 		if (!str_list_del(&vg->tags, tag)) {
    413 			log_error("Failed to remove tag %s from volume group "
    414 				  "%s", tag, vg->name);
    415 			return ECMD_FAILED;
    416 		}
    417 	}
    418 
    419 	if (!vg_write(vg) || !vg_commit(vg)) {
    420 		stack;
    421 		return ECMD_FAILED;
    422 	}
    423 
    424 	backup(vg);
    425 
    426 	log_print("Volume group \"%s\" successfully changed", vg->name);
    427 
    428 	return ECMD_PROCESSED;
    429 }
    430 
    431 static int _vgchange_uuid(struct cmd_context *cmd __attribute((unused)),
    432 			  struct volume_group *vg)
    433 {
    434 	struct lv_list *lvl;
    435 
    436 	if (lvs_in_vg_activated(vg)) {
    437 		log_error("Volume group has active logical volumes");
    438 		return ECMD_FAILED;
    439 	}
    440 
    441 	if (!archive(vg)) {
    442 		stack;
    443 		return ECMD_FAILED;
    444 	}
    445 
    446 	if (!id_create(&vg->id)) {
    447 		log_error("Failed to generate new random UUID for VG %s.",
    448 			  vg->name);
    449 		return ECMD_FAILED;
    450 	}
    451 
    452 	dm_list_iterate_items(lvl, &vg->lvs) {
    453 		memcpy(&lvl->lv->lvid, &vg->id, sizeof(vg->id));
    454 	}
    455 
    456 	if (!vg_write(vg) || !vg_commit(vg)) {
    457 		stack;
    458 		return ECMD_FAILED;
    459 	}
    460 
    461 	backup(vg);
    462 
    463 	log_print("Volume group \"%s\" successfully changed", vg->name);
    464 
    465 	return ECMD_PROCESSED;
    466 }
    467 
    468 static int _vgchange_refresh(struct cmd_context *cmd, struct volume_group *vg)
    469 {
    470 	log_verbose("Refreshing volume group \"%s\"", vg->name);
    471 
    472 	if (!vg_refresh_visible(cmd, vg)) {
    473 		stack;
    474 		return ECMD_FAILED;
    475 	}
    476 
    477 	return ECMD_PROCESSED;
    478 }
    479 
    480 static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
    481 			   struct volume_group *vg,
    482 			   void *handle __attribute((unused)))
    483 {
    484 	int r = ECMD_FAILED;
    485 
    486 	if (vg_is_exported(vg)) {
    487 		log_error("Volume group \"%s\" is exported", vg_name);
    488 		return ECMD_FAILED;
    489 	}
    490 
    491 	init_dmeventd_monitor(arg_int_value(cmd, monitor_ARG,
    492 					    (is_static() || arg_count(cmd, ignoremonitoring_ARG)) ?
    493 					    DMEVENTD_MONITOR_IGNORE : DEFAULT_DMEVENTD_MONITOR));
    494 
    495 	if (arg_count(cmd, available_ARG))
    496 		r = _vgchange_available(cmd, vg);
    497 
    498 	else if (arg_count(cmd, monitor_ARG))
    499 		r = _vgchange_monitoring(cmd, vg);
    500 
    501 	else if (arg_count(cmd, resizeable_ARG))
    502 		r = _vgchange_resizeable(cmd, vg);
    503 
    504 	else if (arg_count(cmd, logicalvolume_ARG))
    505 		r = _vgchange_logicalvolume(cmd, vg);
    506 
    507 	else if (arg_count(cmd, maxphysicalvolumes_ARG))
    508 		r = _vgchange_physicalvolumes(cmd, vg);
    509 
    510 	else if (arg_count(cmd, addtag_ARG))
    511 		r = _vgchange_tag(cmd, vg, addtag_ARG);
    512 
    513 	else if (arg_count(cmd, deltag_ARG))
    514 		r = _vgchange_tag(cmd, vg, deltag_ARG);
    515 
    516 	else if (arg_count(cmd, physicalextentsize_ARG))
    517 		r = _vgchange_pesize(cmd, vg);
    518 
    519 	else if (arg_count(cmd, uuid_ARG))
    520 		r = _vgchange_uuid(cmd, vg);
    521 
    522 	else if (arg_count(cmd, alloc_ARG))
    523 		r = _vgchange_alloc(cmd, vg);
    524 
    525 	else if (arg_count(cmd, clustered_ARG))
    526 		r = _vgchange_clustered(cmd, vg);
    527 
    528 	else if (arg_count(cmd, refresh_ARG))
    529 		r = _vgchange_refresh(cmd, vg);
    530 
    531 	return r;
    532 }
    533 
    534 int vgchange(struct cmd_context *cmd, int argc, char **argv)
    535 {
    536 	if (!
    537 	    (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
    538 	     arg_count(cmd, maxphysicalvolumes_ARG) +
    539 	     arg_count(cmd, resizeable_ARG) + arg_count(cmd, deltag_ARG) +
    540 	     arg_count(cmd, addtag_ARG) + arg_count(cmd, uuid_ARG) +
    541 	     arg_count(cmd, physicalextentsize_ARG) +
    542 	     arg_count(cmd, clustered_ARG) + arg_count(cmd, alloc_ARG) +
    543 	     arg_count(cmd, monitor_ARG) + arg_count(cmd, refresh_ARG))) {
    544 		log_error("One of -a, -c, -l, -p, -s, -x, --refresh, "
    545 				"--uuid, --alloc, --addtag or --deltag required");
    546 		return EINVALID_CMD_LINE;
    547 	}
    548 
    549 	/* FIXME Cope with several changes at once! */
    550 	if (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
    551 	    arg_count(cmd, maxphysicalvolumes_ARG) +
    552 	    arg_count(cmd, resizeable_ARG) + arg_count(cmd, deltag_ARG) +
    553 	    arg_count(cmd, addtag_ARG) + arg_count(cmd, alloc_ARG) +
    554 	    arg_count(cmd, uuid_ARG) + arg_count(cmd, clustered_ARG) +
    555 	    arg_count(cmd, physicalextentsize_ARG) > 1) {
    556 		log_error("Only one of -a, -c, -l, -p, -s, -x, --uuid, "
    557 			  "--alloc, --addtag or --deltag allowed");
    558 		return EINVALID_CMD_LINE;
    559 	}
    560 
    561 	if (arg_count(cmd, ignorelockingfailure_ARG) &&
    562 	    !arg_count(cmd, available_ARG)) {
    563 		log_error("--ignorelockingfailure only available with -a");
    564 		return EINVALID_CMD_LINE;
    565 	}
    566 
    567 	if (arg_count(cmd, available_ARG) == 1
    568 	    && arg_count(cmd, autobackup_ARG)) {
    569 		log_error("-A option not necessary with -a option");
    570 		return EINVALID_CMD_LINE;
    571 	}
    572 
    573 	return process_each_vg(cmd, argc, argv,
    574 			       (arg_count(cmd, available_ARG)) ?
    575 			       0 : READ_FOR_UPDATE,
    576 			       NULL,
    577 			       &vgchange_single);
    578 }
    579