mirror of
git://sourceware.org/git/lvm2.git
synced 2025-03-10 16:58:47 +03:00
Separate out polldaemon.
This commit is contained in:
parent
23289e6d14
commit
cb919290c2
@ -1,5 +1,6 @@
|
|||||||
Version 2.00.16 -
|
Version 2.00.16 -
|
||||||
=============================
|
=============================
|
||||||
|
Separate out polldaemon.
|
||||||
Revise internal locking semantics.
|
Revise internal locking semantics.
|
||||||
Move find_pv_by_name to library.
|
Move find_pv_by_name to library.
|
||||||
Rename move->copy.
|
Rename move->copy.
|
||||||
|
@ -516,7 +516,7 @@ static int _print_snapshot(struct formatter *f, struct snapshot *snap,
|
|||||||
seg.stripe_size = 0;
|
seg.stripe_size = 0;
|
||||||
seg.area_count = 0;
|
seg.area_count = 0;
|
||||||
seg.area_len = 0;
|
seg.area_len = 0;
|
||||||
seg.extents_moved = 0;
|
seg.extents_copied = 0;
|
||||||
|
|
||||||
/* Can't tag a snapshot independently of its origin */
|
/* Can't tag a snapshot independently of its origin */
|
||||||
list_init(&seg.tags);
|
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->area_len = extent_count;
|
||||||
seg->status = 0u;
|
seg->status = 0u;
|
||||||
seg->segtype = segtype;
|
seg->segtype = segtype;
|
||||||
seg->extents_moved = 0u;
|
seg->extents_copied = 0u;
|
||||||
seg->area_count = area_count;
|
seg->area_count = area_count;
|
||||||
|
|
||||||
if (seg->segtype->ops->text_import &&
|
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_len = area_len;
|
||||||
seg->area_count = area_count;
|
seg->area_count = area_count;
|
||||||
seg->stripe_size = stripe_size;
|
seg->stripe_size = stripe_size;
|
||||||
seg->extents_moved = 0u;
|
seg->extents_copied = 0u;
|
||||||
|
|
||||||
for (s = 0; s < area_count; s++) {
|
for (s = 0; s < area_count; s++) {
|
||||||
struct pv_area *pva = areas[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->area_len = count;
|
||||||
seg->stripe_size = 0;
|
seg->stripe_size = 0;
|
||||||
seg->area_count = 2;
|
seg->area_count = 2;
|
||||||
seg->extents_moved = 0u;
|
seg->extents_copied = 0u;
|
||||||
/* FIXME Remove AREA_PV restriction here? */
|
/* FIXME Remove AREA_PV restriction here? */
|
||||||
seg->area[0].type = AREA_PV;
|
seg->area[0].type = AREA_PV;
|
||||||
seg->area[0].u.pv.pv = mirrored_pv;
|
seg->area[0].u.pv.pv = mirrored_pv;
|
||||||
|
@ -207,7 +207,7 @@ struct lv_segment {
|
|||||||
struct logical_volume *origin;
|
struct logical_volume *origin;
|
||||||
struct logical_volume *cow;
|
struct logical_volume *cow;
|
||||||
uint32_t chunk_size;
|
uint32_t chunk_size;
|
||||||
uint32_t extents_moved;
|
uint32_t extents_copied;
|
||||||
|
|
||||||
struct list tags;
|
struct list tags;
|
||||||
|
|
||||||
@ -517,11 +517,14 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
|||||||
int remove_pvmove_mirrors(struct volume_group *vg,
|
int remove_pvmove_mirrors(struct volume_group *vg,
|
||||||
struct logical_volume *lv_mirr);
|
struct logical_volume *lv_mirr);
|
||||||
struct logical_volume *find_pvmove_lv(struct volume_group *vg,
|
struct logical_volume *find_pvmove_lv(struct volume_group *vg,
|
||||||
struct device *dev);
|
struct device *dev, uint32_t lv_type);
|
||||||
struct physical_volume *get_pvmove_pv_from_lv(struct logical_volume *lv);
|
struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd,
|
||||||
struct physical_volume *get_pvmove_pv_from_lv_mirr(struct logical_volume
|
struct volume_group *vg,
|
||||||
*lv_mirr);
|
const char *name,
|
||||||
float pvmove_percent(struct logical_volume *lv_mirr);
|
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 list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||||
struct logical_volume *lv);
|
struct logical_volume *lv);
|
||||||
|
|
||||||
|
@ -122,7 +122,8 @@ int remove_pvmove_mirrors(struct volume_group *vg,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mir_seg->extents_moved == mir_seg->area_len)
|
if (mir_seg->extents_copied ==
|
||||||
|
mir_seg->area_len)
|
||||||
c = 1;
|
c = 1;
|
||||||
else
|
else
|
||||||
c = 0;
|
c = 0;
|
||||||
@ -148,8 +149,7 @@ int remove_pvmove_mirrors(struct volume_group *vg,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct physical_volume *get_pvmove_pv_from_lv_mirr(struct logical_volume
|
const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr)
|
||||||
*lv_mirr)
|
|
||||||
{
|
{
|
||||||
struct list *segh;
|
struct list *segh;
|
||||||
struct lv_segment *seg;
|
struct lv_segment *seg;
|
||||||
@ -160,13 +160,13 @@ struct physical_volume *get_pvmove_pv_from_lv_mirr(struct logical_volume
|
|||||||
continue;
|
continue;
|
||||||
if (seg->area[0].type != AREA_PV)
|
if (seg->area[0].type != AREA_PV)
|
||||||
continue;
|
continue;
|
||||||
return seg->area[0].u.pv.pv;
|
return dev_name(seg->area[0].u.pv.pv->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
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 list *segh;
|
||||||
struct lv_segment *seg;
|
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++) {
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
if (seg->area[s].type != AREA_LV)
|
if (seg->area[s].type != AREA_LV)
|
||||||
continue;
|
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 logical_volume *find_pvmove_lv(struct volume_group *vg,
|
||||||
struct device *dev)
|
struct device *dev,
|
||||||
|
uint32_t lv_type)
|
||||||
{
|
{
|
||||||
struct list *lvh, *segh;
|
struct list *lvh, *segh;
|
||||||
struct logical_volume *lv;
|
struct logical_volume *lv;
|
||||||
@ -195,7 +196,7 @@ struct logical_volume *find_pvmove_lv(struct volume_group *vg,
|
|||||||
list_iterate(lvh, &vg->lvs) {
|
list_iterate(lvh, &vg->lvs) {
|
||||||
lv = list_item(lvh, struct lv_list)->lv;
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
|
|
||||||
if (!(lv->status & PVMOVE))
|
if (!(lv->status & lv_type))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
list_iterate(segh, &lv->segments) {
|
list_iterate(segh, &lv->segments) {
|
||||||
@ -211,6 +212,21 @@ struct logical_volume *find_pvmove_lv(struct volume_group *vg,
|
|||||||
return NULL;
|
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 list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||||
struct logical_volume *lv)
|
struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
@ -255,7 +271,7 @@ struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
|
|||||||
return lvs;
|
return lvs;
|
||||||
}
|
}
|
||||||
|
|
||||||
float pvmove_percent(struct logical_volume *lv_mirr)
|
float copy_percent(struct logical_volume *lv_mirr)
|
||||||
{
|
{
|
||||||
uint32_t numerator = 0u, denominator = 0u;
|
uint32_t numerator = 0u, denominator = 0u;
|
||||||
struct list *segh;
|
struct list *segh;
|
||||||
@ -263,11 +279,13 @@ float pvmove_percent(struct logical_volume *lv_mirr)
|
|||||||
|
|
||||||
list_iterate(segh, &lv_mirr->segments) {
|
list_iterate(segh, &lv_mirr->segments) {
|
||||||
seg = list_item(segh, struct lv_segment);
|
seg = list_item(segh, struct lv_segment);
|
||||||
if (!(seg->status & PVMOVE))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
numerator += seg->extents_moved;
|
|
||||||
denominator += seg->area_len;
|
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;
|
return denominator ? (float) numerator *100 / denominator : 100.0;
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software Foundation,
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib.h"
|
#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;
|
const struct config_node *cn;
|
||||||
|
|
||||||
if (find_config_node(sn, "extents_moved")) {
|
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;
|
seg->status |= PVMOVE;
|
||||||
else {
|
else {
|
||||||
log_error("Couldn't read 'extents_moved' for "
|
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);
|
outf(f, "mirror_count = %u", seg->area_count);
|
||||||
if (seg->status & PVMOVE)
|
if (seg->status & PVMOVE)
|
||||||
out_size(f, (uint64_t) seg->extents_moved,
|
out_size(f, (uint64_t) seg->extents_copied,
|
||||||
"extents_moved = %u", seg->extents_moved);
|
"extents_moved = %u", seg->extents_copied);
|
||||||
|
|
||||||
return out_areas(f, seg, "mirror");
|
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]+
|
* #mirrors [device offset]+
|
||||||
*/
|
*/
|
||||||
if (seg->status & PVMOVE) {
|
if (seg->status & PVMOVE) {
|
||||||
if (seg->extents_moved == seg->area_len) {
|
if (seg->extents_copied == seg->area_len) {
|
||||||
mirror_status = MIRR_COMPLETED;
|
mirror_status = MIRR_COMPLETED;
|
||||||
start_area = 1;
|
start_area = 1;
|
||||||
} else if (*pvmove_mirror_count++) {
|
} else if (*pvmove_mirror_count++) {
|
||||||
@ -186,8 +186,8 @@ static int _target_percent(void **target_state, struct pool *mem,
|
|||||||
*total_numerator += numerator;
|
*total_numerator += numerator;
|
||||||
*total_denominator += denominator;
|
*total_denominator += denominator;
|
||||||
|
|
||||||
if (seg && (seg->status & PVMOVE))
|
if (seg)
|
||||||
seg->extents_moved = mirr_state->region_size *
|
seg->extents_copied = mirr_state->region_size *
|
||||||
numerator / seg->lv->vg->extent_size;
|
numerator / seg->lv->vg->extent_size;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -230,7 +230,7 @@ struct segment_type *init_segtype(struct cmd_context *cmd)
|
|||||||
segtype->ops = &_mirrored_ops;
|
segtype->ops = &_mirrored_ops;
|
||||||
segtype->name = "mirror";
|
segtype->name = "mirror";
|
||||||
segtype->private = NULL;
|
segtype->private = NULL;
|
||||||
segtype->flags = SEG_CAN_SPLIT | SEG_AREAS_MIRRORED;
|
segtype->flags = SEG_AREAS_MIRRORED;
|
||||||
|
|
||||||
return segtype;
|
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;
|
const struct lv_segment *seg = (const struct lv_segment *) data;
|
||||||
unsigned int s;
|
unsigned int s;
|
||||||
const char *devname;
|
const char *name;
|
||||||
uint32_t extent;
|
uint32_t extent;
|
||||||
char extent_str[32];
|
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++) {
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
switch (seg->area[s].type) {
|
switch (seg->area[s].type) {
|
||||||
case AREA_LV:
|
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;
|
extent = seg->area[s].u.lv.le;
|
||||||
break;
|
break;
|
||||||
case AREA_PV:
|
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;
|
extent = seg->area[s].u.pv.pe;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
devname = "unknown";
|
name = "unknown";
|
||||||
extent = 0;
|
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");
|
log_error("pool_grow_object failed");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -738,7 +738,7 @@ static int _copypercent_disp(struct report_handle *rh, struct field *field,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
percent = pvmove_percent(lv);
|
percent = copy_percent(lv);
|
||||||
|
|
||||||
if (!(repstr = pool_zalloc(rh->mem, 8))) {
|
if (!(repstr = pool_zalloc(rh->mem, 8))) {
|
||||||
log_error("pool_alloc failed");
|
log_error("pool_alloc failed");
|
||||||
|
@ -31,6 +31,7 @@ SOURCES =\
|
|||||||
lvrename.c \
|
lvrename.c \
|
||||||
lvresize.c \
|
lvresize.c \
|
||||||
lvscan.c \
|
lvscan.c \
|
||||||
|
polldaemon.c \
|
||||||
pvchange.c \
|
pvchange.c \
|
||||||
pvcreate.c \
|
pvcreate.c \
|
||||||
pvdisplay.c \
|
pvdisplay.c \
|
||||||
|
@ -76,20 +76,26 @@ static int lvchange_availability(struct cmd_context *cmd,
|
|||||||
struct logical_volume *lv)
|
struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
int activate = 0;
|
int activate = 0;
|
||||||
struct physical_volume *pv;
|
const char *pvname;
|
||||||
|
|
||||||
if (strcmp(arg_str_value(cmd, available_ARG, "n"), "n"))
|
if (strcmp(arg_str_value(cmd, available_ARG, "n"), "n"))
|
||||||
activate = 1;
|
activate = 1;
|
||||||
|
|
||||||
if (activate) {
|
if (activate) {
|
||||||
/* FIXME Tighter locking if lv_is_origin() */
|
|
||||||
log_verbose("Activating logical volume \"%s\"", lv->name);
|
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;
|
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",
|
log_verbose("Spawning background pvmove process for %s",
|
||||||
dev_name(pv->dev));
|
pvname);
|
||||||
pvmove_poll(cmd, dev_name(pv->dev), 1);
|
pvmove_poll(cmd, pvname, 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log_verbose("Deactivating logical volume \"%s\"", lv->name);
|
log_verbose("Deactivating logical volume \"%s\"", lv->name);
|
||||||
@ -257,7 +263,7 @@ static int lvchange_persistent(struct cmd_context *cmd,
|
|||||||
}
|
}
|
||||||
active = 1;
|
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)) {
|
if (!deactivate_lv(cmd, lv->lvid.s)) {
|
||||||
log_error("%s: deactivation failed", lv->name);
|
log_error("%s: deactivation failed", lv->name);
|
||||||
return 0;
|
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 "tools.h"
|
||||||
#include <signal.h>
|
#include "polldaemon.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allow /dev/vgname/lvname, vgname/lvname or lvname */
|
/* Allow /dev/vgname/lvname, vgname/lvname or lvname */
|
||||||
static const char *_extract_lvname(struct cmd_context *cmd, const char *vgname,
|
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;
|
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,
|
static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
|
||||||
struct volume_group *vg,
|
struct volume_group *vg,
|
||||||
struct physical_volume *pv,
|
struct physical_volume *pv,
|
||||||
@ -265,8 +212,9 @@ static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg,
|
|||||||
|
|
||||||
if (first_time) {
|
if (first_time) {
|
||||||
if (!activate_lv(cmd, lv_mirr->lvid.s)) {
|
if (!activate_lv(cmd, lv_mirr->lvid.s)) {
|
||||||
log_error
|
log_error("ABORTING: Temporary mirror activation "
|
||||||
("ABORTING: Temporary mirror activation failed.");
|
"failed. Run pvmove --abort.");
|
||||||
|
/* FIXME Resume using *original* metadata here! */
|
||||||
resume_lvs(cmd, lvs_changed);
|
resume_lvs(cmd, lvs_changed);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -318,7 +266,7 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
|
|||||||
return ECMD_FAILED;
|
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);
|
log_print("Detected pvmove in progress for %s", pv_name);
|
||||||
if (argc || lv_name)
|
if (argc || lv_name)
|
||||||
log_error("Ignoring remaining command line arguments");
|
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;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _check_pvmove_status(struct cmd_context *cmd,
|
static struct volume_group *_get_move_vg(struct cmd_context *cmd,
|
||||||
struct volume_group *vg,
|
const char *name)
|
||||||
struct logical_volume *lv_mirr,
|
|
||||||
const char *pv_name, struct pvmove_parms *parms,
|
|
||||||
int *finished)
|
|
||||||
{
|
{
|
||||||
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;
|
struct physical_volume *pv;
|
||||||
int finished = 0;
|
|
||||||
|
|
||||||
while (!finished) {
|
/* Reread all metadata in case it got changed */
|
||||||
if (parms->interval && !parms->aborting)
|
if (!(pv = find_pv_by_name(cmd, name))) {
|
||||||
sleep(parms->interval);
|
log_error("ABORTING: Can't reread PV %s", name);
|
||||||
|
/* What more could we do here? */
|
||||||
if (!(pv = find_pv_by_name(cmd, pv_name))) {
|
return NULL;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return _get_vg(cmd, pv->vg_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _poll_pvmove_vgs(struct cmd_context *cmd, const char *vgname,
|
static struct poll_functions _pvmove_fns = {
|
||||||
struct volume_group *vg, int consistent,
|
get_copy_name_from_lv:get_pvmove_pvname_from_lv_mirr,
|
||||||
void *handle)
|
get_copy_vg:_get_move_vg,
|
||||||
{
|
get_copy_lv:find_pvmove_lv_from_pvname,
|
||||||
struct pvmove_parms *parms = (struct pvmove_parms *) handle;
|
update_metadata:_update_metadata,
|
||||||
struct lv_list *lvl;
|
finish_copy:_finish_pvmove,
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int pvmove_poll(struct cmd_context *cmd, const char *pv_name,
|
int pvmove_poll(struct cmd_context *cmd, const char *pv_name,
|
||||||
unsigned background)
|
unsigned background)
|
||||||
{
|
{
|
||||||
struct pvmove_parms parms;
|
return poll_daemon(cmd, pv_name, background, PVMOVE, &_pvmove_fns);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int pvmove(struct cmd_context *cmd, int argc, char **argv)
|
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) &&
|
if (!arg_count(cmd, abort_ARG) &&
|
||||||
(ret = _set_up_pvmove(cmd, pv_name, argc, argv)) !=
|
(ret = _set_up_pvmove(cmd, pv_name, argc, argv)) !=
|
||||||
ECMD_PROCESSED) {
|
ECMD_PROCESSED) {
|
||||||
stack;
|
stack;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
|
|||||||
{
|
{
|
||||||
struct lv_list *lvl;
|
struct lv_list *lvl;
|
||||||
struct logical_volume *lv;
|
struct logical_volume *lv;
|
||||||
struct physical_volume *pv;
|
const char *pvname;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
list_iterate_items(lvl, &vg->lvs) {
|
list_iterate_items(lvl, &vg->lvs) {
|
||||||
@ -44,10 +44,10 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((lv->status & PVMOVE) &&
|
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",
|
log_verbose("Spawning background process for %s %s",
|
||||||
lv->name, dev_name(pv->dev));
|
lv->name, pvname);
|
||||||
pvmove_poll(cmd, dev_name(pv->dev), 1);
|
pvmove_poll(cmd, pvname, 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user