1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-10-27 10:25:13 +03:00

Add pvmove

This commit is contained in:
Alasdair Kergon 2003-04-30 15:28:17 +00:00
parent 6faef15ecd
commit 43ecb8ffe4
5 changed files with 322 additions and 14 deletions

View File

@ -37,6 +37,7 @@ SOURCES=\
pvchange.c \
pvcreate.c \
pvdisplay.c \
pvmove.c \
pvremove.c \
pvscan.c \
report.c \

View File

@ -53,6 +53,7 @@ arg(help_ARG, 'h', "help", NULL)
arg(help2_ARG, '?', "", NULL)
arg(stripesize_ARG, 'I', "stripesize", size_kb_arg)
arg(stripes_ARG, 'i', "stripes", int_arg)
arg(interval_ARG, 'i', "interval", int_arg)
arg(iop_version_ARG, 'i', "iop_version", NULL)
arg(logicalvolume_ARG, 'l', "logicalvolume", int_arg)
arg(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", int_arg)

View File

@ -400,19 +400,22 @@ xx(pvdisplay,
xx(pvmove,
"Move extents from one physical volume to another",
"pvmove "
"[-A|--autobackup {y|n}] "
"[-d|--debug] "
"[-f|--force]"
"[-h|-?|--help]\n\t"
"[-t|--test] "
"[-v|--verbose] "
"[--version]\n\t"
"[{-n|--name} LogicalVolume[:LogicalExtent[-LogicalExtent]...]]\n\t"
"SourcePhysicalVolume[:PhysicalExtent[-PhysicalExtent]...]}\n\t"
"[DestinationPhysicalVolume[:PhysicalExtent[-PhysicalExtent]...]...]\n",
"pvmove " "\n"
"\t[-A|--autobackup {y|n}]\n"
"\t[-d|--debug]\n "
"\t[-f|--force]\n"
"\t[-h|-?|--help]\n"
"\t[-i|--interval seconds]\n"
"\t[-t|--test]\n "
"\t[-v|--verbose]\n "
"\t[--version]\n"
"\t[{-n|--name} LogicalVolume\n"
/* "\t[{-n|--name} LogicalVolume[:LogicalExtent[-LogicalExtent]...]]\n" */
"\tSourcePhysicalVolume\n"
/* "\tSourcePhysicalVolume[:PhysicalExtent[-PhysicalExtent]...]}\n" */
"\t[DestinationPhysicalVolume[:PhysicalExtent[-PhysicalExtent]...]...]\n",
autobackup_ARG, force_ARG, name_ARG, test_ARG)
autobackup_ARG, force_ARG, interval_ARG, name_ARG, test_ARG)
xx(pvremove,
"Remove LVM label(s) from physical volume(s)",
@ -536,7 +539,7 @@ xx(vgck,
"\t[-d|--debug]\n"
"\t[-h|--help]\n"
"\t[-v|--verbose]\n"
"\t[--version]" "\n",
"\t[--version]" "\n"
"\t[VolumeGroupName...]\n" )
xx(vgconvert,

304
tools/pvmove.c Normal file
View File

@ -0,0 +1,304 @@
/*
* Copyright (C) 2003 Sistina Software
*
* LVM is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* LVM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LVM; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "tools.h"
/* Allow /dev/vgname/lvname, vgname/lvname or lvname */
static const char *_extract_lvname(struct cmd_context *cmd, const char *vgname,
const char *arg)
{
const char *lvname;
/* Is an lvname supplied directly? */
if (!strchr(arg, '/'))
return arg;
lvname = arg;
if (!strncmp(lvname, cmd->dev_dir, strlen(cmd->dev_dir)))
lvname += strlen(cmd->dev_dir);
while (*lvname == '/')
lvname++;
if (!strchr(lvname, '/')) {
log_error("--name takes a logical volume name");
return NULL;
}
if (strncmp(vgname, lvname, strlen(vgname)) ||
(lvname += strlen(vgname), *lvname != '/')) {
log_error("Named LV and old PV must be in the same VG");
return NULL;
}
while (*lvname == '/')
lvname++;
if (!*lvname) {
log_error("Incomplete LV name supplied with --name");
return NULL;
}
return lvname;
}
int pvmove(struct cmd_context *cmd, int argc, char **argv)
{
char *pv_name;
const char *lv_name = NULL;
struct volume_group *vg;
struct list *allocatable_pvs, *pvht, *pvh, *lvh;
struct list lvs_changed;
struct pv_list *pvl;
struct physical_volume *pv;
struct logical_volume *lv, *lv_mirr;
int consistent = 1;
int success = 0;
int interval;
float percent = 0.0;
uint32_t event_nr = 0;
if (!argc) {
log_error("Old physical volume name needs specifying");
return EINVALID_CMD_LINE;
}
pv_name = argv[0];
argc--;
argv++;
/* Find VG containing the PV */
if (!(pv = pv_read(cmd, pv_name, NULL, NULL))) {
log_error("Physical volume %s not found", pv_name);
return EINVALID_CMD_LINE;
}
if (!pv->vg_name[0]) {
log_error("Physical volume %s not in a volume group", pv_name);
return EINVALID_CMD_LINE;
}
if (arg_count(cmd, name_ARG)) {
if (!(lv_name = _extract_lvname(cmd, pv->vg_name,
arg_value(cmd, name_ARG)))) {
stack;
return EINVALID_CMD_LINE;
}
}
/* Read VG */
log_verbose("Finding volume group \"%s\"", pv->vg_name);
if (!lock_vol(cmd, pv->vg_name, LCK_VG_WRITE)) {
log_error("Can't get lock for %s", pv->vg_name);
return ECMD_FAILED;
}
if (!(vg = vg_read(cmd, pv->vg_name, &consistent)) || !consistent) {
log_error("Volume group \"%s\" doesn't exist", pv->vg_name);
unlock_vg(cmd, pv->vg_name);
return ECMD_FAILED;
}
if (vg->status & EXPORTED_VG) {
log_error("Volume group \"%s\" is exported", pv->vg_name);
unlock_vg(cmd, pv->vg_name);
return ECMD_FAILED;
}
if (!(vg->status & LVM_WRITE)) {
log_error("Volume group \"%s\" is read-only", pv->vg_name);
unlock_vg(cmd, pv->vg_name);
return ECMD_FAILED;
}
/* Create list of PVs for allocation of replacement extents */
if (argc) {
if (!(allocatable_pvs = create_pv_list(cmd->mem, vg, argc,
argv))) {
stack;
unlock_vg(cmd, pv->vg_name);
return ECMD_FAILED;
}
} else {
if (!(allocatable_pvs = clone_pv_list(cmd->mem, &vg->pvs))) {
stack;
unlock_vg(cmd, pv->vg_name);
return ECMD_FAILED;
}
}
/* Don't allocate onto the PV we're clearing! */
/* Remove PV if full */
list_iterate_safe(pvh, pvht, allocatable_pvs) {
pvl = list_item(pvh, struct pv_list);
if ((pvl->pv->dev == pv->dev) ||
(pvl->pv->pe_count == pvl->pv->pe_alloc_count))
list_del(&pvl->list);
}
if (list_empty(allocatable_pvs)) {
log_error("No extents available for allocation");
unlock_vg(cmd, pv->vg_name);
return ECMD_FAILED;
}
if (!archive(vg)) {
unlock_vg(cmd, pv->vg_name);
stack;
return ECMD_FAILED;
}
if (!(lv_mirr = lv_create_empty(vg->fid, NULL, LVM_READ | LVM_WRITE,
ALLOC_CONTIGUOUS, vg))) {
log_error("Creation of temporary pvmove LV failed");
return ECMD_FAILED;
}
list_init(&lvs_changed);
/* Find segments to be moved and set up mirrors */
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if ((lv == lv_mirr) || (lv_name && strcmp(lv->name, lv_name)))
continue;
if (!insert_pvmove_mirrors(cmd, lv_mirr, pv, lv,
allocatable_pvs, &lvs_changed)) {
stack;
return ECMD_FAILED;
}
}
if (!lv_mirr->le_count) {
log_error("No data to move for %s", vg->name);
return ECMD_FAILED;
}
if (!lock_lvs(cmd, &lvs_changed, LCK_LV_ACTIVATE)) {
stack;
unlock_lvs(cmd, &lvs_changed);
unlock_vg(cmd, pv->vg_name);
return ECMD_FAILED;
}
if (!lock_lvs(cmd, &lvs_changed, LCK_LV_SUSPEND | LCK_HOLD)) {
stack;
unlock_lvs(cmd, &lvs_changed);
unlock_vg(cmd, pv->vg_name);
return ECMD_FAILED;
}
init_pvmove(1);
vg->status |= PVMOVE_VG;
log_verbose("Writing out volume group with temporary pvmove LV");
if (!vg_write(vg)) {
log_error("ABORTING: You might need to use vgcfgrestore "
"to recover.");
unlock_lvs(cmd, &lvs_changed);
unlock_vg(cmd, pv->vg_name);
return ECMD_FAILED;
}
if (!lock_vol(cmd, lv_mirr->lvid.s, LCK_LV_ACTIVATE)) {
log_error("ABORTING: Mirror activation failed. "
"Restoring metadata.");
unlock_lvs(cmd, &lvs_changed);
goto clearup;
}
unlock_lvs(cmd, &lvs_changed);
interval = arg_int_value(cmd, interval_ARG, DEFAULT_INTERVAL);
/* Poll for mirror completion */
while (percent < 100.0) {
if (interval)
sleep(interval);
if (!lv_mirror_percent(lv_mirr, !interval, &percent,
&event_nr)) {
log_error("ABORTING: Mirror percentage check failed. "
"Restoring metadata.");
break;
}
if (interval)
log_print("Mirror percent: %f", percent);
else
log_verbose("Mirror percent: %f", percent);
}
if (percent >= 100.0)
success = 1;
if (!lock_lvs(cmd, &lvs_changed, LCK_LV_SUSPEND | LCK_HOLD)) {
init_pvmove(0);
unlock_lvs(cmd, &lvs_changed);
unlock_vg(cmd, pv->vg_name);
return ECMD_FAILED;
}
if (!unlock_lv(cmd, lv_mirr->lvid.s)) {
log_error("Unable to unlock logical volume \"%s\"",
lv_mirr->name);
}
clearup:
if (!lock_vol(cmd, lv_mirr->lvid.s, LCK_LV_DEACTIVATE)) {
log_error("ABORTING: Unable to deactivate temporary logical "
"volume \"%s\"", lv_mirr->name);
log_error("You might need to use vgcfgrestore to recover.");
unlock_lvs(cmd, &lvs_changed);
unlock_vg(cmd, pv->vg_name);
return ECMD_FAILED;
}
if (!remove_pvmove_mirrors(cmd, vg, lv_mirr, success)) {
log_error("ABORTING: Temporary mirror removal failed");
log_error("You might need to use vgcfgrestore to recover.");
unlock_lvs(cmd, &lvs_changed);
unlock_vg(cmd, pv->vg_name);
return ECMD_FAILED;
}
if (!lv_remove(vg, lv_mirr)) {
log_error("ABORTING: Removal of temporary pvmove LV failed");
log_error("You might need to use vgcfgrestore to recover.");
unlock_lvs(cmd, &lvs_changed);
unlock_vg(cmd, pv->vg_name);
return ECMD_FAILED;
}
vg->status &= ~PVMOVE_VG;
init_pvmove(0);
log_verbose("Writing out final volume group after pvmove");
if (!vg_write(vg)) {
log_error("ABORTING: Failed to write new data locations "
"to disk.");
log_error("You might need to use vgcfgrestore to recover.");
unlock_lvs(cmd, &lvs_changed);
unlock_vg(cmd, pv->vg_name);
return ECMD_FAILED;
}
unlock_lvs(cmd, &lvs_changed);
backup(vg);
unlock_vg(cmd, pv->vg_name);
return success ? ECMD_PROCESSED : ECMD_FAILED;
}

View File

@ -10,6 +10,5 @@
int lvmsadc(struct cmd_context *cmd, int argc, char **argv) unimplemented
int lvmsar(struct cmd_context *cmd, int argc, char **argv) unimplemented
int pvdata(struct cmd_context *cmd, int argc, char **argv) unimplemented
int pvmove(struct cmd_context *cmd, int argc, char **argv) unimplemented
int pvresize(struct cmd_context *cmd, int argc, char **argv) unimplemented
int vgmknodes(struct cmd_context *cmd, int argc, char **argv) unimplemented