summaryrefslogtreecommitdiff
path: root/tools/pvmove.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/pvmove.c')
-rw-r--r--tools/pvmove.c456
1 files changed, 211 insertions, 245 deletions
diff --git a/tools/pvmove.c b/tools/pvmove.c
index 30725844c..038056370 100644
--- a/tools/pvmove.c
+++ b/tools/pvmove.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -14,11 +14,13 @@
*/
#include "tools.h"
+
#include "polldaemon.h"
#include "display.h"
+#include "pvmove_poll.h"
+#include "lvmpolld-client.h"
#define PVMOVE_FIRST_TIME 0x00000001 /* Called for first time */
-#define PVMOVE_EXCLUSIVE 0x00000002 /* Require exclusive LV */
static int _pvmove_target_present(struct cmd_context *cmd, int clustered)
{
@@ -30,7 +32,7 @@ static int _pvmove_target_present(struct cmd_context *cmd, int clustered)
if (clustered && _clustered_found >= 0)
return _clustered_found;
- if (!(segtype = get_segtype_from_string(cmd, "mirror")))
+ if (!(segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_MIRROR)))
return_0;
if (activation() && segtype->ops->target_present &&
@@ -88,13 +90,6 @@ static const char *_extract_lvname(struct cmd_context *cmd, const char *vgname,
return lvname;
}
-static struct volume_group *_get_vg(struct cmd_context *cmd, const char *vgname)
-{
- dev_close_all();
-
- return vg_read_for_update(cmd, vgname, NULL, 0);
-}
-
/* Create list of PVs for allocation of replacement extents */
static struct dm_list *_get_allocatable_pvs(struct cmd_context *cmd, int argc,
char **argv, struct volume_group *vg,
@@ -513,170 +508,62 @@ static int _activate_lv(struct cmd_context *cmd, struct logical_volume *lv_mirr,
return r;
}
-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;
-}
-
-static int _suspend_lvs(struct cmd_context *cmd, unsigned first_time,
- struct logical_volume *lv_mirr,
- struct dm_list *lvs_changed,
- struct volume_group *vg_to_revert)
-{
- /*
- * Suspend lvs_changed the first time.
- * Suspend mirrors on subsequent calls.
- */
- if (first_time) {
- if (!suspend_lvs(cmd, lvs_changed, vg_to_revert))
- return_0;
- } else if (!suspend_lv(cmd, lv_mirr)) {
- if (vg_to_revert)
- vg_revert(vg_to_revert);
- return_0;
- }
-
- return 1;
-}
-
-static int _resume_lvs(struct cmd_context *cmd, unsigned first_time,
- struct logical_volume *lv_mirr,
- struct dm_list *lvs_changed)
-{
- /*
- * Suspend lvs_changed the first time.
- * Suspend mirrors on subsequent calls.
- */
-
- if (first_time) {
- if (!resume_lvs(cmd, lvs_changed)) {
- log_error("Unable to resume logical volumes");
- return 0;
- }
- } else if (!resume_lv(cmd, lv_mirr)) {
- log_error("Unable to reactivate logical volume \"%s\"",
- lv_mirr->name);
- return 0;
- }
-
- return 1;
-}
-
/*
- * Called to set up initial pvmove LV and to advance the mirror
- * to successive sections of it.
- * (Not called after the last section completes.)
+ * Called to set up initial pvmove LV only.
+ * (Not called after first or any other section completes.)
*/
static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv_mirr,
- struct dm_list *lvs_changed, unsigned flags)
+ struct dm_list *lvs_changed, unsigned exclusive)
{
- unsigned exclusive = (flags & PVMOVE_EXCLUSIVE) ? 1 : 0;
- unsigned first_time = (flags & PVMOVE_FIRST_TIME) ? 1 : 0;
int r = 0;
- log_verbose("Updating volume group metadata");
+ log_verbose("Setting up pvmove in on-disk volume group metadata.");
if (!vg_write(vg)) {
log_error("ABORTING: Volume group metadata update failed.");
return 0;
}
- if (!_suspend_lvs(cmd, first_time, lv_mirr, lvs_changed, vg)) {
- log_error("ABORTING: Temporary pvmove mirror %s failed.", first_time ? "activation" : "reload");
+ if (!suspend_lvs(cmd, lvs_changed, vg)) {
+ log_error("ABORTING: Temporary pvmove mirror activation failed.");
/* FIXME Add a recovery path for first time too. */
- if (!first_time && !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_lvs(cmd, first_time, lv_mirr, lvs_changed))
- stack;
- if (!first_time && !revert_lv(cmd, lv_mirr))
- stack;
+ if (!resume_lvs(cmd, lvs_changed))
+ log_error("Unable to resume logical volumes.");
return 0;
}
/* Activate the temporary mirror LV */
/* Only the first mirror segment gets activated as a mirror */
/* FIXME: Add option to use a log */
- if (first_time) {
- if (!exclusive && _pvmove_is_exclusive(cmd, vg))
- exclusive = 1;
+ if (!exclusive && _pvmove_is_exclusive(cmd, vg))
+ exclusive = 1;
- if (!_activate_lv(cmd, lv_mirr, exclusive)) {
- if (test_mode()) {
- r = 1;
- goto out;
- }
-
- /*
- * FIXME Run --abort internally here.
- */
- log_error("ABORTING: Temporary pvmove mirror activation failed. Run pvmove --abort.");
+ if (!_activate_lv(cmd, lv_mirr, exclusive)) {
+ if (test_mode()) {
+ r = 1;
goto out;
}
+
+ /*
+ * FIXME Run --abort internally here.
+ */
+ log_error("ABORTING: Temporary pvmove mirror activation failed. Run pvmove --abort.");
+ goto out;
}
r = 1;
out:
- if (!_resume_lvs(cmd, first_time, lv_mirr, lvs_changed))
+ if (!resume_lvs(cmd, lvs_changed)) {
+ log_error("Unable to resume logical volumes.");
r = 0;
+ }
if (r)
backup(vg);
@@ -684,10 +571,27 @@ out:
return r;
}
+static int _copy_id_components(struct cmd_context *cmd,
+ const struct logical_volume *lv, char **vg_name,
+ char **lv_name, union lvid *lvid)
+{
+ if (!(*vg_name = dm_pool_strdup(cmd->mem, lv->vg->name)) ||
+ !(*lv_name = dm_pool_strdup(cmd->mem, lv->name))) {
+ log_error("Failed to clone VG or LV name.");
+ return 0;
+ }
+
+ *lvid = lv->lvid;
+
+ return 1;
+}
+
static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
- int argc, char **argv)
+ int argc, char **argv, union lvid *lvid, char **vg_name_copy,
+ char **lv_mirr_name)
{
const char *lv_name = NULL;
+ const char *vg_name;
char *pv_name_arg;
struct volume_group *vg;
struct dm_list *source_pvl;
@@ -696,6 +600,7 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
struct dm_list *lvs_changed;
struct physical_volume *pv;
struct logical_volume *lv_mirr;
+ uint32_t lockd_state = 0;
unsigned flags = PVMOVE_FIRST_TIME;
unsigned exclusive;
int r = ECMD_FAILED;
@@ -710,9 +615,10 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
return EINVALID_CMD_LINE;
}
+ vg_name = pv_vg_name(pv);
+
if (arg_count(cmd, name_ARG)) {
- if (!(lv_name = _extract_lvname(cmd, pv_vg_name(pv),
- arg_value(cmd, name_ARG)))) {
+ if (!(lv_name = _extract_lvname(cmd, vg_name, arg_value(cmd, name_ARG)))) {
stack;
free_pv_fid(pv);
return EINVALID_CMD_LINE;
@@ -726,12 +632,15 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
}
/* Read VG */
- log_verbose("Finding volume group \"%s\"", pv_vg_name(pv));
+ log_verbose("Finding volume group \"%s\"", vg_name);
+
+ if (!lockd_vg(cmd, vg_name, "ex", 0, &lockd_state))
+ return_ECMD_FAILED;
- vg = _get_vg(cmd, pv_vg_name(pv));
+ vg = vg_read(cmd, vg_name, NULL, READ_FOR_UPDATE, lockd_state);
if (vg_read_error(vg)) {
release_vg(vg);
- return_ECMD_FAILED;
+ goto out_ret;
}
exclusive = _pvmove_is_exclusive(cmd, vg);
@@ -785,143 +694,154 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
/* init_pvmove(1); */
/* vg->status |= PVMOVE; */
- if (flags & PVMOVE_FIRST_TIME) {
- if (exclusive)
- flags |= PVMOVE_EXCLUSIVE;
- if (!_update_metadata
- (cmd, vg, lv_mirr, lvs_changed, flags))
+ if (!_copy_id_components(cmd, lv_mirr, vg_name_copy, lv_mirr_name, lvid))
+ goto out;
+
+ if (flags & PVMOVE_FIRST_TIME)
+ if (!_update_metadata(cmd, vg, lv_mirr, lvs_changed, exclusive))
goto_out;
- }
/* LVs are all in status LOCKED */
r = ECMD_PROCESSED;
out:
free_pv_fid(pv);
- unlock_and_release_vg(cmd, vg, pv_vg_name(pv));
+ unlock_and_release_vg(cmd, vg, vg_name);
+out_ret:
+ /*
+ * Release explicitly because the command may continue running
+ * for some time monitoring the progress, and we don not want
+ * or need the lockd lock held over that.
+ */
+ if (!lockd_vg(cmd, vg_name, "un", 0, &lockd_state))
+ stack;
+
return r;
}
-static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg,
- struct logical_volume *lv_mirr,
- struct dm_list *lvs_changed)
+static int _read_poll_id_from_pvname(struct cmd_context *cmd, const char *pv_name,
+ union lvid *lvid, char **vg_name_copy,
+ char **lv_name_copy, unsigned *in_progress)
{
- int r = 1;
+ int ret = 0;
+ const char *vg_name;
+ struct logical_volume *lv;
+ struct physical_volume *pv;
+ struct volume_group *vg;
+ uint32_t lockd_state = 0;
- 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");
+ if (!pv_name) {
+ log_error(INTERNAL_ERROR "Invalid PV name parameter.");
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;
- }
+ if (!(pv = find_pv_by_name(cmd, pv_name, 0, 0)))
+ 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;
- }
+ vg_name = pv_vg_name(pv);
- /* 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;
- }
+ if (!lockd_vg(cmd, vg_name, "sh", 0, &lockd_state))
+ 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;
+ /* need read-only access */
+ vg = vg_read(cmd, vg_name, NULL, 0, lockd_state);
+ if (vg_read_error(vg)) {
+ log_error("ABORTING: Can't read VG for %s.", pv_name);
+ release_vg(vg);
+ ret = 0;
+ goto out;
}
- /* 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;
+ if (!(lv = find_pvmove_lv(vg, pv_dev(pv), PVMOVE))) {
+ log_print_unless_silent("%s: No pvmove in progress - already finished or aborted.",
+ pv_name);
+ ret = 1;
+ *in_progress = 0;
+ } else if (_copy_id_components(cmd, lv, vg_name_copy, lv_name_copy, lvid)) {
+ ret = 1;
+ *in_progress = 1;
}
- log_verbose("Removing temporary pvmove LV");
- if (!lv_remove(lv_mirr)) {
- log_error("ABORTING: Removal of temporary pvmove LV failed");
- return 0;
- }
+ unlock_and_release_vg(cmd, vg, vg_name);
+out:
+ if (!lockd_vg(cmd, vg_name, "un", 0, &lockd_state))
+ stack;
+ free_pv_fid(pv);
+ return ret;
+}
- /* 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;
- }
+static struct poll_functions _pvmove_fns = {
+ .get_copy_name_from_lv = get_pvmove_pvname_from_lv_mirr,
+ .poll_progress = poll_mirror_progress,
+ .update_metadata = pvmove_update_metadata,
+ .finish_copy = pvmove_finish,
+};
- /* FIXME backup positioning */
- backup(vg);
+static void _destroy_id(struct cmd_context *cmd, struct poll_operation_id *id)
+{
+ if (!id)
+ return;
- return r;
+ dm_pool_free(cmd->mem, id);
}
-static struct volume_group *_get_move_vg(struct cmd_context *cmd,
- const char *name,
- const char *uuid __attribute__((unused)))
+static struct poll_operation_id *_create_id(struct cmd_context *cmd,
+ const char *pv_name,
+ const char *vg_name,
+ const char *lv_name,
+ const char *uuid)
{
- struct physical_volume *pv;
- struct volume_group *vg;
-
- /* Reread all metadata in case it got changed */
- if (!(pv = find_pv_by_name(cmd, name, 0, 0))) {
- log_error("ABORTING: Can't reread PV %s", name);
- /* What more could we do here? */
+ struct poll_operation_id *id = dm_pool_alloc(cmd->mem, sizeof(struct poll_operation_id));
+ if (!id) {
+ log_error("Poll operation ID allocation failed.");
return NULL;
}
- vg = _get_vg(cmd, pv_vg_name(pv));
- free_pv_fid(pv);
+ id->vg_name = vg_name ? dm_pool_strdup(cmd->mem, vg_name) : NULL;
+ id->lv_name = lv_name ? dm_pool_strdup(cmd->mem, lv_name) : NULL;
+ id->display_name = pv_name ? dm_pool_strdup(cmd->mem, pv_name) : NULL;
+ id->uuid = uuid ? dm_pool_strdup(cmd->mem, uuid) : NULL;
- return vg;
-}
+ if (!id->vg_name || !id->lv_name || !id->display_name || !id->uuid) {
+ log_error("Failed to copy one or more poll operation ID members.");
+ _destroy_id(cmd, id);
+ id = NULL;
+ }
-static struct poll_functions _pvmove_fns = {
- .get_copy_name_from_lv = get_pvmove_pvname_from_lv_mirr,
- .get_copy_vg = _get_move_vg,
- .get_copy_lv = find_pvmove_lv_from_pvname,
- .poll_progress = poll_mirror_progress,
- .update_metadata = _update_metadata,
- .finish_copy = _finish_pvmove,
-};
+ return id;
+}
int pvmove_poll(struct cmd_context *cmd, const char *pv_name,
- unsigned background)
+ const char *uuid, const char *vg_name,
+ const char *lv_name, unsigned background)
{
+ int r;
+ struct poll_operation_id *id = NULL;
+
if (test_mode())
return ECMD_PROCESSED;
- return poll_daemon(cmd, pv_name, NULL, background, PVMOVE, &_pvmove_fns,
- "Moved");
+ if (uuid) {
+ id = _create_id(cmd, pv_name, vg_name, lv_name, uuid);
+ if (!id) {
+ log_error("Failed to allocate poll identifier for pvmove.");
+ return ECMD_FAILED;
+ }
+ }
+
+ r = poll_daemon(cmd, background, PVMOVE, &_pvmove_fns, "Moved", id);
+
+ _destroy_id(cmd, id);
+
+ return r;
}
int pvmove(struct cmd_context *cmd, int argc, char **argv)
{
- char *pv_name = NULL;
char *colon;
int ret;
+ unsigned in_progress = 1;
+ union lvid *lvid = NULL;
+ char *pv_name = NULL, *vg_name = NULL, *lv_name = NULL;
/* dm raid1 target must be present in every case */
if (!_pvmove_target_present(cmd, 0)) {
@@ -930,9 +850,32 @@ int pvmove(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
+ if (lvmlockd_use() && !lvmpolld_use()) {
+ /*
+ * Don't want to spend the time making lvmlockd
+ * work without lvmpolld.
+ */
+ log_error("Enable lvmpolld when using lvmlockd.");
+ return ECMD_FAILED;
+ }
+
+ if (lvmlockd_use() && !argc) {
+ /*
+ * FIXME: move process_each_vg from polldaemon up to here,
+ * then we can remove this limitation.
+ */
+ log_error("Specify pvmove args when using lvmlockd.");
+ return ECMD_FAILED;
+ }
+
if (argc) {
+ if (!(lvid = dm_pool_alloc(cmd->mem, sizeof(*lvid)))) {
+ log_error("Failed to allocate lvid.");
+ return ECMD_FAILED;
+ }
+
if (!(pv_name = dm_pool_strdup(cmd->mem, argv[0]))) {
- log_error("Failed to clone PV name");
+ log_error("Failed to clone PV name.");
return ECMD_FAILED;
}
@@ -942,13 +885,36 @@ int pvmove(struct cmd_context *cmd, int argc, char **argv)
if (colon)
*colon = '\0';
- if (!arg_count(cmd, abort_ARG) &&
- (ret = _set_up_pvmove(cmd, pv_name, argc, argv)) !=
- ECMD_PROCESSED) {
+ /*
+ * To do a reverse mapping from PV name to VG name, we need the
+ * correct global mapping of PVs to VGs.
+ */
+ if (!lockd_gl(cmd, "sh", 0)) {
stack;
- return ret;
+ return ECMD_FAILED;
+ }
+
+ if (!arg_count(cmd, abort_ARG)) {
+ if ((ret = _set_up_pvmove(cmd, pv_name, argc, argv, lvid, &vg_name, &lv_name)) != ECMD_PROCESSED) {
+ stack;
+ return ret;
+ }
+ } else {
+ if (!_read_poll_id_from_pvname(cmd, pv_name, lvid, &vg_name, &lv_name, &in_progress))
+ return_ECMD_FAILED;
+
+ if (!in_progress)
+ return ECMD_PROCESSED;
}
+
+ /*
+ * The command may sit and report progress for some time,
+ * and we do not want or need the lockd locks held during
+ * that time.
+ */
+ lockd_gl(cmd, "un", 0);
}
- return pvmove_poll(cmd, pv_name, arg_is_set(cmd, background_ARG));
+ return pvmove_poll(cmd, pv_name, lvid ? lvid->s : NULL, vg_name, lv_name,
+ arg_is_set(cmd, background_ARG));
}