1 1.1 haad /* $NetBSD: vgreduce.c,v 1.1.1.2 2009/12/02 00:25:57 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 #include "lv_alloc.h" 20 1.1 haad 21 1.1 haad static int _remove_pv(struct volume_group *vg, struct pv_list *pvl, int silent) 22 1.1 haad { 23 1.1 haad char uuid[64] __attribute((aligned(8))); 24 1.1 haad 25 1.1 haad if (vg->pv_count == 1) { 26 1.1 haad log_error("Volume Groups must always contain at least one PV"); 27 1.1 haad return 0; 28 1.1 haad } 29 1.1 haad 30 1.1 haad if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid))) 31 1.1 haad return_0; 32 1.1 haad 33 1.1 haad log_verbose("Removing PV with UUID %s from VG %s", uuid, vg->name); 34 1.1 haad 35 1.1 haad if (pvl->pv->pe_alloc_count) { 36 1.1 haad if (!silent) 37 1.1 haad log_error("LVs still present on PV with UUID %s: " 38 1.1 haad "Can't remove from VG %s", uuid, vg->name); 39 1.1 haad return 0; 40 1.1 haad } 41 1.1 haad 42 1.1 haad vg->free_count -= pvl->pv->pe_count; 43 1.1 haad vg->extent_count -= pvl->pv->pe_count; 44 1.1 haad vg->pv_count--; 45 1.1 haad 46 1.1 haad dm_list_del(&pvl->list); 47 1.1 haad 48 1.1 haad return 1; 49 1.1 haad } 50 1.1 haad 51 1.1 haad static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv, 52 1.1 haad int *list_unsafe, struct dm_list *lvs_changed) 53 1.1 haad { 54 1.1 haad struct lv_segment *snap_seg; 55 1.1 haad struct dm_list *snh, *snht; 56 1.1 haad struct logical_volume *cow; 57 1.1 haad struct lv_list *lvl; 58 1.1 haad struct lvinfo info; 59 1.1 haad int first = 1; 60 1.1 haad 61 1.1 haad log_verbose("%s/%s has missing extents: removing (including " 62 1.1 haad "dependencies)", lv->vg->name, lv->name); 63 1.1 haad 64 1.1 haad /* FIXME Cope properly with stacked devices & snapshots. */ 65 1.1 haad 66 1.1 haad /* If snapshot device is missing, deactivate origin. */ 67 1.1 haad if (lv_is_cow(lv) && (snap_seg = find_cow(lv))) { 68 1.1 haad log_verbose("Deactivating (if active) logical volume %s " 69 1.1 haad "(origin of %s)", snap_seg->origin->name, lv->name); 70 1.1 haad 71 1.1 haad if (!test_mode() && !deactivate_lv(cmd, snap_seg->origin)) { 72 1.1 haad log_error("Failed to deactivate LV %s", 73 1.1 haad snap_seg->origin->name); 74 1.1 haad return 0; 75 1.1 haad } 76 1.1 haad 77 1.1 haad /* Use the origin LV */ 78 1.1 haad lv = snap_seg->origin; 79 1.1 haad } 80 1.1 haad 81 1.1 haad /* Remove snapshot dependencies */ 82 1.1 haad dm_list_iterate_safe(snh, snht, &lv->snapshot_segs) { 83 1.1 haad snap_seg = dm_list_struct_base(snh, struct lv_segment, 84 1.1 haad origin_list); 85 1.1 haad cow = snap_seg->cow; 86 1.1 haad 87 1.1 haad if (first && !test_mode() && 88 1.1 haad !deactivate_lv(cmd, snap_seg->origin)) { 89 1.1 haad log_error("Failed to deactivate LV %s", 90 1.1 haad snap_seg->origin->name); 91 1.1 haad return 0; 92 1.1 haad } 93 1.1 haad 94 1.1 haad *list_unsafe = 1; /* May remove caller's lvht! */ 95 1.1 haad if (!vg_remove_snapshot(cow)) 96 1.1 haad return_0; 97 1.1 haad log_verbose("Removing LV %s from VG %s", cow->name, 98 1.1 haad lv->vg->name); 99 1.1 haad if (!lv_remove(cow)) 100 1.1 haad return_0; 101 1.1 haad 102 1.1 haad first = 0; 103 1.1 haad } 104 1.1 haad 105 1.1 haad /* 106 1.1 haad * If LV is active, replace it with error segment 107 1.1 haad * and add to list of LVs to be removed later. 108 1.1 haad * Doesn't apply to snapshots/origins yet - they're already deactivated. 109 1.1 haad */ 110 1.1 haad /* 111 1.1 haad * If the LV is a part of mirror segment, 112 1.1 haad * the mirrored LV also should be cleaned up. 113 1.1 haad * Clean-up is currently done by caller (_make_vg_consistent()). 114 1.1 haad */ 115 1.1 haad if ((lv_info(cmd, lv, &info, 0, 0) && info.exists) || 116 1.1 haad find_mirror_seg(first_seg(lv))) { 117 1.1 haad if (!replace_lv_with_error_segment(lv)) 118 1.1 haad return_0; 119 1.1 haad 120 1.1 haad if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) { 121 1.1 haad log_error("lv_list alloc failed"); 122 1.1 haad return 0; 123 1.1 haad } 124 1.1 haad lvl->lv = lv; 125 1.1 haad dm_list_add(lvs_changed, &lvl->list); 126 1.1 haad } else { 127 1.1 haad /* Remove LV immediately. */ 128 1.1 haad log_verbose("Removing LV %s from VG %s", lv->name, lv->vg->name); 129 1.1 haad if (!lv_remove(lv)) 130 1.1 haad return_0; 131 1.1 haad } 132 1.1 haad 133 1.1 haad return 1; 134 1.1 haad } 135 1.1 haad 136 1.1 haad static int _consolidate_vg(struct cmd_context *cmd, struct volume_group *vg) 137 1.1 haad { 138 1.1 haad struct pv_list *pvl; 139 1.1 haad struct lv_list *lvl; 140 1.1 haad int r = 1; 141 1.1 haad 142 1.1 haad dm_list_iterate_items(lvl, &vg->lvs) 143 1.1 haad if (lvl->lv->status & PARTIAL_LV) { 144 1.1 haad log_warn("WARNING: Partial LV %s needs to be repaired " 145 1.1 haad "or removed. ", lvl->lv->name); 146 1.1 haad r = 0; 147 1.1 haad } 148 1.1 haad 149 1.1 haad if (!r) { 150 1.1 haad cmd->handles_missing_pvs = 1; 151 1.1 haad log_warn("WARNING: There are still partial LVs in VG %s.", vg->name); 152 1.1 haad log_warn("To remove them unconditionally use: vgreduce --removemissing --force."); 153 1.1 haad log_warn("Proceeding to remove empty missing PVs."); 154 1.1 haad } 155 1.1 haad 156 1.1 haad dm_list_iterate_items(pvl, &vg->pvs) { 157 1.1 haad if (pvl->pv->dev && !(pvl->pv->status & MISSING_PV)) 158 1.1 haad continue; 159 1.1 haad if (r && !_remove_pv(vg, pvl, 0)) 160 1.1 haad return_0; 161 1.1 haad } 162 1.1 haad 163 1.1 haad return r; 164 1.1 haad } 165 1.1 haad 166 1.1 haad static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg) 167 1.1 haad { 168 1.1 haad struct dm_list *pvh, *pvht; 169 1.1 haad struct dm_list *lvh, *lvht; 170 1.1 haad struct pv_list *pvl; 171 1.1 haad struct lv_list *lvl, *lvl2, *lvlt; 172 1.1 haad struct logical_volume *lv; 173 1.1 haad struct physical_volume *pv; 174 1.1 haad struct lv_segment *seg, *mirrored_seg; 175 1.1 haad unsigned s; 176 1.1 haad uint32_t mimages, remove_log; 177 1.1 haad int list_unsafe, only_mirror_images_found; 178 1.1 haad DM_LIST_INIT(lvs_changed); 179 1.1 haad only_mirror_images_found = 1; 180 1.1 haad 181 1.1 haad /* Deactivate & remove necessary LVs */ 182 1.1 haad restart_loop: 183 1.1 haad list_unsafe = 0; /* Set if we delete a different list-member */ 184 1.1 haad 185 1.1 haad dm_list_iterate_safe(lvh, lvht, &vg->lvs) { 186 1.1 haad lv = dm_list_item(lvh, struct lv_list)->lv; 187 1.1 haad 188 1.1 haad /* Are any segments of this LV on missing PVs? */ 189 1.1 haad dm_list_iterate_items(seg, &lv->segments) { 190 1.1 haad for (s = 0; s < seg->area_count; s++) { 191 1.1 haad if (seg_type(seg, s) != AREA_PV) 192 1.1 haad continue; 193 1.1 haad 194 1.1 haad /* FIXME Also check for segs on deleted LVs (incl pvmove) */ 195 1.1 haad 196 1.1 haad pv = seg_pv(seg, s); 197 1.1 haad if (!pv || !pv_dev(pv) || 198 1.1 haad (pv->status & MISSING_PV)) { 199 1.1 haad if (arg_count(cmd, mirrorsonly_ARG) && 200 1.1 haad !(lv->status & MIRROR_IMAGE)) { 201 1.1 haad log_error("Non-mirror-image LV %s found: can't remove.", lv->name); 202 1.1 haad only_mirror_images_found = 0; 203 1.1 haad continue; 204 1.1 haad } 205 1.1 haad if (!_remove_lv(cmd, lv, &list_unsafe, &lvs_changed)) 206 1.1 haad return_0; 207 1.1 haad if (list_unsafe) 208 1.1 haad goto restart_loop; 209 1.1 haad } 210 1.1 haad } 211 1.1 haad } 212 1.1 haad } 213 1.1 haad 214 1.1 haad if (!only_mirror_images_found) { 215 1.1 haad log_error("Aborting because --mirrorsonly was specified."); 216 1.1 haad return 0; 217 1.1 haad } 218 1.1 haad 219 1.1 haad /* 220 1.1 haad * Remove missing PVs. FIXME: This duplicates _consolidate_vg above, 221 1.1 haad * but we cannot use that right now, since the LV removal code in this 222 1.1 haad * function leaves the VG in a "somewhat inconsistent" state and 223 1.1 haad * _consolidate_vg doesn't like that -- specifically, mirrors are fixed 224 1.1 haad * up *after* the PVs are removed. All this should be gradually 225 1.1 haad * superseded by lvconvert --repair. 226 1.1 haad */ 227 1.1 haad dm_list_iterate_safe(pvh, pvht, &vg->pvs) { 228 1.1 haad pvl = dm_list_item(pvh, struct pv_list); 229 1.1 haad if (pvl->pv->dev) 230 1.1 haad continue; 231 1.1 haad if (!_remove_pv(vg, pvl, 0)) 232 1.1 haad return_0; 233 1.1 haad } 234 1.1 haad 235 1.1 haad /* FIXME Recovery. For now people must clean up by hand. */ 236 1.1 haad 237 1.1 haad if (!dm_list_empty(&lvs_changed)) { 238 1.1 haad if (!vg_write(vg)) { 239 1.1 haad log_error("Failed to write out a consistent VG for %s", 240 1.1 haad vg->name); 241 1.1 haad return 0; 242 1.1 haad } 243 1.1 haad 244 1.1 haad if (!test_mode()) { 245 1.1 haad /* Suspend lvs_changed */ 246 1.1 haad if (!suspend_lvs(cmd, &lvs_changed)) { 247 1.1 haad stack; 248 1.1 haad vg_revert(vg); 249 1.1 haad return 0; 250 1.1 haad } 251 1.1 haad } 252 1.1 haad 253 1.1 haad if (!vg_commit(vg)) { 254 1.1 haad log_error("Failed to commit consistent VG for %s", 255 1.1 haad vg->name); 256 1.1 haad vg_revert(vg); 257 1.1 haad return 0; 258 1.1 haad } 259 1.1 haad 260 1.1 haad if (!test_mode()) { 261 1.1 haad if (!resume_lvs(cmd, &lvs_changed)) { 262 1.1 haad log_error("Failed to resume LVs using error segments."); 263 1.1 haad return 0; 264 1.1 haad } 265 1.1 haad } 266 1.1 haad 267 1.1 haad lvs_changed_altered: 268 1.1 haad /* Remove lost mirror images from mirrors */ 269 1.1 haad dm_list_iterate_items(lvl, &vg->lvs) { 270 1.1 haad mirrored_seg_altered: 271 1.1 haad mirrored_seg = first_seg(lvl->lv); 272 1.1 haad if (!seg_is_mirrored(mirrored_seg)) 273 1.1 haad continue; 274 1.1 haad 275 1.1 haad mimages = mirrored_seg->area_count; 276 1.1 haad remove_log = 0; 277 1.1 haad 278 1.1 haad for (s = 0; s < mirrored_seg->area_count; s++) { 279 1.1 haad dm_list_iterate_items_safe(lvl2, lvlt, &lvs_changed) { 280 1.1 haad if (seg_type(mirrored_seg, s) != AREA_LV || 281 1.1 haad lvl2->lv != seg_lv(mirrored_seg, s)) 282 1.1 haad continue; 283 1.1 haad dm_list_del(&lvl2->list); 284 1.1 haad if (!shift_mirror_images(mirrored_seg, s)) 285 1.1 haad return_0; 286 1.1 haad mimages--; /* FIXME Assumes uniqueness */ 287 1.1 haad } 288 1.1 haad } 289 1.1 haad 290 1.1 haad if (mirrored_seg->log_lv) { 291 1.1 haad dm_list_iterate_items(seg, &mirrored_seg->log_lv->segments) { 292 1.1 haad /* FIXME: The second test shouldn't be required */ 293 1.1 haad if ((seg->segtype == 294 1.1 haad get_segtype_from_string(vg->cmd, "error"))) { 295 1.1 haad log_print("The log device for %s/%s has failed.", 296 1.1 haad vg->name, mirrored_seg->lv->name); 297 1.1 haad remove_log = 1; 298 1.1 haad break; 299 1.1 haad } 300 1.1 haad if (!strcmp(seg->segtype->name, "error")) { 301 1.1 haad log_print("Log device for %s/%s has failed.", 302 1.1 haad vg->name, mirrored_seg->lv->name); 303 1.1 haad remove_log = 1; 304 1.1 haad break; 305 1.1 haad } 306 1.1 haad } 307 1.1 haad } 308 1.1 haad 309 1.1 haad if ((mimages != mirrored_seg->area_count) || remove_log){ 310 1.1 haad if (!reconfigure_mirror_images(mirrored_seg, mimages, 311 1.1 haad NULL, remove_log)) 312 1.1 haad return_0; 313 1.1 haad 314 1.1 haad if (!vg_write(vg)) { 315 1.1 haad log_error("Failed to write out updated " 316 1.1 haad "VG for %s", vg->name); 317 1.1 haad return 0; 318 1.1 haad } 319 1.1 haad 320 1.1 haad if (!vg_commit(vg)) { 321 1.1 haad log_error("Failed to commit updated VG " 322 1.1 haad "for %s", vg->name); 323 1.1 haad vg_revert(vg); 324 1.1 haad return 0; 325 1.1 haad } 326 1.1 haad 327 1.1 haad /* mirrored LV no longer has valid mimages. 328 1.1 haad * So add it to lvs_changed for removal. 329 1.1 haad * For this LV may be an area of other mirror, 330 1.1 haad * restart the loop. */ 331 1.1 haad if (!mimages) { 332 1.1 haad if (!_remove_lv(cmd, lvl->lv, 333 1.1 haad &list_unsafe, &lvs_changed)) 334 1.1 haad return_0; 335 1.1 haad goto lvs_changed_altered; 336 1.1 haad } 337 1.1 haad 338 1.1 haad /* As a result of reconfigure_mirror_images(), 339 1.1 haad * first_seg(lv) may now be different seg. 340 1.1 haad * e.g. a temporary layer might be removed. 341 1.1 haad * So check the mirrored_seg again. */ 342 1.1 haad goto mirrored_seg_altered; 343 1.1 haad } 344 1.1 haad } 345 1.1 haad 346 1.1 haad /* Deactivate error LVs */ 347 1.1 haad if (!test_mode()) { 348 1.1 haad dm_list_iterate_items_safe(lvl, lvlt, &lvs_changed) { 349 1.1 haad log_verbose("Deactivating (if active) logical volume %s", 350 1.1 haad lvl->lv->name); 351 1.1 haad 352 1.1 haad if (!deactivate_lv(cmd, lvl->lv)) { 353 1.1 haad log_error("Failed to deactivate LV %s", 354 1.1 haad lvl->lv->name); 355 1.1 haad /* 356 1.1 haad * We failed to deactivate. 357 1.1 haad * Probably because this was a mirror log. 358 1.1 haad * Don't try to lv_remove it. 359 1.1 haad * Continue work on others. 360 1.1 haad */ 361 1.1 haad dm_list_del(&lvl->list); 362 1.1 haad } 363 1.1 haad } 364 1.1 haad } 365 1.1 haad 366 1.1 haad /* Remove remaining LVs */ 367 1.1 haad dm_list_iterate_items(lvl, &lvs_changed) { 368 1.1 haad log_verbose("Removing LV %s from VG %s", lvl->lv->name, 369 1.1 haad lvl->lv->vg->name); 370 1.1 haad /* Skip LVs already removed by mirror code */ 371 1.1 haad if (find_lv_in_vg(vg, lvl->lv->name) && 372 1.1 haad !lv_remove(lvl->lv)) 373 1.1 haad return_0; 374 1.1 haad } 375 1.1 haad } 376 1.1 haad 377 1.1 haad return 1; 378 1.1 haad } 379 1.1 haad 380 1.1 haad /* Or take pv_name instead? */ 381 1.1 haad static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg, 382 1.1 haad struct physical_volume *pv, 383 1.1 haad void *handle __attribute((unused))) 384 1.1 haad { 385 1.1 haad struct pv_list *pvl; 386 1.1.1.2 haad struct volume_group *orphan_vg = NULL; 387 1.1.1.2 haad int r = ECMD_FAILED; 388 1.1 haad const char *name = pv_dev_name(pv); 389 1.1 haad 390 1.1 haad if (pv_pe_alloc_count(pv)) { 391 1.1 haad log_error("Physical volume \"%s\" still in use", name); 392 1.1 haad return ECMD_FAILED; 393 1.1 haad } 394 1.1 haad 395 1.1 haad if (vg->pv_count == 1) { 396 1.1 haad log_error("Can't remove final physical volume \"%s\" from " 397 1.1 haad "volume group \"%s\"", name, vg->name); 398 1.1 haad return ECMD_FAILED; 399 1.1 haad } 400 1.1 haad 401 1.1.1.2 haad if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE)) { 402 1.1 haad log_error("Can't get lock for orphan PVs"); 403 1.1 haad return ECMD_FAILED; 404 1.1 haad } 405 1.1 haad 406 1.1 haad pvl = find_pv_in_vg(vg, name); 407 1.1 haad 408 1.1.1.2 haad if (!archive(vg)) 409 1.1.1.2 haad goto_bad; 410 1.1 haad 411 1.1 haad log_verbose("Removing \"%s\" from volume group \"%s\"", name, vg->name); 412 1.1 haad 413 1.1 haad if (pvl) 414 1.1 haad dm_list_del(&pvl->list); 415 1.1 haad 416 1.1 haad pv->vg_name = vg->fid->fmt->orphan_vg_name; 417 1.1 haad pv->status = ALLOCATABLE_PV; 418 1.1 haad 419 1.1 haad if (!dev_get_size(pv_dev(pv), &pv->size)) { 420 1.1 haad log_error("%s: Couldn't get size.", pv_dev_name(pv)); 421 1.1.1.2 haad goto bad; 422 1.1 haad } 423 1.1 haad 424 1.1 haad vg->pv_count--; 425 1.1 haad vg->free_count -= pv_pe_count(pv) - pv_pe_alloc_count(pv); 426 1.1 haad vg->extent_count -= pv_pe_count(pv); 427 1.1 haad 428 1.1.1.2 haad orphan_vg = vg_read_for_update(cmd, vg->fid->fmt->orphan_vg_name, 429 1.1.1.2 haad NULL, 0); 430 1.1.1.2 haad 431 1.1.1.2 haad if (vg_read_error(orphan_vg)) 432 1.1.1.2 haad goto bad; 433 1.1 haad 434 1.1 haad if (!vg_split_mdas(cmd, vg, orphan_vg) || !vg->pv_count) { 435 1.1 haad log_error("Cannot remove final metadata area on \"%s\" from \"%s\"", 436 1.1 haad name, vg->name); 437 1.1.1.2 haad goto bad; 438 1.1 haad } 439 1.1 haad 440 1.1 haad if (!vg_write(vg) || !vg_commit(vg)) { 441 1.1 haad log_error("Removal of physical volume \"%s\" from " 442 1.1 haad "\"%s\" failed", name, vg->name); 443 1.1.1.2 haad goto bad; 444 1.1 haad } 445 1.1 haad 446 1.1 haad if (!pv_write(cmd, pv, NULL, INT64_C(-1))) { 447 1.1 haad log_error("Failed to clear metadata from physical " 448 1.1 haad "volume \"%s\" " 449 1.1 haad "after removal from \"%s\"", name, vg->name); 450 1.1.1.2 haad goto bad; 451 1.1 haad } 452 1.1 haad 453 1.1 haad backup(vg); 454 1.1 haad 455 1.1 haad log_print("Removed \"%s\" from volume group \"%s\"", name, vg->name); 456 1.1.1.2 haad r = ECMD_PROCESSED; 457 1.1.1.2 haad bad: 458 1.1.1.2 haad unlock_and_release_vg(cmd, orphan_vg, VG_ORPHANS); 459 1.1.1.2 haad return r; 460 1.1 haad } 461 1.1 haad 462 1.1 haad int vgreduce(struct cmd_context *cmd, int argc, char **argv) 463 1.1 haad { 464 1.1 haad struct volume_group *vg; 465 1.1 haad char *vg_name; 466 1.1.1.2 haad int ret = ECMD_FAILED; 467 1.1 haad int fixed = 1; 468 1.1 haad int repairing = arg_count(cmd, removemissing_ARG); 469 1.1.1.2 haad int saved_ignore_suspended_devices = ignore_suspended_devices(); 470 1.1 haad 471 1.1 haad if (!argc && !repairing) { 472 1.1 haad log_error("Please give volume group name and " 473 1.1 haad "physical volume paths"); 474 1.1 haad return EINVALID_CMD_LINE; 475 1.1 haad } 476 1.1 haad 477 1.1 haad if (!argc && repairing) { 478 1.1 haad log_error("Please give volume group name"); 479 1.1 haad return EINVALID_CMD_LINE; 480 1.1 haad } 481 1.1 haad 482 1.1 haad if (arg_count(cmd, mirrorsonly_ARG) && !repairing) { 483 1.1 haad log_error("--mirrorsonly requires --removemissing"); 484 1.1 haad return EINVALID_CMD_LINE; 485 1.1 haad } 486 1.1 haad 487 1.1 haad if (argc == 1 && !arg_count(cmd, all_ARG) && !repairing) { 488 1.1 haad log_error("Please enter physical volume paths or option -a"); 489 1.1 haad return EINVALID_CMD_LINE; 490 1.1 haad } 491 1.1 haad 492 1.1 haad if (argc > 1 && arg_count(cmd, all_ARG)) { 493 1.1 haad log_error("Option -a and physical volume paths mutually " 494 1.1 haad "exclusive"); 495 1.1 haad return EINVALID_CMD_LINE; 496 1.1 haad } 497 1.1 haad 498 1.1 haad if (argc > 1 && repairing) { 499 1.1 haad log_error("Please only specify the volume group"); 500 1.1 haad return EINVALID_CMD_LINE; 501 1.1 haad } 502 1.1 haad 503 1.1 haad vg_name = skip_dev_dir(cmd, argv[0], NULL); 504 1.1 haad argv++; 505 1.1 haad argc--; 506 1.1 haad 507 1.1 haad log_verbose("Finding volume group \"%s\"", vg_name); 508 1.1 haad 509 1.1.1.2 haad if (repairing) { 510 1.1.1.2 haad init_ignore_suspended_devices(1); 511 1.1.1.2 haad cmd->handles_missing_pvs = 1; 512 1.1 haad } 513 1.1 haad 514 1.1.1.2 haad vg = vg_read_for_update(cmd, vg_name, NULL, READ_ALLOW_EXPORTED); 515 1.1.1.2 haad if (vg_read_error(vg) == FAILED_ALLOCATION || 516 1.1.1.2 haad vg_read_error(vg) == FAILED_NOTFOUND) 517 1.1.1.2 haad goto_out; 518 1.1.1.2 haad 519 1.1.1.2 haad /* FIXME We want to allow read-only VGs to be changed here? */ 520 1.1.1.2 haad if (vg_read_error(vg) && vg_read_error(vg) != FAILED_READ_ONLY 521 1.1.1.2 haad && !arg_count(cmd, removemissing_ARG)) 522 1.1.1.2 haad goto_out; 523 1.1 haad 524 1.1 haad if (repairing) { 525 1.1.1.2 haad if (!vg_read_error(vg) && !vg_missing_pv_count(vg)) { 526 1.1 haad log_error("Volume group \"%s\" is already consistent", 527 1.1 haad vg_name); 528 1.1.1.2 haad ret = ECMD_PROCESSED; 529 1.1.1.2 haad goto out; 530 1.1 haad } 531 1.1 haad 532 1.1.1.2 haad vg_release(vg); 533 1.1.1.2 haad log_verbose("Trying to open VG %s for recovery...", vg_name); 534 1.1.1.2 haad 535 1.1.1.2 haad vg = vg_read_for_update(cmd, vg_name, NULL, 536 1.1.1.2 haad READ_ALLOW_INCONSISTENT 537 1.1.1.2 haad | READ_ALLOW_EXPORTED); 538 1.1.1.2 haad 539 1.1.1.2 haad if (vg_read_error(vg) && vg_read_error(vg) != FAILED_READ_ONLY 540 1.1.1.2 haad && vg_read_error(vg) != FAILED_INCONSISTENT) 541 1.1.1.2 haad goto_out; 542 1.1.1.2 haad 543 1.1.1.2 haad if (!archive(vg)) 544 1.1.1.2 haad goto_out; 545 1.1 haad 546 1.1 haad if (arg_count(cmd, force_ARG)) { 547 1.1.1.2 haad if (!_make_vg_consistent(cmd, vg)) 548 1.1.1.2 haad goto_out; 549 1.1 haad } else 550 1.1 haad fixed = _consolidate_vg(cmd, vg); 551 1.1 haad 552 1.1 haad if (!vg_write(vg) || !vg_commit(vg)) { 553 1.1 haad log_error("Failed to write out a consistent VG for %s", 554 1.1 haad vg_name); 555 1.1.1.2 haad goto out; 556 1.1 haad } 557 1.1 haad backup(vg); 558 1.1 haad 559 1.1.1.2 haad if (fixed) { 560 1.1 haad log_print("Wrote out consistent volume group %s", 561 1.1 haad vg_name); 562 1.1.1.2 haad ret = ECMD_PROCESSED; 563 1.1.1.2 haad } else 564 1.1.1.2 haad ret = ECMD_FAILED; 565 1.1 haad 566 1.1 haad } else { 567 1.1.1.2 haad if (!vg_check_status(vg, EXPORTED_VG | LVM_WRITE | RESIZEABLE_VG)) 568 1.1.1.2 haad goto_out; 569 1.1 haad 570 1.1 haad /* FIXME: Pass private struct through to all these functions */ 571 1.1 haad /* and update in batch here? */ 572 1.1.1.2 haad ret = process_each_pv(cmd, argc, argv, vg, READ_FOR_UPDATE, 0, NULL, 573 1.1 haad _vgreduce_single); 574 1.1 haad 575 1.1 haad } 576 1.1.1.2 haad out: 577 1.1.1.2 haad init_ignore_suspended_devices(saved_ignore_suspended_devices); 578 1.1.1.2 haad unlock_and_release_vg(cmd, vg, vg_name); 579 1.1 haad 580 1.1 haad return ret; 581 1.1 haad 582 1.1 haad /******* FIXME 583 1.1 haad log_error ("no empty physical volumes found in volume group \"%s\"", vg_name); 584 1.1 haad 585 1.1 haad log_verbose 586 1.1 haad ("volume group \"%s\" will be reduced by %d physical volume%s", 587 1.1 haad vg_name, np, np > 1 ? "s" : ""); 588 1.1 haad log_verbose ("reducing volume group \"%s\" by physical volume \"%s\"", 589 1.1 haad vg_name, pv_names[p]); 590 1.1 haad 591 1.1 haad log_print 592 1.1 haad ("volume group \"%s\" %ssuccessfully reduced by physical volume%s:", 593 1.1 haad vg_name, error > 0 ? "NOT " : "", p > 1 ? "s" : ""); 594 1.1 haad log_print("%s", pv_this[p]->pv_name); 595 1.1 haad ********/ 596 1.1 haad 597 1.1 haad } 598