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:
parent
23289e6d14
commit
cb919290c2
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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 &&
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -31,6 +31,7 @@ SOURCES =\
|
||||
lvrename.c \
|
||||
lvresize.c \
|
||||
lvscan.c \
|
||||
polldaemon.c \
|
||||
pvchange.c \
|
||||
pvcreate.c \
|
||||
pvdisplay.c \
|
||||
|
@ -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;
|
||||
}
|
||||
} else if (!activate_lv(cmd, lv->lvid.s)) {
|
||||
stack;
|
||||
return 0;
|
||||
if ((lv->status & LOCKED) && (pv = get_pvmove_pv_from_lv(lv))) {
|
||||
}
|
||||
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
264
tools/polldaemon.c
Normal 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
52
tools/polldaemon.h
Normal 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
|
259
tools/pvmove.c
259
tools/pvmove.c
@ -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;
|
||||
}
|
||||
|
||||
if (!(vg = _get_vg(cmd, pv->vg_name))) {
|
||||
log_error("ABORTING: Can't reread VG %s", pv->vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
/* 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;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return _get_vg(cmd, pv->vg_name);
|
||||
}
|
||||
|
||||
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)
|
||||
@ -654,7 +441,7 @@ int pvmove(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
if (!arg_count(cmd, abort_ARG) &&
|
||||
(ret = _set_up_pvmove(cmd, pv_name, argc, argv)) !=
|
||||
ECMD_PROCESSED) {
|
||||
ECMD_PROCESSED) {
|
||||
stack;
|
||||
return ret;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user