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