mirror of
git://sourceware.org/git/lvm2.git
synced 2024-10-29 21:55:56 +03:00
fcbef05aae
Hmm rpmlint suggest fsf is using a different address these days, so lets keep it up-to-date
197 lines
5.1 KiB
C
197 lines
5.1 KiB
C
/*
|
|
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
|
|
* Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
|
*
|
|
* This file is part of LVM2.
|
|
*
|
|
* This copyrighted material is made available to anyone wishing to use,
|
|
* modify, copy, or redistribute it subject to the terms and conditions
|
|
* of the GNU Lesser General Public License v.2.1.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "tools.h"
|
|
|
|
#include "pvmove_poll.h"
|
|
|
|
static int _is_pvmove_image_removable(struct logical_volume *mimage_lv,
|
|
void *baton)
|
|
{
|
|
uint32_t mimage_to_remove = *((uint32_t *)baton);
|
|
struct lv_segment *mirror_seg;
|
|
|
|
if (!(mirror_seg = get_only_segment_using_this_lv(mimage_lv))) {
|
|
log_error(INTERNAL_ERROR "%s is not a proper mirror image",
|
|
mimage_lv->name);
|
|
return 0;
|
|
}
|
|
|
|
if (seg_type(mirror_seg, 0) != AREA_LV) {
|
|
log_error(INTERNAL_ERROR "%s is not a pvmove mirror of LV-type",
|
|
mirror_seg->lv->name);
|
|
return 0;
|
|
}
|
|
|
|
if (mimage_to_remove > mirror_seg->area_count) {
|
|
log_error(INTERNAL_ERROR "Mirror image %" PRIu32 " not found in segment",
|
|
mimage_to_remove);
|
|
return 0;
|
|
}
|
|
|
|
if (seg_lv(mirror_seg, mimage_to_remove) == mimage_lv)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _detach_pvmove_mirror(struct cmd_context *cmd,
|
|
struct logical_volume *lv_mirr)
|
|
{
|
|
uint32_t mimage_to_remove = 0;
|
|
struct dm_list lvs_completed;
|
|
struct lv_list *lvl;
|
|
|
|
/* Update metadata to remove mirror segments and break dependencies */
|
|
dm_list_init(&lvs_completed);
|
|
|
|
if (arg_is_set(cmd, abort_ARG) &&
|
|
(seg_type(first_seg(lv_mirr), 0) == AREA_LV))
|
|
mimage_to_remove = 1; /* remove the second mirror leg */
|
|
|
|
if (!lv_remove_mirrors(cmd, lv_mirr, 1, 0, _is_pvmove_image_removable, &mimage_to_remove, PVMOVE) ||
|
|
!remove_layers_for_segments_all(cmd, lv_mirr, PVMOVE,
|
|
&lvs_completed)) {
|
|
return 0;
|
|
}
|
|
|
|
dm_list_iterate_items(lvl, &lvs_completed)
|
|
/* FIXME Assumes only one pvmove at a time! */
|
|
lvl->lv->status &= ~LOCKED;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Called to advance the mirror to successive sections of it.
|
|
* (Not called first time or after the last section completes.)
|
|
*/
|
|
int pvmove_update_metadata(struct cmd_context *cmd, struct volume_group *vg,
|
|
struct logical_volume *lv_mirr,
|
|
struct dm_list *lvs_changed __attribute__((unused)),
|
|
unsigned flags __attribute__((unused)))
|
|
{
|
|
log_verbose("Updating volume group metadata.");
|
|
if (!vg_write(vg)) {
|
|
log_error("ABORTING: Volume group metadata update failed.");
|
|
return 0;
|
|
}
|
|
|
|
if (!suspend_lv(cmd, lv_mirr)) {
|
|
vg_revert(vg);
|
|
log_error("ABORTING: Temporary pvmove mirror reload failed.");
|
|
if (!revert_lv(cmd, lv_mirr))
|
|
stack;
|
|
return 0;
|
|
}
|
|
|
|
/* Commit on-disk metadata */
|
|
if (!vg_commit(vg)) {
|
|
log_error("ABORTING: Volume group metadata update failed.");
|
|
if (!resume_lv(cmd, lv_mirr))
|
|
log_error("Unable to reactivate logical volume \"%s\".",
|
|
lv_mirr->name);
|
|
if (!revert_lv(cmd, lv_mirr))
|
|
stack;
|
|
return 0;
|
|
}
|
|
|
|
if (!resume_lv(cmd, lv_mirr)) {
|
|
log_error("Unable to reactivate logical volume \"%s\".",
|
|
lv_mirr->name);
|
|
return 0;
|
|
}
|
|
|
|
backup(vg);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int pvmove_finish(struct cmd_context *cmd, struct volume_group *vg,
|
|
struct logical_volume *lv_mirr, struct dm_list *lvs_changed)
|
|
{
|
|
int r = 1;
|
|
|
|
if (!dm_list_empty(lvs_changed) &&
|
|
(!_detach_pvmove_mirror(cmd, lv_mirr) ||
|
|
!replace_lv_with_error_segment(lv_mirr))) {
|
|
log_error("ABORTING: Removal of temporary mirror failed");
|
|
return 0;
|
|
}
|
|
|
|
/* Store metadata without dependencies on mirror segments */
|
|
if (!vg_write(vg)) {
|
|
log_error("ABORTING: Failed to write new data locations "
|
|
"to disk.");
|
|
return 0;
|
|
}
|
|
|
|
/* Suspend LVs changed (implicitly suspends lv_mirr) */
|
|
if (!suspend_lvs(cmd, lvs_changed, vg)) {
|
|
log_error("ABORTING: Locking LVs to remove temporary mirror failed");
|
|
if (!revert_lv(cmd, lv_mirr))
|
|
stack;
|
|
return 0;
|
|
}
|
|
|
|
/* Store metadata without dependencies on mirror segments */
|
|
if (!vg_commit(vg)) {
|
|
log_error("ABORTING: Failed to write new data locations "
|
|
"to disk.");
|
|
if (!revert_lv(cmd, lv_mirr))
|
|
stack;
|
|
if (!revert_lvs(cmd, lvs_changed))
|
|
stack;
|
|
return 0;
|
|
}
|
|
|
|
/* Release mirror LV. (No pending I/O because it's been suspended.) */
|
|
if (!resume_lv(cmd, lv_mirr)) {
|
|
log_error("Unable to reactivate logical volume \"%s\"",
|
|
lv_mirr->name);
|
|
r = 0;
|
|
}
|
|
|
|
/* Unsuspend LVs */
|
|
if (!resume_lvs(cmd, lvs_changed))
|
|
stack;
|
|
|
|
/* Deactivate mirror LV */
|
|
if (!deactivate_lv(cmd, lv_mirr)) {
|
|
log_error("ABORTING: Unable to deactivate temporary logical "
|
|
"volume \"%s\"", lv_mirr->name);
|
|
r = 0;
|
|
}
|
|
|
|
log_verbose("Removing temporary pvmove LV");
|
|
if (!lv_remove(lv_mirr)) {
|
|
log_error("ABORTING: Removal of temporary pvmove LV failed");
|
|
return 0;
|
|
}
|
|
|
|
/* Store it on disks */
|
|
log_verbose("Writing out final volume group after pvmove");
|
|
if (!vg_write(vg) || !vg_commit(vg)) {
|
|
log_error("ABORTING: Failed to write new data locations "
|
|
"to disk.");
|
|
return 0;
|
|
}
|
|
|
|
/* FIXME backup positioning */
|
|
backup(vg);
|
|
|
|
return r;
|
|
}
|