1 /* $NetBSD: vgsplit.c,v 1.1.1.2 2009/12/02 00:25:46 haad Exp $ */ 2 3 /* 4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. 5 * Copyright (C) 2004-2009 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 /* FIXME Why not (lv->vg == vg) ? */ 21 static int _lv_is_in_vg(struct volume_group *vg, struct logical_volume *lv) 22 { 23 struct lv_list *lvl; 24 25 dm_list_iterate_items(lvl, &vg->lvs) 26 if (lv == lvl->lv) 27 return 1; 28 29 return 0; 30 } 31 32 static int _move_one_lv(struct volume_group *vg_from, 33 struct volume_group *vg_to, 34 struct dm_list *lvh) 35 { 36 struct logical_volume *lv = dm_list_item(lvh, struct lv_list)->lv; 37 38 dm_list_move(&vg_to->lvs, lvh); 39 40 if (lv_is_active(lv)) { 41 log_error("Logical volume \"%s\" must be inactive", lv->name); 42 return 0; 43 } 44 45 return 1; 46 } 47 48 static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to) 49 { 50 struct dm_list *lvh, *lvht; 51 struct logical_volume *lv; 52 struct lv_segment *seg; 53 struct physical_volume *pv; 54 struct volume_group *vg_with; 55 unsigned s; 56 57 dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) { 58 lv = dm_list_item(lvh, struct lv_list)->lv; 59 60 if ((lv->status & SNAPSHOT)) 61 continue; 62 63 if ((lv->status & MIRRORED)) 64 continue; 65 66 /* Ensure all the PVs used by this LV remain in the same */ 67 /* VG as each other */ 68 vg_with = NULL; 69 dm_list_iterate_items(seg, &lv->segments) { 70 for (s = 0; s < seg->area_count; s++) { 71 /* FIXME Check AREA_LV too */ 72 if (seg_type(seg, s) != AREA_PV) 73 continue; 74 75 pv = seg_pv(seg, s); 76 if (vg_with) { 77 if (!pv_is_in_vg(vg_with, pv)) { 78 log_error("Can't split Logical " 79 "Volume %s between " 80 "two Volume Groups", 81 lv->name); 82 return 0; 83 } 84 continue; 85 } 86 87 if (pv_is_in_vg(vg_from, pv)) { 88 vg_with = vg_from; 89 continue; 90 } 91 if (pv_is_in_vg(vg_to, pv)) { 92 vg_with = vg_to; 93 continue; 94 } 95 log_error("Physical Volume %s not found", 96 pv_dev_name(pv)); 97 return 0; 98 } 99 100 } 101 102 if (vg_with == vg_from) 103 continue; 104 105 /* Move this LV */ 106 if (!_move_one_lv(vg_from, vg_to, lvh)) 107 return_0; 108 } 109 110 /* FIXME Ensure no LVs contain segs pointing at LVs in the other VG */ 111 112 return 1; 113 } 114 115 /* 116 * Move the hidden / internal "snapshotN" LVs.from 'vg_from' to 'vg_to'. 117 */ 118 static int _move_snapshots(struct volume_group *vg_from, 119 struct volume_group *vg_to) 120 { 121 struct dm_list *lvh, *lvht; 122 struct logical_volume *lv; 123 struct lv_segment *seg; 124 int cow_from = 0; 125 int origin_from = 0; 126 127 dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) { 128 lv = dm_list_item(lvh, struct lv_list)->lv; 129 130 if (!(lv->status & SNAPSHOT)) 131 continue; 132 133 dm_list_iterate_items(seg, &lv->segments) { 134 cow_from = _lv_is_in_vg(vg_from, seg->cow); 135 origin_from = _lv_is_in_vg(vg_from, seg->origin); 136 137 if (cow_from && origin_from) 138 continue; 139 if ((!cow_from && origin_from) || 140 (cow_from && !origin_from)) { 141 log_error("Can't split snapshot %s between" 142 " two Volume Groups", seg->cow->name); 143 return 0; 144 } 145 146 /* 147 * At this point, the cow and origin should already be 148 * in vg_to. 149 */ 150 if (_lv_is_in_vg(vg_to, seg->cow) && 151 _lv_is_in_vg(vg_to, seg->origin)) { 152 if (!_move_one_lv(vg_from, vg_to, lvh)) 153 return_0; 154 } 155 } 156 157 } 158 159 return 1; 160 } 161 162 static int _move_mirrors(struct volume_group *vg_from, 163 struct volume_group *vg_to) 164 { 165 struct dm_list *lvh, *lvht; 166 struct logical_volume *lv; 167 struct lv_segment *seg; 168 unsigned s, seg_in, log_in; 169 170 dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) { 171 lv = dm_list_item(lvh, struct lv_list)->lv; 172 173 if (!(lv->status & MIRRORED)) 174 continue; 175 176 seg = first_seg(lv); 177 178 seg_in = 0; 179 for (s = 0; s < seg->area_count; s++) 180 if (_lv_is_in_vg(vg_to, seg_lv(seg, s))) 181 seg_in++; 182 183 log_in = (!seg->log_lv || _lv_is_in_vg(vg_to, seg->log_lv)); 184 185 if ((seg_in && seg_in < seg->area_count) || 186 (seg_in && seg->log_lv && !log_in) || 187 (!seg_in && seg->log_lv && log_in)) { 188 log_error("Can't split mirror %s between " 189 "two Volume Groups", lv->name); 190 return 0; 191 } 192 193 if (seg_in == seg->area_count && log_in) { 194 if (!_move_one_lv(vg_from, vg_to, lvh)) 195 return_0; 196 } 197 } 198 199 return 1; 200 } 201 202 /* 203 * Create or open the destination of the vgsplit operation. 204 * Returns 205 * - non-NULL: VG handle w/VG lock held 206 * - NULL: no VG lock held 207 */ 208 static struct volume_group *_vgsplit_to(struct cmd_context *cmd, 209 const char *vg_name_to, 210 int *existing_vg) 211 { 212 struct volume_group *vg_to = NULL; 213 214 log_verbose("Checking for new volume group \"%s\"", vg_name_to); 215 /* 216 * First try to create a new VG. If we cannot create it, 217 * and we get FAILED_EXIST (we will not be holding a lock), 218 * a VG must already exist with this name. We then try to 219 * read the existing VG - the vgsplit will be into an existing VG. 220 * 221 * Otherwise, if the lock was successful, it must be the case that 222 * we obtained a WRITE lock and could not find the vgname in the 223 * system. Thus, the split will be into a new VG. 224 */ 225 vg_to = vg_create(cmd, vg_name_to); 226 if (vg_read_error(vg_to) == FAILED_LOCKING) { 227 log_error("Can't get lock for %s", vg_name_to); 228 vg_release(vg_to); 229 return NULL; 230 } 231 if (vg_read_error(vg_to) == FAILED_EXIST) { 232 *existing_vg = 1; 233 vg_release(vg_to); 234 vg_to = vg_read_for_update(cmd, vg_name_to, NULL, 0); 235 236 if (vg_read_error(vg_to)) { 237 vg_release(vg_to); 238 stack; 239 return NULL; 240 } 241 242 } else if (vg_read_error(vg_to) == SUCCESS) { 243 *existing_vg = 0; 244 } 245 return vg_to; 246 } 247 248 /* 249 * Open the source of the vgsplit operation. 250 * Returns 251 * - non-NULL: VG handle w/VG lock held 252 * - NULL: no VG lock held 253 */ 254 static struct volume_group *_vgsplit_from(struct cmd_context *cmd, 255 const char *vg_name_from) 256 { 257 struct volume_group *vg_from; 258 259 log_verbose("Checking for volume group \"%s\"", vg_name_from); 260 261 vg_from = vg_read_for_update(cmd, vg_name_from, NULL, 0); 262 if (vg_read_error(vg_from)) { 263 vg_release(vg_from); 264 return NULL; 265 } 266 return vg_from; 267 } 268 269 /* 270 * Has the user given an option related to a new vg as the split destination? 271 */ 272 static int new_vg_option_specified(struct cmd_context *cmd) 273 { 274 return(arg_count(cmd, clustered_ARG) || 275 arg_count(cmd, alloc_ARG) || 276 arg_count(cmd, maxphysicalvolumes_ARG) || 277 arg_count(cmd, maxlogicalvolumes_ARG)); 278 } 279 280 int vgsplit(struct cmd_context *cmd, int argc, char **argv) 281 { 282 struct vgcreate_params vp_new; 283 struct vgcreate_params vp_def; 284 char *vg_name_from, *vg_name_to; 285 struct volume_group *vg_to = NULL, *vg_from = NULL; 286 int opt; 287 int existing_vg = 0; 288 int r = ECMD_FAILED; 289 const char *lv_name; 290 int lock_vg_from_first = 1; 291 292 if ((arg_count(cmd, name_ARG) + argc) < 3) { 293 log_error("Existing VG, new VG and either physical volumes " 294 "or logical volume required."); 295 return EINVALID_CMD_LINE; 296 } 297 298 if (arg_count(cmd, name_ARG) && (argc > 2)) { 299 log_error("A logical volume name cannot be given with " 300 "physical volumes."); 301 return ECMD_FAILED; 302 } 303 304 if (arg_count(cmd, name_ARG)) 305 lv_name = arg_value(cmd, name_ARG); 306 else 307 lv_name = NULL; 308 309 vg_name_from = skip_dev_dir(cmd, argv[0], NULL); 310 vg_name_to = skip_dev_dir(cmd, argv[1], NULL); 311 argc -= 2; 312 argv += 2; 313 314 if (!strcmp(vg_name_to, vg_name_from)) { 315 log_error("Duplicate volume group name \"%s\"", vg_name_from); 316 return ECMD_FAILED; 317 } 318 319 if (strcmp(vg_name_to, vg_name_from) < 0) 320 lock_vg_from_first = 0; 321 322 if (lock_vg_from_first) { 323 vg_from = _vgsplit_from(cmd, vg_name_from); 324 if (!vg_from) { 325 stack; 326 return ECMD_FAILED; 327 } 328 /* 329 * Set metadata format of original VG. 330 * NOTE: We must set the format before calling vg_create() 331 * since vg_create() calls the per-format constructor. 332 */ 333 cmd->fmt = vg_from->fid->fmt; 334 335 vg_to = _vgsplit_to(cmd, vg_name_to, &existing_vg); 336 if (!vg_to) { 337 unlock_and_release_vg(cmd, vg_from, vg_name_from); 338 stack; 339 return ECMD_FAILED; 340 } 341 } else { 342 vg_to = _vgsplit_to(cmd, vg_name_to, &existing_vg); 343 if (!vg_to) { 344 stack; 345 return ECMD_FAILED; 346 } 347 vg_from = _vgsplit_from(cmd, vg_name_from); 348 if (!vg_from) { 349 unlock_and_release_vg(cmd, vg_to, vg_name_to); 350 stack; 351 return ECMD_FAILED; 352 } 353 354 if (cmd->fmt != vg_from->fid->fmt) { 355 /* In this case we don't know the vg_from->fid->fmt */ 356 log_error("Unable to set new VG metadata type based on " 357 "source VG format - use -M option."); 358 goto bad; 359 } 360 } 361 362 if (existing_vg) { 363 if (new_vg_option_specified(cmd)) { 364 log_error("Volume group \"%s\" exists, but new VG " 365 "option specified", vg_name_to); 366 goto bad; 367 } 368 if (!vgs_are_compatible(cmd, vg_from,vg_to)) 369 goto_bad; 370 } else { 371 vgcreate_params_set_defaults(&vp_def, vg_from); 372 vp_def.vg_name = vg_name_to; 373 if (vgcreate_params_set_from_args(cmd, &vp_new, &vp_def)) { 374 r = EINVALID_CMD_LINE; 375 goto_bad; 376 } 377 378 if (vgcreate_params_validate(cmd, &vp_new)) { 379 r = EINVALID_CMD_LINE; 380 goto_bad; 381 } 382 383 if (!vg_set_extent_size(vg_to, vp_new.extent_size) || 384 !vg_set_max_lv(vg_to, vp_new.max_lv) || 385 !vg_set_max_pv(vg_to, vp_new.max_pv) || 386 !vg_set_alloc_policy(vg_to, vp_new.alloc) || 387 !vg_set_clustered(vg_to, vp_new.clustered)) 388 goto_bad; 389 } 390 391 /* Archive vg_from before changing it */ 392 if (!archive(vg_from)) 393 goto_bad; 394 395 /* Move PVs across to new structure */ 396 for (opt = 0; opt < argc; opt++) { 397 if (!move_pv(vg_from, vg_to, argv[opt])) 398 goto_bad; 399 } 400 401 /* If an LV given on the cmdline, move used_by PVs */ 402 if (lv_name && !move_pvs_used_by_lv(vg_from, vg_to, lv_name)) 403 goto_bad; 404 405 /* Move required LVs across, checking consistency */ 406 if (!(_move_lvs(vg_from, vg_to))) 407 goto_bad; 408 409 /* FIXME Separate the 'move' from the 'validation' to fix dev stacks */ 410 /* Move required mirrors across */ 411 if (!(_move_mirrors(vg_from, vg_to))) 412 goto_bad; 413 414 /* Move required snapshots across */ 415 if (!(_move_snapshots(vg_from, vg_to))) 416 goto_bad; 417 418 /* Split metadata areas and check if both vgs have at least one area */ 419 if (!(vg_split_mdas(cmd, vg_from, vg_to)) && vg_from->pv_count) { 420 log_error("Cannot split: Nowhere to store metadata for new Volume Group"); 421 goto bad; 422 } 423 424 /* Set proper name for all PVs in new VG */ 425 if (!vg_rename(cmd, vg_to, vg_name_to)) 426 goto_bad; 427 428 /* store it on disks */ 429 log_verbose("Writing out updated volume groups"); 430 431 /* 432 * First, write out the new VG as EXPORTED. We do this first in case 433 * there is a crash - we will still have the new VG information, in an 434 * exported state. Recovery after this point would be removal of the 435 * new VG and redoing the vgsplit. 436 * FIXME: recover automatically or instruct the user? 437 */ 438 vg_to->status |= EXPORTED_VG; 439 440 if (!archive(vg_to)) 441 goto_bad; 442 443 if (!vg_write(vg_to) || !vg_commit(vg_to)) 444 goto_bad; 445 446 backup(vg_to); 447 448 /* 449 * Next, write out the updated old VG. If we crash after this point, 450 * recovery is a vgimport on the new VG. 451 * FIXME: recover automatically or instruct the user? 452 */ 453 if (vg_from->pv_count) { 454 if (!vg_write(vg_from) || !vg_commit(vg_from)) 455 goto_bad; 456 457 backup(vg_from); 458 } 459 460 /* 461 * Finally, remove the EXPORTED flag from the new VG and write it out. 462 */ 463 if (!test_mode()) { 464 vg_release(vg_to); 465 vg_to = vg_read_for_update(cmd, vg_name_to, NULL, 466 READ_ALLOW_EXPORTED); 467 if (vg_read_error(vg_to)) { 468 log_error("Volume group \"%s\" became inconsistent: " 469 "please fix manually", vg_name_to); 470 goto bad; 471 } 472 } 473 474 vg_to->status &= ~EXPORTED_VG; 475 476 if (!vg_write(vg_to) || !vg_commit(vg_to)) 477 goto_bad; 478 479 backup(vg_to); 480 481 log_print("%s volume group \"%s\" successfully split from \"%s\"", 482 existing_vg ? "Existing" : "New", 483 vg_to->name, vg_from->name); 484 485 r = ECMD_PROCESSED; 486 487 bad: 488 if (lock_vg_from_first) { 489 unlock_and_release_vg(cmd, vg_to, vg_name_to); 490 unlock_and_release_vg(cmd, vg_from, vg_name_from); 491 } else { 492 unlock_and_release_vg(cmd, vg_from, vg_name_from); 493 unlock_and_release_vg(cmd, vg_to, vg_name_to); 494 } 495 return r; 496 } 497