summaryrefslogtreecommitdiff
path: root/tools/pvmove_poll.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/pvmove_poll.c')
-rw-r--r--tools/pvmove_poll.c196
1 files changed, 196 insertions, 0 deletions
diff --git a/tools/pvmove_poll.c b/tools/pvmove_poll.c
new file mode 100644
index 000000000..0f071dc93
--- /dev/null
+++ b/tools/pvmove_poll.c
@@ -0,0 +1,196 @@
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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;
+}