1 /* $NetBSD: vgchange.c,v 1.1.1.2 2009/02/18 11:17:49 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 const char *pvname; 62 int count = 0; 63 64 dm_list_iterate_items(lvl, &vg->lvs) { 65 lv = lvl->lv; 66 67 /* Only request activation of snapshot origin devices */ 68 if ((lv->status & SNAPSHOT) || lv_is_cow(lv)) 69 continue; 70 71 /* Only request activation of mirror LV */ 72 if ((lv->status & MIRROR_IMAGE) || (lv->status & MIRROR_LOG)) 73 continue; 74 75 /* Can't deactivate a pvmove LV */ 76 /* FIXME There needs to be a controlled way of doing this */ 77 if (((activate == CHANGE_AN) || (activate == CHANGE_ALN)) && 78 ((lv->status & PVMOVE) )) 79 continue; 80 81 if (activate == CHANGE_AN) { 82 if (!deactivate_lv(cmd, lv)) 83 continue; 84 } else if (activate == CHANGE_ALN) { 85 if (!deactivate_lv_local(cmd, lv)) 86 continue; 87 } else if (lv_is_origin(lv) || (activate == CHANGE_AE)) { 88 if (!activate_lv_excl(cmd, lv)) 89 continue; 90 } else if (activate == CHANGE_ALY) { 91 if (!activate_lv_local(cmd, lv)) 92 continue; 93 } else if (!activate_lv(cmd, lv)) 94 continue; 95 96 if ((lv->status & PVMOVE) && 97 (pvname = get_pvmove_pvname_from_lv_mirr(lv))) { 98 log_verbose("Spawning background process for %s %s", 99 lv->name, pvname); 100 pvmove_poll(cmd, pvname, 1); 101 continue; 102 } 103 104 count++; 105 } 106 107 return count; 108 } 109 110 static int _vgchange_monitoring(struct cmd_context *cmd, struct volume_group *vg) 111 { 112 int active, monitored; 113 114 if ((active = lvs_in_vg_activated(vg)) && 115 dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) { 116 monitored = _monitor_lvs_in_vg(cmd, vg, dmeventd_monitor_mode()); 117 log_print("%d logical volume(s) in volume group " 118 "\"%s\" %smonitored", 119 monitored, vg->name, (dmeventd_monitor_mode()) ? "" : "un"); 120 } 121 122 return ECMD_PROCESSED; 123 } 124 125 static int _vgchange_available(struct cmd_context *cmd, struct volume_group *vg) 126 { 127 int lv_open, active, monitored; 128 int available; 129 int activate = 1; 130 131 available = arg_uint_value(cmd, available_ARG, 0); 132 133 if ((available == CHANGE_AN) || (available == CHANGE_ALN)) 134 activate = 0; 135 136 /* FIXME: Force argument to deactivate them? */ 137 if (!activate && (lv_open = lvs_in_vg_opened(vg))) { 138 log_error("Can't deactivate volume group \"%s\" with %d open " 139 "logical volume(s)", vg->name, lv_open); 140 return ECMD_FAILED; 141 } 142 143 if (activate && lockingfailed() && (vg_is_clustered(vg))) { 144 log_error("Locking inactive: ignoring clustered " 145 "volume group %s", vg->name); 146 return ECMD_FAILED; 147 } 148 149 /* FIXME Move into library where clvmd can use it */ 150 if (activate && !lockingfailed()) 151 check_current_backup(vg); 152 153 if (activate && (active = lvs_in_vg_activated(vg))) { 154 log_verbose("%d logical volume(s) in volume group \"%s\" " 155 "already active", active, vg->name); 156 if (dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) { 157 monitored = _monitor_lvs_in_vg(cmd, vg, dmeventd_monitor_mode()); 158 log_verbose("%d existing logical volume(s) in volume " 159 "group \"%s\" %smonitored", 160 monitored, vg->name, 161 dmeventd_monitor_mode() ? "" : "un"); 162 } 163 } 164 165 if (activate && _activate_lvs_in_vg(cmd, vg, available)) 166 log_verbose("Activated logical volumes in " 167 "volume group \"%s\"", vg->name); 168 169 if (!activate && _activate_lvs_in_vg(cmd, vg, available)) 170 log_verbose("Deactivated logical volumes in " 171 "volume group \"%s\"", vg->name); 172 173 log_print("%d logical volume(s) in volume group \"%s\" now active", 174 lvs_in_vg_activated(vg), vg->name); 175 return ECMD_PROCESSED; 176 } 177 178 static int _vgchange_alloc(struct cmd_context *cmd, struct volume_group *vg) 179 { 180 alloc_policy_t alloc; 181 182 alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_NORMAL); 183 184 if (alloc == ALLOC_INHERIT) { 185 log_error("Volume Group allocation policy cannot inherit " 186 "from anything"); 187 return EINVALID_CMD_LINE; 188 } 189 190 if (alloc == vg->alloc) { 191 log_error("Volume group allocation policy is already %s", 192 get_alloc_string(vg->alloc)); 193 return ECMD_FAILED; 194 } 195 196 if (!archive(vg)) 197 return ECMD_FAILED; 198 199 vg->alloc = alloc; 200 201 if (!vg_write(vg) || !vg_commit(vg)) 202 return ECMD_FAILED; 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_status(vg) & RESIZEABLE_VG)) { 217 log_error("Volume group \"%s\" is already resizeable", 218 vg->name); 219 return ECMD_FAILED; 220 } 221 222 if (!resizeable && !(vg_status(vg) & 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 return ECMD_FAILED; 230 231 if (resizeable) 232 vg->status |= RESIZEABLE_VG; 233 else 234 vg->status &= ~RESIZEABLE_VG; 235 236 if (!vg_write(vg) || !vg_commit(vg)) 237 return ECMD_FAILED; 238 239 backup(vg); 240 241 log_print("Volume group \"%s\" successfully changed", vg->name); 242 243 return ECMD_PROCESSED; 244 } 245 246 static int _vgchange_clustered(struct cmd_context *cmd, 247 struct volume_group *vg) 248 { 249 int clustered = !strcmp(arg_str_value(cmd, clustered_ARG, "n"), "y"); 250 struct lv_list *lvl; 251 252 if (clustered && (vg_is_clustered(vg))) { 253 log_error("Volume group \"%s\" is already clustered", 254 vg->name); 255 return ECMD_FAILED; 256 } 257 258 if (!clustered && !(vg_is_clustered(vg))) { 259 log_error("Volume group \"%s\" is already not clustered", 260 vg->name); 261 return ECMD_FAILED; 262 } 263 264 if (clustered) { 265 dm_list_iterate_items(lvl, &vg->lvs) { 266 if (lv_is_origin(lvl->lv) || lv_is_cow(lvl->lv)) { 267 log_error("Volume group %s contains snapshots " 268 "that are not yet supported.", 269 vg->name); 270 return ECMD_FAILED; 271 } 272 } 273 } 274 275 if (!archive(vg)) 276 return ECMD_FAILED; 277 278 if (clustered) 279 vg->status |= CLUSTERED; 280 else 281 vg->status &= ~CLUSTERED; 282 283 if (!vg_write(vg) || !vg_commit(vg)) 284 return ECMD_FAILED; 285 286 backup(vg); 287 288 log_print("Volume group \"%s\" successfully changed", vg->name); 289 290 return ECMD_PROCESSED; 291 } 292 293 static int _vgchange_logicalvolume(struct cmd_context *cmd, 294 struct volume_group *vg) 295 { 296 uint32_t max_lv = arg_uint_value(cmd, logicalvolume_ARG, 0); 297 298 if (!(vg_status(vg) & RESIZEABLE_VG)) { 299 log_error("Volume group \"%s\" must be resizeable " 300 "to change MaxLogicalVolume", vg->name); 301 return ECMD_FAILED; 302 } 303 304 if (!(vg->fid->fmt->features & FMT_UNLIMITED_VOLS)) { 305 if (!max_lv) 306 max_lv = 255; 307 else if (max_lv > 255) { 308 log_error("MaxLogicalVolume limit is 255"); 309 return ECMD_FAILED; 310 } 311 } 312 313 if (max_lv && max_lv < vg->lv_count) { 314 log_error("MaxLogicalVolume is less than the current number " 315 "%d of LVs for \"%s\"", vg->lv_count, 316 vg->name); 317 return ECMD_FAILED; 318 } 319 320 if (!archive(vg)) 321 return ECMD_FAILED; 322 323 vg->max_lv = max_lv; 324 325 if (!vg_write(vg) || !vg_commit(vg)) 326 return ECMD_FAILED; 327 328 backup(vg); 329 330 log_print("Volume group \"%s\" successfully changed", vg->name); 331 332 return ECMD_PROCESSED; 333 } 334 335 static int _vgchange_physicalvolumes(struct cmd_context *cmd, 336 struct volume_group *vg) 337 { 338 uint32_t max_pv = arg_uint_value(cmd, maxphysicalvolumes_ARG, 0); 339 340 if (!(vg_status(vg) & RESIZEABLE_VG)) { 341 log_error("Volume group \"%s\" must be resizeable " 342 "to change MaxPhysicalVolumes", vg->name); 343 return ECMD_FAILED; 344 } 345 346 if (arg_sign_value(cmd, maxphysicalvolumes_ARG, 0) == SIGN_MINUS) { 347 log_error("MaxPhysicalVolumes may not be negative"); 348 return EINVALID_CMD_LINE; 349 } 350 351 if (!(vg->fid->fmt->features & FMT_UNLIMITED_VOLS)) { 352 if (!max_pv) 353 max_pv = 255; 354 else if (max_pv > 255) { 355 log_error("MaxPhysicalVolume limit is 255"); 356 return ECMD_FAILED; 357 } 358 } 359 360 if (max_pv && max_pv < vg->pv_count) { 361 log_error("MaxPhysicalVolumes is less than the current number " 362 "%d of PVs for \"%s\"", vg->pv_count, 363 vg->name); 364 return ECMD_FAILED; 365 } 366 367 if (!archive(vg)) 368 return ECMD_FAILED; 369 370 vg->max_pv = max_pv; 371 372 if (!vg_write(vg) || !vg_commit(vg)) 373 return ECMD_FAILED; 374 375 backup(vg); 376 377 log_print("Volume group \"%s\" successfully changed", vg->name); 378 379 return ECMD_PROCESSED; 380 } 381 382 static int _vgchange_pesize(struct cmd_context *cmd, struct volume_group *vg) 383 { 384 uint32_t extent_size; 385 386 if (!(vg_status(vg) & RESIZEABLE_VG)) { 387 log_error("Volume group \"%s\" must be resizeable " 388 "to change PE size", vg->name); 389 return ECMD_FAILED; 390 } 391 392 if (arg_sign_value(cmd, physicalextentsize_ARG, 0) == SIGN_MINUS) { 393 log_error("Physical extent size may not be negative"); 394 return EINVALID_CMD_LINE; 395 } 396 397 extent_size = arg_uint_value(cmd, physicalextentsize_ARG, 0); 398 if (!extent_size) { 399 log_error("Physical extent size may not be zero"); 400 return EINVALID_CMD_LINE; 401 } 402 403 if (extent_size == vg->extent_size) { 404 log_error("Physical extent size of VG %s is already %s", 405 vg->name, display_size(cmd, (uint64_t) extent_size)); 406 return ECMD_PROCESSED; 407 } 408 409 if (extent_size & (extent_size - 1)) { 410 log_error("Physical extent size must be a power of 2."); 411 return EINVALID_CMD_LINE; 412 } 413 414 if (extent_size > vg->extent_size) { 415 if ((uint64_t) vg->extent_size * vg->extent_count % extent_size) { 416 /* FIXME Adjust used PV sizes instead */ 417 log_error("New extent size is not a perfect fit"); 418 return EINVALID_CMD_LINE; 419 } 420 } 421 422 if (!archive(vg)) 423 return ECMD_FAILED; 424 425 if (!vg_change_pesize(cmd, vg, extent_size)) { 426 stack; 427 return ECMD_FAILED; 428 } 429 430 if (!vg_write(vg) || !vg_commit(vg)) 431 return ECMD_FAILED; 432 433 backup(vg); 434 435 log_print("Volume group \"%s\" successfully changed", vg->name); 436 437 return ECMD_PROCESSED; 438 } 439 440 static int _vgchange_tag(struct cmd_context *cmd, struct volume_group *vg, 441 int arg) 442 { 443 const char *tag; 444 445 if (!(tag = arg_str_value(cmd, arg, NULL))) { 446 log_error("Failed to get tag"); 447 return ECMD_FAILED; 448 } 449 450 if (!(vg->fid->fmt->features & FMT_TAGS)) { 451 log_error("Volume group %s does not support tags", vg->name); 452 return ECMD_FAILED; 453 } 454 455 if (!archive(vg)) 456 return ECMD_FAILED; 457 458 if ((arg == addtag_ARG)) { 459 if (!str_list_add(cmd->mem, &vg->tags, tag)) { 460 log_error("Failed to add tag %s to volume group %s", 461 tag, vg->name); 462 return ECMD_FAILED; 463 } 464 } else { 465 if (!str_list_del(&vg->tags, tag)) { 466 log_error("Failed to remove tag %s from volume group " 467 "%s", tag, vg->name); 468 return ECMD_FAILED; 469 } 470 } 471 472 if (!vg_write(vg) || !vg_commit(vg)) 473 return ECMD_FAILED; 474 475 backup(vg); 476 477 log_print("Volume group \"%s\" successfully changed", vg->name); 478 479 return ECMD_PROCESSED; 480 } 481 482 static int _vgchange_uuid(struct cmd_context *cmd __attribute((unused)), 483 struct volume_group *vg) 484 { 485 struct lv_list *lvl; 486 487 if (lvs_in_vg_activated(vg)) { 488 log_error("Volume group has active logical volumes"); 489 return ECMD_FAILED; 490 } 491 492 if (!archive(vg)) 493 return ECMD_FAILED; 494 495 if (!id_create(&vg->id)) { 496 log_error("Failed to generate new random UUID for VG %s.", 497 vg->name); 498 return ECMD_FAILED; 499 } 500 501 dm_list_iterate_items(lvl, &vg->lvs) { 502 memcpy(&lvl->lv->lvid, &vg->id, sizeof(vg->id)); 503 } 504 505 if (!vg_write(vg) || !vg_commit(vg)) 506 return ECMD_FAILED; 507 508 backup(vg); 509 510 log_print("Volume group \"%s\" successfully changed", vg->name); 511 512 return ECMD_PROCESSED; 513 } 514 515 static int _vgchange_refresh(struct cmd_context *cmd, struct volume_group *vg) 516 { 517 log_verbose("Refreshing volume group \"%s\"", vg->name); 518 519 if (!vg_refresh_visible(cmd, vg)) 520 return ECMD_FAILED; 521 522 return ECMD_PROCESSED; 523 } 524 525 static int vgchange_single(struct cmd_context *cmd, const char *vg_name, 526 struct volume_group *vg, int consistent, 527 void *handle __attribute((unused))) 528 { 529 int r = ECMD_FAILED; 530 531 if (!vg) { 532 log_error("Unable to find volume group \"%s\"", vg_name); 533 return ECMD_FAILED; 534 } 535 536 if (!consistent) { 537 unlock_vg(cmd, vg_name); 538 dev_close_all(); 539 log_error("Volume group \"%s\" inconsistent", vg_name); 540 if (!(vg = recover_vg(cmd, vg_name, LCK_VG_WRITE))) 541 return ECMD_FAILED; 542 } 543 544 if (!(vg_status(vg) & LVM_WRITE) && !arg_count(cmd, available_ARG)) { 545 log_error("Volume group \"%s\" is read-only", vg->name); 546 return ECMD_FAILED; 547 } 548 549 if (vg_status(vg) & EXPORTED_VG) { 550 log_error("Volume group \"%s\" is exported", vg_name); 551 return ECMD_FAILED; 552 } 553 554 init_dmeventd_monitor(arg_int_value(cmd, monitor_ARG, 555 (is_static() || arg_count(cmd, ignoremonitoring_ARG)) ? 556 DMEVENTD_MONITOR_IGNORE : DEFAULT_DMEVENTD_MONITOR)); 557 558 if (arg_count(cmd, available_ARG)) 559 r = _vgchange_available(cmd, vg); 560 561 else if (arg_count(cmd, monitor_ARG)) 562 r = _vgchange_monitoring(cmd, vg); 563 564 else if (arg_count(cmd, resizeable_ARG)) 565 r = _vgchange_resizeable(cmd, vg); 566 567 else if (arg_count(cmd, logicalvolume_ARG)) 568 r = _vgchange_logicalvolume(cmd, vg); 569 570 else if (arg_count(cmd, maxphysicalvolumes_ARG)) 571 r = _vgchange_physicalvolumes(cmd, vg); 572 573 else if (arg_count(cmd, addtag_ARG)) 574 r = _vgchange_tag(cmd, vg, addtag_ARG); 575 576 else if (arg_count(cmd, deltag_ARG)) 577 r = _vgchange_tag(cmd, vg, deltag_ARG); 578 579 else if (arg_count(cmd, physicalextentsize_ARG)) 580 r = _vgchange_pesize(cmd, vg); 581 582 else if (arg_count(cmd, uuid_ARG)) 583 r = _vgchange_uuid(cmd, vg); 584 585 else if (arg_count(cmd, alloc_ARG)) 586 r = _vgchange_alloc(cmd, vg); 587 588 else if (arg_count(cmd, clustered_ARG)) 589 r = _vgchange_clustered(cmd, vg); 590 591 else if (arg_count(cmd, refresh_ARG)) 592 r = _vgchange_refresh(cmd, vg); 593 594 return r; 595 } 596 597 int vgchange(struct cmd_context *cmd, int argc, char **argv) 598 { 599 if (! 600 (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) + 601 arg_count(cmd, maxphysicalvolumes_ARG) + 602 arg_count(cmd, resizeable_ARG) + arg_count(cmd, deltag_ARG) + 603 arg_count(cmd, addtag_ARG) + arg_count(cmd, uuid_ARG) + 604 arg_count(cmd, physicalextentsize_ARG) + 605 arg_count(cmd, clustered_ARG) + arg_count(cmd, alloc_ARG) + 606 arg_count(cmd, monitor_ARG) + arg_count(cmd, refresh_ARG))) { 607 log_error("One of -a, -c, -l, -p, -s, -x, --refresh, " 608 "--uuid, --alloc, --addtag or --deltag required"); 609 return EINVALID_CMD_LINE; 610 } 611 612 /* FIXME Cope with several changes at once! */ 613 if (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) + 614 arg_count(cmd, maxphysicalvolumes_ARG) + 615 arg_count(cmd, resizeable_ARG) + arg_count(cmd, deltag_ARG) + 616 arg_count(cmd, addtag_ARG) + arg_count(cmd, alloc_ARG) + 617 arg_count(cmd, uuid_ARG) + arg_count(cmd, clustered_ARG) + 618 arg_count(cmd, physicalextentsize_ARG) > 1) { 619 log_error("Only one of -a, -c, -l, -p, -s, -x, --uuid, " 620 "--alloc, --addtag or --deltag allowed"); 621 return EINVALID_CMD_LINE; 622 } 623 624 if (arg_count(cmd, ignorelockingfailure_ARG) && 625 !arg_count(cmd, available_ARG)) { 626 log_error("--ignorelockingfailure only available with -a"); 627 return EINVALID_CMD_LINE; 628 } 629 630 if (arg_count(cmd, available_ARG) == 1 631 && arg_count(cmd, autobackup_ARG)) { 632 log_error("-A option not necessary with -a option"); 633 return EINVALID_CMD_LINE; 634 } 635 636 return process_each_vg(cmd, argc, argv, 637 (arg_count(cmd, available_ARG)) ? 638 LCK_VG_READ : LCK_VG_WRITE, 0, NULL, 639 &vgchange_single); 640 } 641