From 4cf8960c0c06551c7425da516b5b1c9f6626ff03 Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Wed, 5 May 2004 17:56:20 +0000 Subject: [PATCH] Separate out polldaemon. --- WHATS_NEW | 1 + lib/format_text/export.c | 2 +- lib/format_text/import_vsn1.c | 2 +- lib/metadata/lv_manip.c | 4 +- lib/metadata/metadata.h | 15 +- lib/metadata/mirror.c | 42 ++++-- lib/mirror/mirrored.c | 16 +-- lib/report/report.c | 12 +- tools/Makefile.in | 1 + tools/lvchange.c | 20 ++- tools/polldaemon.c | 264 ++++++++++++++++++++++++++++++++++ tools/polldaemon.h | 52 +++++++ tools/pvmove.c | 259 +++------------------------------ tools/vgchange.c | 8 +- 14 files changed, 415 insertions(+), 283 deletions(-) create mode 100644 tools/polldaemon.c create mode 100644 tools/polldaemon.h diff --git a/WHATS_NEW b/WHATS_NEW index 88dac6fbc..38a2805e5 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -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. diff --git a/lib/format_text/export.c b/lib/format_text/export.c index 7ae3072c9..d5ecb21bd 100644 --- a/lib/format_text/export.c +++ b/lib/format_text/export.c @@ -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); diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c index 07f84a86c..fc798f56c 100644 --- a/lib/format_text/import_vsn1.c +++ b/lib/format_text/import_vsn1.c @@ -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 && diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index 197aa8bb8..eb284fb3e 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -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; diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index 189d381b1..cebf1367a 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -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); diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c index 5e058c16f..7635d0ef6 100644 --- a/lib/metadata/mirror.c +++ b/lib/metadata/mirror.c @@ -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; diff --git a/lib/mirror/mirrored.c b/lib/mirror/mirrored.c index 846297c4a..b4b649531 100644 --- a/lib/mirror/mirrored.c +++ b/lib/mirror/mirrored.c @@ -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; } diff --git a/lib/report/report.c b/lib/report/report.c index a58dbef89..eb2a3a62c 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -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"); diff --git a/tools/Makefile.in b/tools/Makefile.in index 64c49aa9c..864bb316c 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -31,6 +31,7 @@ SOURCES =\ lvrename.c \ lvresize.c \ lvscan.c \ + polldaemon.c \ pvchange.c \ pvcreate.c \ pvdisplay.c \ diff --git a/tools/lvchange.c b/tools/lvchange.c index 040b5125f..c2f6e6e1c 100644 --- a/tools/lvchange.c +++ b/tools/lvchange.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; diff --git a/tools/polldaemon.c b/tools/polldaemon.c new file mode 100644 index 000000000..88506902a --- /dev/null +++ b/tools/polldaemon.c @@ -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 +#include + +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; +} diff --git a/tools/polldaemon.h b/tools/polldaemon.h new file mode 100644 index 000000000..81f16e650 --- /dev/null +++ b/tools/polldaemon.h @@ -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 diff --git a/tools/pvmove.c b/tools/pvmove.c index 322cf7c5b..e38da4dc1 100644 --- a/tools/pvmove.c +++ b/tools/pvmove.c @@ -14,60 +14,7 @@ */ #include "tools.h" -#include -#include - -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; } diff --git a/tools/vgchange.c b/tools/vgchange.c index 5464b1c54..940bd6d0c 100644 --- a/tools/vgchange.c +++ b/tools/vgchange.c @@ -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; }