1 1.1 haad /* $NetBSD: pvmove.c,v 1.1.1.2 2009/12/02 00:25:54 haad Exp $ */ 2 1.1 haad 3 1.1 haad /* 4 1.1 haad * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. 5 1.1 haad * Copyright (C) 2004-2007 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 #include "polldaemon.h" 20 1.1 haad #include "display.h" 21 1.1 haad 22 1.1 haad #define PVMOVE_FIRST_TIME 0x00000001 /* Called for first time */ 23 1.1 haad 24 1.1 haad static int _pvmove_target_present(struct cmd_context *cmd, int clustered) 25 1.1 haad { 26 1.1 haad const struct segment_type *segtype; 27 1.1 haad unsigned attr = 0; 28 1.1 haad int found = 1; 29 1.1 haad static int _clustered_found = -1; 30 1.1 haad 31 1.1 haad if (clustered && _clustered_found >= 0) 32 1.1 haad return _clustered_found; 33 1.1 haad 34 1.1 haad if (!(segtype = get_segtype_from_string(cmd, "mirror"))) 35 1.1 haad return_0; 36 1.1 haad 37 1.1 haad if (activation() && segtype->ops->target_present && 38 1.1.1.2 haad !segtype->ops->target_present(cmd, NULL, clustered ? &attr : NULL)) 39 1.1 haad found = 0; 40 1.1 haad 41 1.1 haad if (activation() && clustered) { 42 1.1 haad if (found && (attr & MIRROR_LOG_CLUSTERED)) 43 1.1 haad _clustered_found = found = 1; 44 1.1 haad else 45 1.1 haad _clustered_found = found = 0; 46 1.1 haad } 47 1.1 haad 48 1.1 haad return found; 49 1.1 haad } 50 1.1 haad 51 1.1 haad static unsigned _pvmove_is_exclusive(struct cmd_context *cmd, 52 1.1 haad struct volume_group *vg) 53 1.1 haad { 54 1.1 haad if (vg_is_clustered(vg)) 55 1.1 haad if (!_pvmove_target_present(cmd, 1)) 56 1.1 haad return 1; 57 1.1 haad 58 1.1 haad return 0; 59 1.1 haad } 60 1.1 haad 61 1.1 haad /* Allow /dev/vgname/lvname, vgname/lvname or lvname */ 62 1.1 haad static const char *_extract_lvname(struct cmd_context *cmd, const char *vgname, 63 1.1 haad const char *arg) 64 1.1 haad { 65 1.1 haad const char *lvname; 66 1.1 haad 67 1.1 haad /* Is an lvname supplied directly? */ 68 1.1 haad if (!strchr(arg, '/')) 69 1.1 haad return arg; 70 1.1 haad 71 1.1 haad lvname = skip_dev_dir(cmd, arg, NULL); 72 1.1 haad while (*lvname == '/') 73 1.1 haad lvname++; 74 1.1 haad if (!strchr(lvname, '/')) { 75 1.1 haad log_error("--name takes a logical volume name"); 76 1.1 haad return NULL; 77 1.1 haad } 78 1.1 haad if (strncmp(vgname, lvname, strlen(vgname)) || 79 1.1 haad (lvname += strlen(vgname), *lvname != '/')) { 80 1.1 haad log_error("Named LV and old PV must be in the same VG"); 81 1.1 haad return NULL; 82 1.1 haad } 83 1.1 haad while (*lvname == '/') 84 1.1 haad lvname++; 85 1.1 haad if (!*lvname) { 86 1.1 haad log_error("Incomplete LV name supplied with --name"); 87 1.1 haad return NULL; 88 1.1 haad } 89 1.1 haad return lvname; 90 1.1 haad } 91 1.1 haad 92 1.1 haad static struct volume_group *_get_vg(struct cmd_context *cmd, const char *vgname) 93 1.1 haad { 94 1.1 haad dev_close_all(); 95 1.1 haad 96 1.1.1.2 haad return vg_read_for_update(cmd, vgname, NULL, 0); 97 1.1 haad } 98 1.1 haad 99 1.1 haad /* Create list of PVs for allocation of replacement extents */ 100 1.1 haad static struct dm_list *_get_allocatable_pvs(struct cmd_context *cmd, int argc, 101 1.1 haad char **argv, struct volume_group *vg, 102 1.1 haad struct physical_volume *pv, 103 1.1 haad alloc_policy_t alloc) 104 1.1 haad { 105 1.1 haad struct dm_list *allocatable_pvs, *pvht, *pvh; 106 1.1 haad struct pv_list *pvl; 107 1.1 haad 108 1.1 haad if (argc) 109 1.1 haad allocatable_pvs = create_pv_list(cmd->mem, vg, argc, argv, 1); 110 1.1 haad else 111 1.1 haad allocatable_pvs = clone_pv_list(cmd->mem, &vg->pvs); 112 1.1 haad 113 1.1 haad if (!allocatable_pvs) 114 1.1 haad return_NULL; 115 1.1 haad 116 1.1 haad dm_list_iterate_safe(pvh, pvht, allocatable_pvs) { 117 1.1 haad pvl = dm_list_item(pvh, struct pv_list); 118 1.1 haad 119 1.1 haad /* Don't allocate onto the PV we're clearing! */ 120 1.1 haad if ((alloc != ALLOC_ANYWHERE) && (pvl->pv->dev == pv_dev(pv))) { 121 1.1 haad dm_list_del(&pvl->list); 122 1.1 haad continue; 123 1.1 haad } 124 1.1 haad 125 1.1 haad /* Remove PV if full */ 126 1.1 haad if ((pvl->pv->pe_count == pvl->pv->pe_alloc_count)) 127 1.1 haad dm_list_del(&pvl->list); 128 1.1 haad } 129 1.1 haad 130 1.1 haad if (dm_list_empty(allocatable_pvs)) { 131 1.1 haad log_error("No extents available for allocation"); 132 1.1 haad return NULL; 133 1.1 haad } 134 1.1 haad 135 1.1 haad return allocatable_pvs; 136 1.1 haad } 137 1.1 haad 138 1.1 haad /* 139 1.1 haad * Replace any LV segments on given PV with temporary mirror. 140 1.1 haad * Returns list of LVs changed. 141 1.1 haad */ 142 1.1 haad static int _insert_pvmove_mirrors(struct cmd_context *cmd, 143 1.1 haad struct logical_volume *lv_mirr, 144 1.1 haad struct dm_list *source_pvl, 145 1.1 haad struct logical_volume *lv, 146 1.1 haad struct dm_list *lvs_changed) 147 1.1 haad 148 1.1 haad { 149 1.1 haad struct pv_list *pvl; 150 1.1 haad uint32_t prev_le_count; 151 1.1 haad 152 1.1 haad /* Only 1 PV may feature in source_pvl */ 153 1.1 haad pvl = dm_list_item(source_pvl->n, struct pv_list); 154 1.1 haad 155 1.1 haad prev_le_count = lv_mirr->le_count; 156 1.1 haad if (!insert_layer_for_segments_on_pv(cmd, lv, lv_mirr, PVMOVE, 157 1.1 haad pvl, lvs_changed)) 158 1.1 haad return_0; 159 1.1 haad 160 1.1 haad /* check if layer was inserted */ 161 1.1 haad if (lv_mirr->le_count - prev_le_count) { 162 1.1 haad lv->status |= LOCKED; 163 1.1 haad 164 1.1 haad log_verbose("Moving %u extents of logical volume %s/%s", 165 1.1 haad lv_mirr->le_count - prev_le_count, 166 1.1 haad lv->vg->name, lv->name); 167 1.1 haad } 168 1.1 haad 169 1.1 haad return 1; 170 1.1 haad } 171 1.1 haad 172 1.1 haad /* Create new LV with mirror segments for the required copies */ 173 1.1 haad static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd, 174 1.1 haad struct volume_group *vg, 175 1.1 haad struct dm_list *source_pvl, 176 1.1 haad const char *lv_name, 177 1.1 haad struct dm_list *allocatable_pvs, 178 1.1 haad alloc_policy_t alloc, 179 1.1 haad struct dm_list **lvs_changed) 180 1.1 haad { 181 1.1 haad struct logical_volume *lv_mirr, *lv; 182 1.1 haad struct lv_list *lvl; 183 1.1 haad uint32_t log_count = 0; 184 1.1 haad int lv_found = 0; 185 1.1 haad 186 1.1 haad /* FIXME Cope with non-contiguous => splitting existing segments */ 187 1.1 haad if (!(lv_mirr = lv_create_empty("pvmove%d", NULL, 188 1.1 haad LVM_READ | LVM_WRITE, 189 1.1.1.2 haad ALLOC_CONTIGUOUS, vg))) { 190 1.1 haad log_error("Creation of temporary pvmove LV failed"); 191 1.1 haad return NULL; 192 1.1 haad } 193 1.1 haad 194 1.1 haad lv_mirr->status |= (PVMOVE | LOCKED); 195 1.1 haad 196 1.1 haad if (!(*lvs_changed = dm_pool_alloc(cmd->mem, sizeof(**lvs_changed)))) { 197 1.1 haad log_error("lvs_changed list struct allocation failed"); 198 1.1 haad return NULL; 199 1.1 haad } 200 1.1 haad 201 1.1 haad dm_list_init(*lvs_changed); 202 1.1 haad 203 1.1 haad /* Find segments to be moved and set up mirrors */ 204 1.1 haad dm_list_iterate_items(lvl, &vg->lvs) { 205 1.1 haad lv = lvl->lv; 206 1.1 haad if ((lv == lv_mirr)) 207 1.1 haad continue; 208 1.1 haad if (lv_name) { 209 1.1 haad if (strcmp(lv->name, lv_name)) 210 1.1 haad continue; 211 1.1 haad lv_found = 1; 212 1.1 haad } 213 1.1 haad if (lv_is_origin(lv) || lv_is_cow(lv)) { 214 1.1 haad log_print("Skipping snapshot-related LV %s", lv->name); 215 1.1 haad continue; 216 1.1 haad } 217 1.1 haad if (lv->status & MIRRORED) { 218 1.1 haad log_print("Skipping mirror LV %s", lv->name); 219 1.1 haad continue; 220 1.1 haad } 221 1.1 haad if (lv->status & MIRROR_LOG) { 222 1.1 haad log_print("Skipping mirror log LV %s", lv->name); 223 1.1 haad continue; 224 1.1 haad } 225 1.1 haad if (lv->status & MIRROR_IMAGE) { 226 1.1 haad log_print("Skipping mirror image LV %s", lv->name); 227 1.1 haad continue; 228 1.1 haad } 229 1.1 haad if (lv->status & LOCKED) { 230 1.1 haad log_print("Skipping locked LV %s", lv->name); 231 1.1 haad continue; 232 1.1 haad } 233 1.1 haad if (!_insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv, 234 1.1 haad *lvs_changed)) 235 1.1 haad return_NULL; 236 1.1 haad } 237 1.1 haad 238 1.1 haad if (lv_name && !lv_found) { 239 1.1 haad log_error("Logical volume %s not found.", lv_name); 240 1.1 haad return NULL; 241 1.1 haad } 242 1.1 haad 243 1.1 haad /* Is temporary mirror empty? */ 244 1.1 haad if (!lv_mirr->le_count) { 245 1.1 haad log_error("No data to move for %s", vg->name); 246 1.1 haad return NULL; 247 1.1 haad } 248 1.1 haad 249 1.1 haad if (!lv_add_mirrors(cmd, lv_mirr, 1, 1, 0, log_count, 250 1.1 haad allocatable_pvs, alloc, MIRROR_BY_SEG)) { 251 1.1 haad log_error("Failed to convert pvmove LV to mirrored"); 252 1.1 haad return_NULL; 253 1.1 haad } 254 1.1 haad 255 1.1 haad if (!split_parent_segments_for_layer(cmd, lv_mirr)) { 256 1.1 haad log_error("Failed to split segments being moved"); 257 1.1 haad return_NULL; 258 1.1 haad } 259 1.1 haad 260 1.1 haad return lv_mirr; 261 1.1 haad } 262 1.1 haad 263 1.1 haad static int _activate_lv(struct cmd_context *cmd, struct logical_volume *lv_mirr, 264 1.1 haad unsigned exclusive) 265 1.1 haad { 266 1.1 haad if (exclusive) 267 1.1 haad return activate_lv_excl(cmd, lv_mirr); 268 1.1 haad 269 1.1 haad return activate_lv(cmd, lv_mirr); 270 1.1 haad } 271 1.1 haad 272 1.1.1.2 haad static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg, 273 1.1.1.2 haad struct logical_volume *lv_mirr, 274 1.1.1.2 haad struct dm_list *lvs_changed); 275 1.1.1.2 haad 276 1.1 haad static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg, 277 1.1 haad struct logical_volume *lv_mirr, 278 1.1 haad struct dm_list *lvs_changed, unsigned flags) 279 1.1 haad { 280 1.1 haad unsigned exclusive = _pvmove_is_exclusive(cmd, vg); 281 1.1 haad unsigned first_time = (flags & PVMOVE_FIRST_TIME) ? 1 : 0; 282 1.1.1.2 haad int r = 0; 283 1.1 haad 284 1.1 haad log_verbose("Updating volume group metadata"); 285 1.1 haad if (!vg_write(vg)) { 286 1.1 haad log_error("ABORTING: Volume group metadata update failed."); 287 1.1 haad return 0; 288 1.1 haad } 289 1.1 haad 290 1.1 haad /* Suspend lvs_changed */ 291 1.1 haad if (!suspend_lvs(cmd, lvs_changed)) 292 1.1.1.2 haad goto_out; 293 1.1 haad 294 1.1 haad /* Suspend mirrors on subsequent calls */ 295 1.1 haad if (!first_time) { 296 1.1 haad if (!suspend_lv(cmd, lv_mirr)) { 297 1.1 haad resume_lvs(cmd, lvs_changed); 298 1.1 haad vg_revert(vg); 299 1.1.1.2 haad goto_out; 300 1.1 haad } 301 1.1 haad } 302 1.1 haad 303 1.1 haad /* Commit on-disk metadata */ 304 1.1 haad if (!vg_commit(vg)) { 305 1.1 haad log_error("ABORTING: Volume group metadata update failed."); 306 1.1 haad if (!first_time) 307 1.1 haad resume_lv(cmd, lv_mirr); 308 1.1 haad resume_lvs(cmd, lvs_changed); 309 1.1.1.2 haad goto out; 310 1.1 haad } 311 1.1 haad 312 1.1 haad /* Activate the temporary mirror LV */ 313 1.1 haad /* Only the first mirror segment gets activated as a mirror */ 314 1.1 haad /* FIXME: Add option to use a log */ 315 1.1 haad if (first_time) { 316 1.1 haad if (!_activate_lv(cmd, lv_mirr, exclusive)) { 317 1.1.1.2 haad if (test_mode()) 318 1.1.1.2 haad goto out; 319 1.1.1.2 haad 320 1.1.1.2 haad /* 321 1.1.1.2 haad * Nothing changed yet, try to revert pvmove. 322 1.1.1.2 haad */ 323 1.1.1.2 haad log_error("Temporary pvmove mirror activation failed."); 324 1.1.1.2 haad if (!_finish_pvmove(cmd, vg, lv_mirr, lvs_changed)) 325 1.1.1.2 haad log_error("ABORTING: Restoring original configuration " 326 1.1.1.2 haad "before pvmove failed. Run pvmove --abort."); 327 1.1.1.2 haad goto out; 328 1.1 haad } 329 1.1 haad } else if (!resume_lv(cmd, lv_mirr)) { 330 1.1 haad log_error("Unable to reactivate logical volume \"%s\"", 331 1.1 haad lv_mirr->name); 332 1.1 haad resume_lvs(cmd, lvs_changed); 333 1.1.1.2 haad goto out; 334 1.1 haad } 335 1.1 haad 336 1.1 haad /* Unsuspend LVs */ 337 1.1 haad if (!resume_lvs(cmd, lvs_changed)) { 338 1.1 haad log_error("Unable to resume logical volumes"); 339 1.1.1.2 haad goto out; 340 1.1 haad } 341 1.1 haad 342 1.1.1.2 haad r = 1; 343 1.1.1.2 haad out: 344 1.1.1.2 haad backup(vg); 345 1.1.1.2 haad return r; 346 1.1 haad } 347 1.1 haad 348 1.1 haad static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name, 349 1.1 haad int argc, char **argv) 350 1.1 haad { 351 1.1 haad const char *lv_name = NULL; 352 1.1 haad char *pv_name_arg; 353 1.1 haad struct volume_group *vg; 354 1.1 haad struct dm_list *source_pvl; 355 1.1 haad struct dm_list *allocatable_pvs; 356 1.1 haad alloc_policy_t alloc; 357 1.1 haad struct dm_list *lvs_changed; 358 1.1 haad struct physical_volume *pv; 359 1.1 haad struct logical_volume *lv_mirr; 360 1.1 haad unsigned first_time = 1; 361 1.1 haad unsigned exclusive; 362 1.1.1.2 haad int r = ECMD_FAILED; 363 1.1 haad 364 1.1 haad pv_name_arg = argv[0]; 365 1.1 haad argc--; 366 1.1 haad argv++; 367 1.1 haad 368 1.1 haad /* Find PV (in VG) */ 369 1.1 haad if (!(pv = find_pv_by_name(cmd, pv_name))) { 370 1.1 haad stack; 371 1.1 haad return EINVALID_CMD_LINE; 372 1.1 haad } 373 1.1 haad 374 1.1 haad if (arg_count(cmd, name_ARG)) { 375 1.1 haad if (!(lv_name = _extract_lvname(cmd, pv_vg_name(pv), 376 1.1 haad arg_value(cmd, name_ARG)))) { 377 1.1 haad stack; 378 1.1 haad return EINVALID_CMD_LINE; 379 1.1 haad } 380 1.1 haad 381 1.1 haad if (!validate_name(lv_name)) { 382 1.1 haad log_error("Logical volume name %s is invalid", lv_name); 383 1.1 haad return EINVALID_CMD_LINE; 384 1.1 haad } 385 1.1 haad } 386 1.1 haad 387 1.1 haad /* Read VG */ 388 1.1 haad log_verbose("Finding volume group \"%s\"", pv_vg_name(pv)); 389 1.1 haad 390 1.1.1.2 haad vg = _get_vg(cmd, pv_vg_name(pv)); 391 1.1.1.2 haad if (vg_read_error(vg)) { 392 1.1.1.2 haad vg_release(vg); 393 1.1 haad stack; 394 1.1 haad return ECMD_FAILED; 395 1.1 haad } 396 1.1 haad 397 1.1 haad exclusive = _pvmove_is_exclusive(cmd, vg); 398 1.1 haad 399 1.1 haad if ((lv_mirr = find_pvmove_lv(vg, pv_dev(pv), PVMOVE))) { 400 1.1 haad log_print("Detected pvmove in progress for %s", pv_name); 401 1.1 haad if (argc || lv_name) 402 1.1 haad log_error("Ignoring remaining command line arguments"); 403 1.1 haad 404 1.1 haad if (!(lvs_changed = lvs_using_lv(cmd, vg, lv_mirr))) { 405 1.1.1.2 haad log_error("ABORTING: Failed to generate list of moving LVs"); 406 1.1.1.2 haad goto out; 407 1.1 haad } 408 1.1 haad 409 1.1 haad /* Ensure mirror LV is active */ 410 1.1 haad if (!_activate_lv(cmd, lv_mirr, exclusive)) { 411 1.1.1.2 haad log_error("ABORTING: Temporary mirror activation failed."); 412 1.1.1.2 haad goto out; 413 1.1 haad } 414 1.1 haad 415 1.1 haad first_time = 0; 416 1.1 haad } else { 417 1.1 haad /* Determine PE ranges to be moved */ 418 1.1 haad if (!(source_pvl = create_pv_list(cmd->mem, vg, 1, 419 1.1.1.2 haad &pv_name_arg, 0))) 420 1.1.1.2 haad goto_out; 421 1.1 haad 422 1.1 haad alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT); 423 1.1 haad if (alloc == ALLOC_INHERIT) 424 1.1 haad alloc = vg->alloc; 425 1.1 haad 426 1.1 haad /* Get PVs we can use for allocation */ 427 1.1 haad if (!(allocatable_pvs = _get_allocatable_pvs(cmd, argc, argv, 428 1.1.1.2 haad vg, pv, alloc))) 429 1.1.1.2 haad goto_out; 430 1.1 haad 431 1.1.1.2 haad if (!archive(vg)) 432 1.1.1.2 haad goto_out; 433 1.1 haad 434 1.1 haad if (!(lv_mirr = _set_up_pvmove_lv(cmd, vg, source_pvl, lv_name, 435 1.1 haad allocatable_pvs, alloc, 436 1.1.1.2 haad &lvs_changed))) 437 1.1.1.2 haad goto_out; 438 1.1 haad } 439 1.1 haad 440 1.1 haad /* Lock lvs_changed and activate (with old metadata) */ 441 1.1.1.2 haad if (!activate_lvs(cmd, lvs_changed, exclusive)) 442 1.1.1.2 haad goto_out; 443 1.1 haad 444 1.1 haad /* FIXME Presence of a mirror once set PVMOVE - now remove associated logic */ 445 1.1 haad /* init_pvmove(1); */ 446 1.1 haad /* vg->status |= PVMOVE; */ 447 1.1 haad 448 1.1 haad if (first_time) { 449 1.1 haad if (!_update_metadata 450 1.1.1.2 haad (cmd, vg, lv_mirr, lvs_changed, PVMOVE_FIRST_TIME)) 451 1.1.1.2 haad goto_out; 452 1.1 haad } 453 1.1 haad 454 1.1 haad /* LVs are all in status LOCKED */ 455 1.1.1.2 haad r = ECMD_PROCESSED; 456 1.1.1.2 haad out: 457 1.1.1.2 haad unlock_and_release_vg(cmd, vg, pv_vg_name(pv)); 458 1.1.1.2 haad return r; 459 1.1 haad } 460 1.1 haad 461 1.1 haad static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg, 462 1.1 haad struct logical_volume *lv_mirr, 463 1.1 haad struct dm_list *lvs_changed) 464 1.1 haad { 465 1.1 haad int r = 1; 466 1.1 haad struct dm_list lvs_completed; 467 1.1 haad struct lv_list *lvl; 468 1.1 haad 469 1.1 haad /* Update metadata to remove mirror segments and break dependencies */ 470 1.1 haad dm_list_init(&lvs_completed); 471 1.1 haad if (!lv_remove_mirrors(cmd, lv_mirr, 1, 0, NULL, PVMOVE) || 472 1.1 haad !remove_layers_for_segments_all(cmd, lv_mirr, PVMOVE, 473 1.1 haad &lvs_completed)) { 474 1.1 haad log_error("ABORTING: Removal of temporary mirror failed"); 475 1.1 haad return 0; 476 1.1 haad } 477 1.1 haad 478 1.1 haad dm_list_iterate_items(lvl, &lvs_completed) 479 1.1 haad /* FIXME Assumes only one pvmove at a time! */ 480 1.1 haad lvl->lv->status &= ~LOCKED; 481 1.1 haad 482 1.1 haad /* Store metadata without dependencies on mirror segments */ 483 1.1 haad if (!vg_write(vg)) { 484 1.1 haad log_error("ABORTING: Failed to write new data locations " 485 1.1 haad "to disk."); 486 1.1 haad return 0; 487 1.1 haad } 488 1.1 haad 489 1.1 haad /* Suspend LVs changed */ 490 1.1 haad if (!suspend_lvs(cmd, lvs_changed)) { 491 1.1 haad log_error("Locking LVs to remove temporary mirror failed"); 492 1.1 haad r = 0; 493 1.1 haad } 494 1.1 haad 495 1.1 haad /* Suspend mirror LV to flush pending I/O */ 496 1.1 haad if (!suspend_lv(cmd, lv_mirr)) { 497 1.1 haad log_error("Suspension of temporary mirror LV failed"); 498 1.1 haad r = 0; 499 1.1 haad } 500 1.1 haad 501 1.1 haad /* Store metadata without dependencies on mirror segments */ 502 1.1 haad if (!vg_commit(vg)) { 503 1.1 haad log_error("ABORTING: Failed to write new data locations " 504 1.1 haad "to disk."); 505 1.1 haad vg_revert(vg); 506 1.1 haad resume_lv(cmd, lv_mirr); 507 1.1 haad resume_lvs(cmd, lvs_changed); 508 1.1 haad return 0; 509 1.1 haad } 510 1.1 haad 511 1.1 haad /* Release mirror LV. (No pending I/O because it's been suspended.) */ 512 1.1 haad if (!resume_lv(cmd, lv_mirr)) { 513 1.1 haad log_error("Unable to reactivate logical volume \"%s\"", 514 1.1 haad lv_mirr->name); 515 1.1 haad r = 0; 516 1.1 haad } 517 1.1 haad 518 1.1 haad /* Unsuspend LVs */ 519 1.1 haad resume_lvs(cmd, lvs_changed); 520 1.1 haad 521 1.1 haad /* Deactivate mirror LV */ 522 1.1 haad if (!deactivate_lv(cmd, lv_mirr)) { 523 1.1 haad log_error("ABORTING: Unable to deactivate temporary logical " 524 1.1 haad "volume \"%s\"", lv_mirr->name); 525 1.1 haad r = 0; 526 1.1 haad } 527 1.1 haad 528 1.1 haad log_verbose("Removing temporary pvmove LV"); 529 1.1 haad if (!lv_remove(lv_mirr)) { 530 1.1 haad log_error("ABORTING: Removal of temporary pvmove LV failed"); 531 1.1 haad return 0; 532 1.1 haad } 533 1.1 haad 534 1.1 haad /* Store it on disks */ 535 1.1 haad log_verbose("Writing out final volume group after pvmove"); 536 1.1 haad if (!vg_write(vg) || !vg_commit(vg)) { 537 1.1 haad log_error("ABORTING: Failed to write new data locations " 538 1.1 haad "to disk."); 539 1.1 haad return 0; 540 1.1 haad } 541 1.1 haad 542 1.1 haad /* FIXME backup positioning */ 543 1.1 haad backup(vg); 544 1.1 haad 545 1.1 haad return r; 546 1.1 haad } 547 1.1 haad 548 1.1 haad static struct volume_group *_get_move_vg(struct cmd_context *cmd, 549 1.1.1.2 haad const char *name, const char *uuid) 550 1.1 haad { 551 1.1 haad struct physical_volume *pv; 552 1.1 haad 553 1.1 haad /* Reread all metadata in case it got changed */ 554 1.1 haad if (!(pv = find_pv_by_name(cmd, name))) { 555 1.1 haad log_error("ABORTING: Can't reread PV %s", name); 556 1.1 haad /* What more could we do here? */ 557 1.1 haad return NULL; 558 1.1 haad } 559 1.1 haad 560 1.1 haad return _get_vg(cmd, pv_vg_name(pv)); 561 1.1 haad } 562 1.1 haad 563 1.1 haad static struct poll_functions _pvmove_fns = { 564 1.1 haad .get_copy_name_from_lv = get_pvmove_pvname_from_lv_mirr, 565 1.1 haad .get_copy_vg = _get_move_vg, 566 1.1 haad .get_copy_lv = find_pvmove_lv_from_pvname, 567 1.1.1.2 haad .poll_progress = poll_mirror_progress, 568 1.1 haad .update_metadata = _update_metadata, 569 1.1 haad .finish_copy = _finish_pvmove, 570 1.1 haad }; 571 1.1 haad 572 1.1 haad int pvmove_poll(struct cmd_context *cmd, const char *pv_name, 573 1.1 haad unsigned background) 574 1.1 haad { 575 1.1.1.2 haad return poll_daemon(cmd, pv_name, NULL, background, PVMOVE, &_pvmove_fns, 576 1.1 haad "Moved"); 577 1.1 haad } 578 1.1 haad 579 1.1 haad int pvmove(struct cmd_context *cmd, int argc, char **argv) 580 1.1 haad { 581 1.1 haad char *pv_name = NULL; 582 1.1 haad char *colon; 583 1.1 haad int ret; 584 1.1 haad 585 1.1 haad /* dm raid1 target must be present in every case */ 586 1.1 haad if (!_pvmove_target_present(cmd, 0)) { 587 1.1 haad log_error("Required device-mapper target(s) not " 588 1.1 haad "detected in your kernel"); 589 1.1 haad return ECMD_FAILED; 590 1.1 haad } 591 1.1 haad 592 1.1 haad if (argc) { 593 1.1 haad pv_name = argv[0]; 594 1.1 haad 595 1.1 haad /* Drop any PE lists from PV name */ 596 1.1 haad if ((colon = strchr(pv_name, ':'))) { 597 1.1 haad if (!(pv_name = dm_pool_strndup(cmd->mem, pv_name, 598 1.1 haad (unsigned) (colon - 599 1.1 haad pv_name)))) { 600 1.1 haad log_error("Failed to clone PV name"); 601 1.1 haad return ECMD_FAILED; 602 1.1 haad } 603 1.1 haad } 604 1.1 haad 605 1.1 haad if (!arg_count(cmd, abort_ARG) && 606 1.1 haad (ret = _set_up_pvmove(cmd, pv_name, argc, argv)) != 607 1.1 haad ECMD_PROCESSED) { 608 1.1 haad stack; 609 1.1 haad return ret; 610 1.1 haad } 611 1.1 haad } 612 1.1 haad 613 1.1.1.2 haad return pvmove_poll(cmd, pv_name, arg_is_set(cmd, background_ARG)); 614 1.1 haad } 615