1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

Separate out polldaemon.

This commit is contained in:
Alasdair Kergon 2004-05-05 17:56:20 +00:00
parent 23289e6d14
commit cb919290c2
14 changed files with 415 additions and 283 deletions

View File

@ -1,5 +1,6 @@
Version 2.00.16 -
=============================
Separate out polldaemon.
Revise internal locking semantics.
Move find_pv_by_name to library.
Rename move->copy.

View File

@ -516,7 +516,7 @@ static int _print_snapshot(struct formatter *f, struct snapshot *snap,
seg.stripe_size = 0;
seg.area_count = 0;
seg.area_len = 0;
seg.extents_moved = 0;
seg.extents_copied = 0;
/* Can't tag a snapshot independently of its origin */
list_init(&seg.tags);

View File

@ -294,7 +294,7 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
seg->area_len = extent_count;
seg->status = 0u;
seg->segtype = segtype;
seg->extents_moved = 0u;
seg->extents_copied = 0u;
seg->area_count = area_count;
if (seg->segtype->ops->text_import &&

View File

@ -109,7 +109,7 @@ static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
seg->area_len = area_len;
seg->area_count = area_count;
seg->stripe_size = stripe_size;
seg->extents_moved = 0u;
seg->extents_copied = 0u;
for (s = 0; s < area_count; s++) {
struct pv_area *pva = areas[s];
@ -282,7 +282,7 @@ static int _alloc_mirrored_area(struct logical_volume *lv, uint32_t *ix,
seg->area_len = count;
seg->stripe_size = 0;
seg->area_count = 2;
seg->extents_moved = 0u;
seg->extents_copied = 0u;
/* FIXME Remove AREA_PV restriction here? */
seg->area[0].type = AREA_PV;
seg->area[0].u.pv.pv = mirrored_pv;

View File

@ -207,7 +207,7 @@ struct lv_segment {
struct logical_volume *origin;
struct logical_volume *cow;
uint32_t chunk_size;
uint32_t extents_moved;
uint32_t extents_copied;
struct list tags;
@ -517,11 +517,14 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
int remove_pvmove_mirrors(struct volume_group *vg,
struct logical_volume *lv_mirr);
struct logical_volume *find_pvmove_lv(struct volume_group *vg,
struct device *dev);
struct physical_volume *get_pvmove_pv_from_lv(struct logical_volume *lv);
struct physical_volume *get_pvmove_pv_from_lv_mirr(struct logical_volume
*lv_mirr);
float pvmove_percent(struct logical_volume *lv_mirr);
struct device *dev, uint32_t lv_type);
struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd,
struct volume_group *vg,
const char *name,
uint32_t lv_type);
const char *get_pvmove_pvname_from_lv(struct logical_volume *lv);
const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr);
float copy_percent(struct logical_volume *lv_mirr);
struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv);

View File

@ -122,7 +122,8 @@ int remove_pvmove_mirrors(struct volume_group *vg,
return 0;
}
if (mir_seg->extents_moved == mir_seg->area_len)
if (mir_seg->extents_copied ==
mir_seg->area_len)
c = 1;
else
c = 0;
@ -148,8 +149,7 @@ int remove_pvmove_mirrors(struct volume_group *vg,
return 1;
}
struct physical_volume *get_pvmove_pv_from_lv_mirr(struct logical_volume
*lv_mirr)
const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr)
{
struct list *segh;
struct lv_segment *seg;
@ -160,13 +160,13 @@ struct physical_volume *get_pvmove_pv_from_lv_mirr(struct logical_volume
continue;
if (seg->area[0].type != AREA_PV)
continue;
return seg->area[0].u.pv.pv;
return dev_name(seg->area[0].u.pv.pv->dev);
}
return NULL;
}
struct physical_volume *get_pvmove_pv_from_lv(struct logical_volume *lv)
const char *get_pvmove_pvname_from_lv(struct logical_volume *lv)
{
struct list *segh;
struct lv_segment *seg;
@ -177,7 +177,7 @@ struct physical_volume *get_pvmove_pv_from_lv(struct logical_volume *lv)
for (s = 0; s < seg->area_count; s++) {
if (seg->area[s].type != AREA_LV)
continue;
return get_pvmove_pv_from_lv_mirr(seg->area[s].u.lv.lv);
return get_pvmove_pvname_from_lv_mirr(seg->area[s].u.lv.lv);
}
}
@ -185,7 +185,8 @@ struct physical_volume *get_pvmove_pv_from_lv(struct logical_volume *lv)
}
struct logical_volume *find_pvmove_lv(struct volume_group *vg,
struct device *dev)
struct device *dev,
uint32_t lv_type)
{
struct list *lvh, *segh;
struct logical_volume *lv;
@ -195,7 +196,7 @@ struct logical_volume *find_pvmove_lv(struct volume_group *vg,
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if (!(lv->status & PVMOVE))
if (!(lv->status & lv_type))
continue;
list_iterate(segh, &lv->segments) {
@ -211,6 +212,21 @@ struct logical_volume *find_pvmove_lv(struct volume_group *vg,
return NULL;
}
struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd,
struct volume_group *vg,
const char *name,
uint32_t lv_type)
{
struct physical_volume *pv;
if (!(pv = find_pv_by_name(cmd, name))) {
stack;
return NULL;
}
return find_pvmove_lv(vg, pv->dev, lv_type);
}
struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv)
{
@ -255,7 +271,7 @@ struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
return lvs;
}
float pvmove_percent(struct logical_volume *lv_mirr)
float copy_percent(struct logical_volume *lv_mirr)
{
uint32_t numerator = 0u, denominator = 0u;
struct list *segh;
@ -263,11 +279,13 @@ float pvmove_percent(struct logical_volume *lv_mirr)
list_iterate(segh, &lv_mirr->segments) {
seg = list_item(segh, struct lv_segment);
if (!(seg->status & PVMOVE))
continue;
numerator += seg->extents_moved;
denominator += seg->area_len;
if (seg->segtype->flags & SEG_AREAS_MIRRORED)
numerator += seg->extents_copied;
else
numerator += seg->area_len;
}
return denominator ? (float) numerator *100 / denominator : 100.0;

View File

@ -11,7 +11,6 @@
* You should have received a copy of the GNU 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 "lib.h"
@ -72,7 +71,8 @@ static int _text_import(struct lv_segment *seg, const struct config_node *sn,
const struct config_node *cn;
if (find_config_node(sn, "extents_moved")) {
if (get_config_uint32(sn, "extents_moved", &seg->extents_moved))
if (get_config_uint32(sn, "extents_moved",
&seg->extents_copied))
seg->status |= PVMOVE;
else {
log_error("Couldn't read 'extents_moved' for "
@ -94,8 +94,8 @@ static int _text_export(const struct lv_segment *seg, struct formatter *f)
{
outf(f, "mirror_count = %u", seg->area_count);
if (seg->status & PVMOVE)
out_size(f, (uint64_t) seg->extents_moved,
"extents_moved = %u", seg->extents_moved);
out_size(f, (uint64_t) seg->extents_copied,
"extents_moved = %u", seg->extents_copied);
return out_areas(f, seg, "mirror");
}
@ -139,7 +139,7 @@ static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
* #mirrors [device offset]+
*/
if (seg->status & PVMOVE) {
if (seg->extents_moved == seg->area_len) {
if (seg->extents_copied == seg->area_len) {
mirror_status = MIRR_COMPLETED;
start_area = 1;
} else if (*pvmove_mirror_count++) {
@ -186,8 +186,8 @@ static int _target_percent(void **target_state, struct pool *mem,
*total_numerator += numerator;
*total_denominator += denominator;
if (seg && (seg->status & PVMOVE))
seg->extents_moved = mirr_state->region_size *
if (seg)
seg->extents_copied = mirr_state->region_size *
numerator / seg->lv->vg->extent_size;
return 1;
@ -230,7 +230,7 @@ struct segment_type *init_segtype(struct cmd_context *cmd)
segtype->ops = &_mirrored_ops;
segtype->name = "mirror";
segtype->private = NULL;
segtype->flags = SEG_CAN_SPLIT | SEG_AREAS_MIRRORED;
segtype->flags = SEG_AREAS_MIRRORED;
return segtype;
}

View File

@ -129,7 +129,7 @@ static int _devices_disp(struct report_handle *rh, struct field *field,
{
const struct lv_segment *seg = (const struct lv_segment *) data;
unsigned int s;
const char *devname;
const char *name;
uint32_t extent;
char extent_str[32];
@ -141,19 +141,19 @@ static int _devices_disp(struct report_handle *rh, struct field *field,
for (s = 0; s < seg->area_count; s++) {
switch (seg->area[s].type) {
case AREA_LV:
devname = seg->area[s].u.lv.lv->name;
name = seg->area[s].u.lv.lv->name;
extent = seg->area[s].u.lv.le;
break;
case AREA_PV:
devname = dev_name(seg->area[s].u.pv.pv->dev);
name = dev_name(seg->area[s].u.pv.pv->dev);
extent = seg->area[s].u.pv.pe;
break;
default:
devname = "unknown";
name = "unknown";
extent = 0;
}
if (!pool_grow_object(rh->mem, devname, strlen(devname))) {
if (!pool_grow_object(rh->mem, name, strlen(name))) {
log_error("pool_grow_object failed");
return 0;
}
@ -738,7 +738,7 @@ static int _copypercent_disp(struct report_handle *rh, struct field *field,
return 1;
}
percent = pvmove_percent(lv);
percent = copy_percent(lv);
if (!(repstr = pool_zalloc(rh->mem, 8))) {
log_error("pool_alloc failed");

View File

@ -31,6 +31,7 @@ SOURCES =\
lvrename.c \
lvresize.c \
lvscan.c \
polldaemon.c \
pvchange.c \
pvcreate.c \
pvdisplay.c \

View File

@ -76,20 +76,26 @@ static int lvchange_availability(struct cmd_context *cmd,
struct logical_volume *lv)
{
int activate = 0;
struct physical_volume *pv;
const char *pvname;
if (strcmp(arg_str_value(cmd, available_ARG, "n"), "n"))
activate = 1;
if (activate) {
/* FIXME Tighter locking if lv_is_origin() */
log_verbose("Activating logical volume \"%s\"", lv->name);
if (!activate_lv(cmd, lv->lvid.s))
if (lv_is_origin(lv)) {
if (!activate_lv_excl(cmd, lv->lvid.s)) {
stack;
return 0;
if ((lv->status & LOCKED) && (pv = get_pvmove_pv_from_lv(lv))) {
}
} else if (!activate_lv(cmd, lv->lvid.s)) {
stack;
return 0;
}
if ((lv->status & LOCKED) && (pvname = get_pvmove_pvname_from_lv(lv))) {
log_verbose("Spawning background pvmove process for %s",
dev_name(pv->dev));
pvmove_poll(cmd, dev_name(pv->dev), 1);
pvname);
pvmove_poll(cmd, pvname, 1);
}
} else {
log_verbose("Deactivating logical volume \"%s\"", lv->name);
@ -257,7 +263,7 @@ static int lvchange_persistent(struct cmd_context *cmd,
}
active = 1;
}
log_print("Ensuring %s is inactive. ", lv->name);
log_verbose("Ensuring %s is inactive. ", lv->name);
if (!deactivate_lv(cmd, lv->lvid.s)) {
log_error("%s: deactivation failed", lv->name);
return 0;

264
tools/polldaemon.c Normal file
View File

@ -0,0 +1,264 @@
/*
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 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 General Public License v.2.
*
* You should have received a copy of the GNU 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 "polldaemon.h"
#include <signal.h>
#include <sys/wait.h>
static void _sigchld_handler(int sig)
{
while (wait4(-1, NULL, WNOHANG | WUNTRACED, NULL) > 0) ;
}
static int _become_daemon(struct cmd_context *cmd)
{
pid_t pid;
struct sigaction act = {
{_sigchld_handler},
.sa_flags = SA_NOCLDSTOP,
};
log_verbose("Forking background process");
sigaction(SIGCHLD, &act, NULL);
if ((pid = fork()) == -1) {
log_error("fork failed: %s", strerror(errno));
return 1;
}
/* Parent */
if (pid > 0)
return 0;
/* Child */
if (setsid() == -1)
log_error("Background process failed to setsid: %s",
strerror(errno));
init_verbose(VERBOSE_BASE_LEVEL);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
strncpy(*cmd->argv, "(lvm2copyd)", strlen(*cmd->argv));
reset_locking();
dev_close_all();
return 1;
}
static int _check_mirror_status(struct cmd_context *cmd,
struct volume_group *vg,
struct logical_volume *lv_mirr,
const char *name, struct daemon_parms *parms,
int *finished)
{
struct list *lvs_changed;
float segment_percent = 0.0, overall_percent = 0.0;
uint32_t event_nr = 0;
/* By default, caller should not retry */
*finished = 1;
if (parms->aborting) {
if (!(lvs_changed = lvs_using_lv(cmd, vg, lv_mirr))) {
log_error("Failed to generate list of copied LVs: "
"can't abort.");
return 0;
}
parms->poll_fns->finish_copy(cmd, vg, lv_mirr, lvs_changed);
return 0;
}
if (!lv_mirror_percent(lv_mirr, !parms->interval, &segment_percent,
&event_nr)) {
log_error("ABORTING: Mirror percentage check failed.");
return 0;
}
overall_percent = copy_percent(lv_mirr);
if (parms->progress_display)
log_print("%s: Moved: %.1f%%", name, overall_percent);
else
log_verbose("%s: Moved: %.1f%%", name, overall_percent);
if (segment_percent < 100.0) {
/* The only case the caller *should* try again later */
*finished = 0;
return 1;
}
if (!(lvs_changed = lvs_using_lv(cmd, vg, lv_mirr))) {
log_error("ABORTING: Failed to generate list of copied LVs");
return 0;
}
/* Finished? Or progress to next segment? */
if (overall_percent >= 100.0) {
if (!parms->poll_fns->finish_copy(cmd, vg, lv_mirr,
lvs_changed))
return 0;
} else {
if (!parms->poll_fns->update_metadata(cmd, vg, lv_mirr,
lvs_changed, 0)) {
log_error("ABORTING: Segment progression failed.");
parms->poll_fns->finish_copy(cmd, vg, lv_mirr,
lvs_changed);
return 0;
}
*finished = 0; /* Another segment */
}
return 1;
}
static int _wait_for_single_mirror(struct cmd_context *cmd, const char *name,
struct daemon_parms *parms)
{
struct volume_group *vg;
struct logical_volume *lv_mirr;
int finished = 0;
/* Poll for mirror completion */
while (!finished) {
/* FIXME Also needed in vg/lvchange -ay? */
/* FIXME Use alarm for regular intervals instead */
if (parms->interval && !parms->aborting)
sleep(parms->interval);
/* Locks the (possibly renamed) VG again */
if (!(vg = parms->poll_fns->get_copy_vg(cmd, name))) {
log_error("ABORTING: Can't reread VG for %s", name);
/* What more could we do here? */
return 0;
}
if (!(lv_mirr = parms->poll_fns->get_copy_lv(cmd, vg, name,
parms->lv_type))) {
log_error("ABORTING: Can't find mirror LV in %s for %s",
vg->name, name);
unlock_vg(cmd, vg->name);
return 0;
}
if (!_check_mirror_status(cmd, vg, lv_mirr, name, parms,
&finished)) {
unlock_vg(cmd, vg->name);
return 0;
}
unlock_vg(cmd, vg->name);
}
return 1;
}
static int _poll_vg(struct cmd_context *cmd, const char *vgname,
struct volume_group *vg, int consistent, void *handle)
{
struct daemon_parms *parms = (struct daemon_parms *) handle;
struct lv_list *lvl;
struct logical_volume *lv_mirr;
const char *name;
int finished;
if (!vg) {
log_error("Couldn't read volume group %s", vgname);
return ECMD_FAILED;
}
if (!consistent) {
log_error("Volume Group %s inconsistent - skipping", vgname);
/* FIXME Should we silently recover it here or not? */
return ECMD_FAILED;
}
if (vg->status & EXPORTED_VG) {
log_error("Volume group \"%s\" is exported", vg->name);
return ECMD_FAILED;
}
list_iterate_items(lvl, &vg->lvs) {
lv_mirr = lvl->lv;
if (!(lv_mirr->status & parms->lv_type))
continue;
if (!(name = parms->poll_fns->get_copy_name_from_lv(lv_mirr)))
continue;
/* FIXME Need to do the activation from _set_up_pvmove here
* if it's not running and we're not aborting */
if (_check_mirror_status(cmd, vg, lv_mirr, name,
parms, &finished) && !finished)
parms->outstanding_count++;
}
return ECMD_PROCESSED;
}
static void _poll_for_all_vgs(struct cmd_context *cmd,
struct daemon_parms *parms)
{
while (1) {
parms->outstanding_count = 0;
process_each_vg(cmd, 0, NULL, LCK_VG_WRITE, 1, parms, _poll_vg);
if (!parms->outstanding_count)
break;
sleep(parms->interval);
}
}
int poll_daemon(struct cmd_context *cmd, const char *name, unsigned background,
uint32_t lv_type, struct poll_functions *poll_fns)
{
struct daemon_parms parms;
parms.aborting = arg_count(cmd, abort_ARG) ? 1 : 0;
parms.background = background;
parms.interval = arg_uint_value(cmd, interval_ARG, DEFAULT_INTERVAL);
parms.progress_display = 1;
parms.lv_type = lv_type;
parms.poll_fns = poll_fns;
if (parms.interval && !parms.aborting)
log_verbose("Checking progress every %u seconds",
parms.interval);
if (!parms.interval) {
parms.progress_display = 0;
/* FIXME Disabled multiple-copy wait_event */
if (!name)
parms.interval = DEFAULT_INTERVAL;
}
if (parms.background) {
if (!_become_daemon(cmd))
return ECMD_PROCESSED; /* Parent */
parms.progress_display = 0;
/* FIXME Use wait_event (i.e. interval = 0) and */
/* fork one daemon per copy? */
}
if (name) {
if (!_wait_for_single_mirror(cmd, name, &parms))
return ECMD_FAILED;
} else
_poll_for_all_vgs(cmd, &parms);
return ECMD_PROCESSED;
}

52
tools/polldaemon.h Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 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 General Public License v.2.
*
* You should have received a copy of the GNU 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
*/
#ifndef _LVM_TOOL_POLLDAEMON_H
#define _LVM_TOOL_POLLDAEMON_H
#include "metadata.h"
struct poll_functions {
const char *(*get_copy_name_from_lv) (struct logical_volume * lv_mirr);
struct volume_group *(*get_copy_vg) (struct cmd_context * cmd,
const char *name);
struct logical_volume *(*get_copy_lv) (struct cmd_context * cmd,
struct volume_group * vg,
const char *name,
uint32_t lv_type);
int (*update_metadata) (struct cmd_context * cmd,
struct volume_group * vg,
struct logical_volume * lv_mirr,
struct list * lvs_changed, int first_time);
int (*finish_copy) (struct cmd_context * cmd,
struct volume_group * vg,
struct logical_volume * lv_mirr,
struct list * lvs_changed);
};
struct daemon_parms {
unsigned interval;
unsigned aborting;
unsigned background;
unsigned outstanding_count;
unsigned progress_display;
uint32_t lv_type;
struct poll_functions *poll_fns;
};
int poll_daemon(struct cmd_context *cmd, const char *name, unsigned background,
uint32_t lv_type, struct poll_functions *poll_fns);
#endif

View File

@ -14,60 +14,7 @@
*/
#include "tools.h"
#include <signal.h>
#include <sys/wait.h>
struct pvmove_parms {
unsigned interval;
unsigned aborting;
unsigned background;
unsigned outstanding_count;
unsigned progress_display;
};
static void _sigchld_handler(int sig)
{
while (wait4(-1, NULL, WNOHANG | WUNTRACED, NULL) > 0) ;
}
static int _become_daemon(struct cmd_context *cmd)
{
pid_t pid;
struct sigaction act = {
{_sigchld_handler},
.sa_flags = SA_NOCLDSTOP,
};
log_verbose("Forking background process");
sigaction(SIGCHLD, &act, NULL);
if ((pid = fork()) == -1) {
log_error("fork failed: %s", strerror(errno));
return 1;
}
/* Parent */
if (pid > 0)
return 0;
/* Child */
if (setsid() == -1)
log_error("Background process failed to setsid: %s",
strerror(errno));
init_verbose(VERBOSE_BASE_LEVEL);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
strncpy(*cmd->argv, "(pvmove)", strlen(*cmd->argv));
reset_locking();
dev_close_all();
return 1;
}
#include "polldaemon.h"
/* Allow /dev/vgname/lvname, vgname/lvname or lvname */
static const char *_extract_lvname(struct cmd_context *cmd, const char *vgname,
@ -173,7 +120,7 @@ static struct list *_get_allocatable_pvs(struct cmd_context *cmd, int argc,
return allocatable_pvs;
}
/* Create new LV with mirror segments for the required moves */
/* Create new LV with mirror segments for the required copies */
static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
struct volume_group *vg,
struct physical_volume *pv,
@ -265,8 +212,9 @@ static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg,
if (first_time) {
if (!activate_lv(cmd, lv_mirr->lvid.s)) {
log_error
("ABORTING: Temporary mirror activation failed.");
log_error("ABORTING: Temporary mirror activation "
"failed. Run pvmove --abort.");
/* FIXME Resume using *original* metadata here! */
resume_lvs(cmd, lvs_changed);
return 0;
}
@ -318,7 +266,7 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
return ECMD_FAILED;
}
if ((lv_mirr = find_pvmove_lv(vg, pv->dev))) {
if ((lv_mirr = find_pvmove_lv(vg, pv->dev, PVMOVE))) {
log_print("Detected pvmove in progress for %s", pv_name);
if (argc || lv_name)
log_error("Ignoring remaining command line arguments");
@ -452,194 +400,33 @@ static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg,
return r;
}
static int _check_pvmove_status(struct cmd_context *cmd,
struct volume_group *vg,
struct logical_volume *lv_mirr,
const char *pv_name, struct pvmove_parms *parms,
int *finished)
static struct volume_group *_get_move_vg(struct cmd_context *cmd,
const char *name)
{
struct list *lvs_changed;
float segment_percent = 0.0, overall_percent = 0.0;
uint32_t event_nr = 0;
*finished = 1;
if (parms->aborting) {
if (!(lvs_changed = lvs_using_lv(cmd, vg, lv_mirr))) {
log_error("Failed to generate list of moved LVs: "
"can't abort.");
return 0;
}
_finish_pvmove(cmd, vg, lv_mirr, lvs_changed);
return 0;
}
if (!lv_mirror_percent(lv_mirr, !parms->interval, &segment_percent,
&event_nr)) {
log_error("ABORTING: Mirror percentage check failed.");
return 0;
}
overall_percent = pvmove_percent(lv_mirr);
if (parms->progress_display)
log_print("%s: Moved: %.1f%%", pv_name, overall_percent);
else
log_verbose("%s: Moved: %.1f%%", pv_name, overall_percent);
if (segment_percent < 100.0) {
*finished = 0;
return 1;
}
if (!(lvs_changed = lvs_using_lv(cmd, vg, lv_mirr))) {
log_error("ABORTING: Failed to generate list of moved LVs");
return 0;
}
if (overall_percent >= 100.0) {
if (!_finish_pvmove(cmd, vg, lv_mirr, lvs_changed))
return 0;
} else {
if (!_update_metadata(cmd, vg, lv_mirr, lvs_changed, 0)) {
log_error("ABORTING: Segment progression failed.");
_finish_pvmove(cmd, vg, lv_mirr, lvs_changed);
return 0;
}
*finished = 0; /* Another segment */
}
return 1;
}
static int _wait_for_single_pvmove(struct cmd_context *cmd, const char *pv_name,
struct pvmove_parms *parms)
{
struct volume_group *vg;
struct logical_volume *lv_mirr;
struct physical_volume *pv;
int finished = 0;
while (!finished) {
if (parms->interval && !parms->aborting)
sleep(parms->interval);
if (!(pv = find_pv_by_name(cmd, pv_name))) {
log_error("ABORTING: Can't reread PV %s", pv_name);
return 0;
/* Reread all metadata in case it got changed */
if (!(pv = find_pv_by_name(cmd, name))) {
log_error("ABORTING: Can't reread PV %s", name);
/* What more could we do here? */
return NULL;
}
if (!(vg = _get_vg(cmd, pv->vg_name))) {
log_error("ABORTING: Can't reread VG %s", pv->vg_name);
return 0;
return _get_vg(cmd, pv->vg_name);
}
if (!(lv_mirr = find_pvmove_lv(vg, pv->dev))) {
log_error("ABORTING: Can't reread mirror LV in %s",
vg->name);
unlock_vg(cmd, pv->vg_name);
return 0;
}
if (!_check_pvmove_status(cmd, vg, lv_mirr, pv_name, parms,
&finished)) {
unlock_vg(cmd, pv->vg_name);
return 0;
}
unlock_vg(cmd, pv->vg_name);
}
return 1;
}
static int _poll_pvmove_vgs(struct cmd_context *cmd, const char *vgname,
struct volume_group *vg, int consistent,
void *handle)
{
struct pvmove_parms *parms = (struct pvmove_parms *) handle;
struct lv_list *lvl;
struct logical_volume *lv_mirr;
struct physical_volume *pv;
int finished;
if (!vg) {
log_error("Couldn't read volume group %s", vgname);
return ECMD_FAILED;
}
if (!consistent) {
log_error("Volume Group %s inconsistent - skipping", vgname);
/* FIXME Should we silently recover it here or not? */
return ECMD_FAILED;
}
if (vg->status & EXPORTED_VG) {
log_error("Volume group \"%s\" is exported", vg->name);
return ECMD_FAILED;
}
list_iterate_items(lvl, &vg->lvs) {
lv_mirr = lvl->lv;
if (!(lv_mirr->status & PVMOVE))
continue;
if (!(pv = get_pvmove_pv_from_lv_mirr(lv_mirr)))
continue;
if (_check_pvmove_status(cmd, vg, lv_mirr, dev_name(pv->dev),
parms, &finished) && !finished)
parms->outstanding_count++;
}
return ECMD_PROCESSED;
}
static void _poll_for_all_pvmoves(struct cmd_context *cmd,
struct pvmove_parms *parms)
{
while (1) {
parms->outstanding_count = 0;
process_each_vg(cmd, 0, NULL, LCK_VG_WRITE, 1,
parms, _poll_pvmove_vgs);
if (!parms->outstanding_count)
break;
sleep(parms->interval);
}
}
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,
update_metadata:_update_metadata,
finish_copy:_finish_pvmove,
};
int pvmove_poll(struct cmd_context *cmd, const char *pv_name,
unsigned background)
{
struct pvmove_parms parms;
parms.aborting = arg_count(cmd, abort_ARG) ? 1 : 0;
parms.background = background;
parms.interval = arg_uint_value(cmd, interval_ARG, DEFAULT_INTERVAL);
parms.progress_display = 1;
if (parms.interval && !parms.aborting)
log_verbose("Checking progress every %u seconds",
parms.interval);
if (!parms.interval) {
parms.progress_display = 0;
if (!pv_name)
parms.interval = DEFAULT_INTERVAL;
}
if (parms.background) {
if (!_become_daemon(cmd))
return ECMD_PROCESSED; /* Parent */
parms.progress_display = 0;
}
if (pv_name) {
if (!_wait_for_single_pvmove(cmd, pv_name, &parms))
return ECMD_FAILED;
} else
_poll_for_all_pvmoves(cmd, &parms);
return ECMD_PROCESSED;
return poll_daemon(cmd, pv_name, background, PVMOVE, &_pvmove_fns);
}
int pvmove(struct cmd_context *cmd, int argc, char **argv)

View File

@ -20,7 +20,7 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
{
struct lv_list *lvl;
struct logical_volume *lv;
struct physical_volume *pv;
const char *pvname;
int count = 0;
list_iterate_items(lvl, &vg->lvs) {
@ -44,10 +44,10 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
continue;
if ((lv->status & PVMOVE) &&
(pv = get_pvmove_pv_from_lv_mirr(lv))) {
(pvname = get_pvmove_pvname_from_lv_mirr(lv))) {
log_verbose("Spawning background process for %s %s",
lv->name, dev_name(pv->dev));
pvmove_poll(cmd, dev_name(pv->dev), 1);
lv->name, pvname);
pvmove_poll(cmd, pvname, 1);
continue;
}