1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-03-30 10:50:34 +03:00

polldaemon: refactor polling interfaces

Routines responsible for polling of in-progress pvmove, snapshot merge
or mirror conversion each used custom lookup functions to find vg and
lv involved in polling.

Especially pvmove used pvname to lookup pvmove in-progress. The future
lvmpolld will poll each operation by vg/lv name (internally by lvid).
Also there're plans to make pvmove able to move non-overlaping ranges
of extents instead of single PVs as of now. This would also require
to identify the opertion in different manner.

The poll_operation_id structure together with daemon_parms structure they
identify unambiguously the polling task.
This commit is contained in:
Ondrej Kozina 2015-04-10 14:08:19 +02:00
parent bda26acf70
commit 76a0dffe6f
8 changed files with 292 additions and 109 deletions

View File

@ -720,37 +720,68 @@ static struct poll_functions _lvconvert_thin_merge_fns = {
.finish_copy = lvconvert_merge_finish,
};
static void _destroy_id(struct cmd_context *cmd, struct poll_operation_id *id)
{
if (!id)
return;
dm_pool_free(cmd->mem, (void *)id);
}
static struct poll_operation_id *_create_id(struct cmd_context *cmd,
const char *vg_name,
const char *lv_name,
const char *uuid)
{
char lv_full_name[NAME_LEN];
struct poll_operation_id *id = dm_pool_alloc(cmd->mem, sizeof(struct poll_operation_id));
if (!id) {
log_error("Poll operation ID allocation failed.");
return NULL;
}
if (dm_snprintf(lv_full_name, sizeof(lv_full_name), "%s/%s", vg_name, lv_name) < 0) {
log_error(INTERNAL_ERROR "Name \"%s/%s\" is too long.", vg_name, lv_name);
_destroy_id(cmd, id);
return NULL;
}
id->display_name = dm_pool_strdup(cmd->mem, lv_full_name);
id->vg_name = vg_name ? dm_pool_strdup(cmd->mem, vg_name) : NULL;
id->lv_name = id->display_name ? strchr(id->display_name, '/') + 1 : NULL;
id->uuid = uuid ? dm_pool_strdup(cmd->mem, uuid) : NULL;
if (!id->vg_name || !id->lv_name || !id->display_name || !id->uuid) {
log_error("Failed to copy one or more poll operation ID members.");
_destroy_id(cmd, id);
id = NULL;
}
return id;
}
int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv,
unsigned background)
{
/*
* FIXME allocate an "object key" structure with split
* out members (vg_name, lv_name, uuid, etc) and pass that
* around the lvconvert and polldaemon code
* - will avoid needless work, e.g. extract_vgname()
* - unfortunately there are enough overloaded "name" dragons in
* the polldaemon, lvconvert, pvmove code that a comprehensive
* audit/rework is needed
*/
char uuid[sizeof(lv->lvid)];
char lv_full_name[NAME_LEN];
int is_thin, r;
struct poll_operation_id *id = _create_id(cmd, lv->vg->name, lv->name, lv->lvid.s);
if (dm_snprintf(lv_full_name, sizeof(lv_full_name), "%s/%s", lv->vg->name, lv->name) < 0) {
log_error(INTERNAL_ERROR "Name \"%s/%s\" is too long.", lv->vg->name, lv->name);
if (!id) {
log_error("Failed to allocate poll identifier for lvconvert.");
return ECMD_FAILED;
}
memcpy(uuid, &lv->lvid, sizeof(lv->lvid));
if (lv_is_merging_origin(lv)) {
is_thin = seg_is_thin_volume(find_snapshot(lv));
r = poll_daemon(cmd, lv_full_name, uuid, background, 0,
r = poll_daemon(cmd, background,
(MERGING | (is_thin ? THIN_VOLUME : SNAPSHOT)),
is_thin ? &_lvconvert_thin_merge_fns : &_lvconvert_merge_fns,
"Merged");
"Merged", id);
} else
r = poll_daemon(cmd, lv_full_name, uuid, background, 0,
&_lvconvert_mirror_fns, "Converted");
r = poll_daemon(cmd, background, CONVERTING,
&_lvconvert_mirror_fns, "Converted", id);
_destroy_id(cmd, id);
return r;
}

View File

@ -143,7 +143,7 @@ static void _sleep_and_rescan_devices(struct daemon_parms *parms)
}
}
static int _wait_for_single_lv(struct cmd_context *cmd, const char *name, const char *uuid,
static int _wait_for_single_lv(struct cmd_context *cmd, struct poll_operation_id *id,
struct daemon_parms *parms)
{
struct volume_group *vg;
@ -156,26 +156,26 @@ static int _wait_for_single_lv(struct cmd_context *cmd, const char *name, const
_sleep_and_rescan_devices(parms);
/* Locks the (possibly renamed) VG again */
vg = parms->poll_fns->get_copy_vg(cmd, name, uuid, READ_FOR_UPDATE);
vg = parms->poll_fns->get_copy_vg(cmd, id->vg_name, NULL, READ_FOR_UPDATE);
if (vg_read_error(vg)) {
release_vg(vg);
log_error("ABORTING: Can't reread VG for %s", name);
log_error("ABORTING: Can't reread VG for %s.", id->display_name);
/* What more could we do here? */
return 0;
}
lv = parms->poll_fns->get_copy_lv(cmd, vg, name, uuid, parms->lv_type);
lv = parms->poll_fns->get_copy_lv(cmd, vg, id->lv_name, id->uuid, parms->lv_type);
if (!lv && parms->lv_type == PVMOVE) {
log_print_unless_silent("%s: no pvmove in progress - already finished or aborted.",
name);
id->display_name);
unlock_and_release_vg(cmd, vg, vg->name);
return 1;
}
if (!lv) {
log_error("ABORTING: Can't find LV in %s for %s",
vg->name, name);
log_error("ABORTING: Can't find LV in %s for %s.",
vg->name, id->display_name);
unlock_and_release_vg(cmd, vg, vg->name);
return 0;
}
@ -185,12 +185,12 @@ static int _wait_for_single_lv(struct cmd_context *cmd, const char *name, const
* queried for its status. We must exit in this case.
*/
if (!lv_is_active_locally(lv)) {
log_print_unless_silent("%s: Interrupted: No longer active.", name);
log_print_unless_silent("%s: Interrupted: No longer active.", id->display_name);
unlock_and_release_vg(cmd, vg, vg->name);
return 1;
}
if (!_check_lv_status(cmd, vg, lv, name, parms, &finished)) {
if (!_check_lv_status(cmd, vg, lv, id->display_name, parms, &finished)) {
unlock_and_release_vg(cmd, vg, vg->name);
return_0;
}
@ -216,15 +216,65 @@ static int _wait_for_single_lv(struct cmd_context *cmd, const char *name, const
return 1;
}
struct poll_id_list {
struct dm_list list;
struct poll_operation_id *id;
};
static struct poll_operation_id *copy_poll_operation_id(struct dm_pool *mem,
const struct poll_operation_id *id)
{
struct poll_operation_id *copy;
if (!id)
return_NULL;
copy = (struct poll_operation_id *) dm_pool_alloc(mem, sizeof(struct poll_operation_id));
if (!copy) {
log_error("Poll operation ID allocation failed.");
return NULL;
}
copy->display_name = id->display_name ? dm_pool_strdup(mem, id->display_name) : NULL;
copy->lv_name = id->lv_name ? dm_pool_strdup(mem, id->lv_name) : NULL;
copy->vg_name = id->vg_name ? dm_pool_strdup(mem, id->vg_name) : NULL;
copy->uuid = id->uuid ? dm_pool_strdup(mem, id->uuid) : NULL;
if (!copy->display_name || !copy->lv_name || !copy->vg_name || !copy->uuid) {
log_error("Failed to copy one or more poll_operation_id members.");
return NULL;
}
return copy;
}
static struct poll_id_list* poll_id_list_create(struct dm_pool *mem,
const struct poll_operation_id *id)
{
struct poll_id_list *idl = (struct poll_id_list *) dm_pool_alloc(mem, sizeof(struct poll_id_list));
if (!idl) {
log_error("Poll ID list allocation failed.");
return NULL;
}
if (!(idl->id = copy_poll_operation_id(mem, id))) {
dm_pool_free(mem, idl);
return NULL;
}
return idl;
}
static int _poll_vg(struct cmd_context *cmd, const char *vgname,
struct volume_group *vg, struct processing_handle *handle)
{
struct daemon_parms *parms;
struct lv_list *lvl;
struct dm_list *sls;
struct dm_str_list *sl;
struct dm_list idls;
struct poll_id_list *idl;
struct poll_operation_id id;
struct logical_volume *lv;
const char *name;
int finished;
if (!handle || !(parms = (struct daemon_parms *) handle->custom_handle)) {
@ -232,8 +282,7 @@ static int _poll_vg(struct cmd_context *cmd, const char *vgname,
return ECMD_FAILED;
}
if (!(sls = str_list_create(cmd->mem)))
return ECMD_FAILED;
dm_list_init(&idls);
/*
* first iterate all LVs in a VG and collect LVs suitable
@ -243,11 +292,11 @@ static int _poll_vg(struct cmd_context *cmd, const char *vgname,
lv = lvl->lv;
if (!(lv->status & parms->lv_type))
continue;
name = parms->poll_fns->get_copy_name_from_lv(lv);
if (!name && !parms->aborting)
id.display_name = parms->poll_fns->get_copy_name_from_lv(lv);
if (!id.display_name && !parms->aborting)
continue;
if (!name) {
if (!id.display_name) {
log_error("Device name for LV %s not found in metadata. "
"(unfinished pvmove mirror removal?)", display_lvname(lv));
goto err;
@ -256,25 +305,33 @@ static int _poll_vg(struct cmd_context *cmd, const char *vgname,
/* FIXME Need to do the activation from _set_up_pvmove here
* if it's not running and we're not aborting. */
if (!lv_is_active(lv)) {
log_print_unless_silent("%s: Skipping inactive LV. Try lvchange or vgchange.", name);
log_print_unless_silent("%s: Skipping inactive LV. Try lvchange or vgchange.", id.display_name);
continue;
}
if (!str_list_add(cmd->mem, sls, dm_pool_strdup(cmd->mem, name))) {
log_error("Failed to clone pvname");
id.lv_name = lv->name;
id.vg_name = vg->name;
id.uuid = lv->lvid.s;
idl = poll_id_list_create(cmd->mem, &id);
if (!idl) {
log_error("Failed to create poll_id_list.");
goto err;
}
dm_list_add(&idls, &idl->list);
}
/* perform the poll operation on LVs collected in previous cycle */
dm_list_iterate_items(sl, sls) {
lv = parms->poll_fns->get_copy_lv(cmd, vg, sl->str, NULL, parms->lv_type);
if (lv && _check_lv_status(cmd, vg, lv, sl->str, parms, &finished) && !finished)
dm_list_iterate_items(idl, &idls) {
lv = parms->poll_fns->get_copy_lv(cmd, vg, idl->id->lv_name, idl->id->uuid, parms->lv_type);
if (lv && _check_lv_status(cmd, vg, lv, idl->id->display_name, parms, &finished) && !finished)
parms->outstanding_count++;
}
err:
dm_pool_free(cmd->mem, sls);
if (!dm_list_empty(&idls))
dm_pool_free(cmd->mem, dm_list_item(dm_list_first(&idls), struct poll_id_list));
return ECMD_PROCESSED;
}
@ -299,8 +356,8 @@ static void _poll_for_all_vgs(struct cmd_context *cmd,
* - 'background' is advisory so a child polldaemon may not be used even
* if it was requested.
*/
static int _poll_daemon(struct cmd_context *cmd, const char *name,
const char *uuid, struct daemon_parms *parms)
static int _poll_daemon(struct cmd_context *cmd, struct poll_operation_id *id,
struct daemon_parms *parms)
{
struct processing_handle *handle = NULL;
int daemon_mode = 0;
@ -319,8 +376,8 @@ static int _poll_daemon(struct cmd_context *cmd, const char *name,
/*
* Process one specific task or all incomplete tasks?
*/
if (name) {
if (!_wait_for_single_lv(cmd, name, uuid, parms)) {
if (id) {
if (!_wait_for_single_lv(cmd, id, parms)) {
stack;
ret = ECMD_FAILED;
}
@ -382,15 +439,16 @@ static int _daemon_parms_init(struct cmd_context *cmd, struct daemon_parms *parm
return 1;
}
int poll_daemon(struct cmd_context *cmd, const char *name, const char *uuid,
unsigned background,
int poll_daemon(struct cmd_context *cmd, unsigned background,
uint64_t lv_type, struct poll_functions *poll_fns,
const char *progress_title)
const char *progress_title, struct poll_operation_id *id)
{
struct daemon_parms parms;
if (!_daemon_parms_init(cmd, &parms, background, poll_fns, progress_title, lv_type))
return_EINVALID_CMD_LINE;
return _poll_daemon(cmd, name, uuid, &parms);
/* classical polling allows only PMVOVE or 0 values */
parms.lv_type &= PVMOVE;
return _poll_daemon(cmd, id, &parms);
}

View File

@ -52,6 +52,13 @@ struct poll_functions {
struct dm_list *lvs_changed);
};
struct poll_operation_id {
const char *vg_name;
const char *lv_name;
const char *display_name;
const char *uuid;
};
struct daemon_parms {
unsigned interval;
unsigned wait_before_testing;
@ -64,10 +71,9 @@ struct daemon_parms {
struct poll_functions *poll_fns;
};
int poll_daemon(struct cmd_context *cmd, const char *name, const char *uuid,
unsigned background,
int poll_daemon(struct cmd_context *cmd, unsigned background,
uint64_t lv_type, struct poll_functions *poll_fns,
const char *progress_title);
const char *progress_title, struct poll_operation_id *id);
progress_t poll_mirror_progress(struct cmd_context *cmd,
struct logical_volume *lv, const char *name,

View File

@ -569,8 +569,24 @@ out:
return r;
}
static int _copy_id_components(struct cmd_context *cmd,
const struct logical_volume *lv, char **vg_name,
char **lv_name, union lvid *lvid)
{
if (!(*vg_name = dm_pool_strdup(cmd->mem, lv->vg->name)) ||
!(*lv_name = dm_pool_strdup(cmd->mem, lv->name))) {
log_error("Failed to clone VG or LV name.");
return 0;
}
*lvid = lv->lvid;
return 1;
}
static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
int argc, char **argv)
int argc, char **argv, union lvid *lvid, char **vg_name,
char **lv_mirr_name)
{
const char *lv_name = NULL;
char *pv_name_arg;
@ -613,7 +629,7 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
/* Read VG */
log_verbose("Finding volume group \"%s\"", pv_vg_name(pv));
vg = get_vg(cmd, pv_vg_name(pv));
vg = poll_get_copy_vg(cmd, pv_vg_name(pv), NULL, READ_FOR_UPDATE);
if (vg_read_error(vg)) {
release_vg(vg);
return_ECMD_FAILED;
@ -674,6 +690,9 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
if (!_update_metadata(cmd, vg, lv_mirr, lvs_changed, exclusive))
goto_out;
if (!_copy_id_components(cmd, lv_mirr, vg_name, lv_mirr_name, lvid))
goto out;
/* LVs are all in status LOCKED */
r = ECMD_PROCESSED;
out:
@ -682,30 +701,122 @@ out:
return r;
}
static int _read_poll_id_from_pvname(struct cmd_context *cmd, const char *pv_name,
union lvid *lvid, char **vg_name, char **lv_name,
unsigned *in_progress)
{
int ret = 0;
struct logical_volume *lv;
struct physical_volume *pv;
struct volume_group *vg;
if (!pv_name) {
log_error(INTERNAL_ERROR "Invalid PV name parameter.");
return 0;
}
if (!(pv = find_pv_by_name(cmd, pv_name, 0, 0)))
return_0;
/* need read-only access */
vg = poll_get_copy_vg(cmd, pv_vg_name(pv), NULL, 0);
if (vg_read_error(vg)) {
log_error("ABORTING: Can't read VG for %s.", pv_name);
release_vg(vg);
free_pv_fid(pv);
return 0;
}
if (!(lv = find_pvmove_lv(vg, pv_dev(pv), PVMOVE))) {
log_print_unless_silent("%s: no pvmove in progress - already finished or aborted.",
pv_name);
ret = 1;
*in_progress = 0;
} else if (_copy_id_components(cmd, lv, vg_name, lv_name, lvid)) {
ret = 1;
*in_progress = 1;
}
unlock_and_release_vg(cmd, vg, pv_vg_name(pv));
free_pv_fid(pv);
return ret;
}
static struct poll_functions _pvmove_fns = {
.get_copy_name_from_lv = get_pvmove_pvname_from_lv_mirr,
.get_copy_vg = pvmove_get_copy_vg,
.get_copy_lv = find_pvmove_lv_from_pvname,
.get_copy_vg = poll_get_copy_vg,
.get_copy_lv = poll_get_copy_lv,
.poll_progress = poll_mirror_progress,
.update_metadata = pvmove_update_metadata,
.finish_copy = pvmove_finish,
};
int pvmove_poll(struct cmd_context *cmd, const char *pv_name,
unsigned background)
static void _destroy_id(struct cmd_context *cmd, struct poll_operation_id *id)
{
if (!id)
return;
dm_pool_free(cmd->mem, id);
}
static struct poll_operation_id *_create_id(struct cmd_context *cmd,
const char *pv_name,
const char *vg_name,
const char *lv_name,
const char *uuid)
{
struct poll_operation_id *id = dm_pool_alloc(cmd->mem, sizeof(struct poll_operation_id));
if (!id) {
log_error("Poll operation ID allocation failed.");
return NULL;
}
id->vg_name = vg_name ? dm_pool_strdup(cmd->mem, vg_name) : NULL;
id->lv_name = lv_name ? dm_pool_strdup(cmd->mem, lv_name) : NULL;
id->display_name = pv_name ? dm_pool_strdup(cmd->mem, pv_name) : NULL;
id->uuid = uuid ? dm_pool_strdup(cmd->mem, uuid) : NULL;
if (!id->vg_name || !id->lv_name || !id->display_name || !id->uuid) {
log_error("Failed to copy one or more poll operation ID members.");
_destroy_id(cmd, id);
id = NULL;
}
return id;
}
int pvmove_poll(struct cmd_context *cmd, const char *pv_name,
const char *uuid, const char *vg_name,
const char *lv_name, unsigned background)
{
int r;
struct poll_operation_id *id = NULL;
if (test_mode())
return ECMD_PROCESSED;
return poll_daemon(cmd, pv_name, NULL, background, PVMOVE, &_pvmove_fns,
"Moved");
if (uuid) {
id = _create_id(cmd, pv_name, vg_name, lv_name, uuid);
if (!id) {
log_error("Failed to allocate poll identifier for pvmove.");
return ECMD_FAILED;
}
}
r = poll_daemon(cmd, background, PVMOVE, &_pvmove_fns, "Moved", id);
_destroy_id(cmd, id);
return r;
}
int pvmove(struct cmd_context *cmd, int argc, char **argv)
{
char *pv_name = NULL;
char *colon;
int ret;
unsigned in_progress = 1;
union lvid *lvid = NULL;
char *pv_name = NULL, *vg_name = NULL, *lv_name = NULL;
/* dm raid1 target must be present in every case */
if (!_pvmove_target_present(cmd, 0)) {
@ -715,8 +826,13 @@ int pvmove(struct cmd_context *cmd, int argc, char **argv)
}
if (argc) {
if (!(lvid = dm_pool_alloc(cmd->mem, sizeof(*lvid)))) {
log_error("Failed to allocate lvid.");
return ECMD_FAILED;
}
if (!(pv_name = dm_pool_strdup(cmd->mem, argv[0]))) {
log_error("Failed to clone PV name");
log_error("Failed to clone PV name.");
return ECMD_FAILED;
}
@ -726,13 +842,20 @@ int pvmove(struct cmd_context *cmd, int argc, char **argv)
if (colon)
*colon = '\0';
if (!arg_count(cmd, abort_ARG) &&
(ret = _set_up_pvmove(cmd, pv_name, argc, argv)) !=
ECMD_PROCESSED) {
stack;
return ret;
if (!arg_count(cmd, abort_ARG)) {
if ((ret = _set_up_pvmove(cmd, pv_name, argc, argv, lvid, &vg_name, &lv_name)) != ECMD_PROCESSED) {
stack;
return ret;
}
} else {
if (!_read_poll_id_from_pvname(cmd, pv_name, lvid, &vg_name, &lv_name, &in_progress))
return_ECMD_FAILED;
if (!in_progress)
return ECMD_PROCESSED;
}
}
return pvmove_poll(cmd, pv_name, arg_is_set(cmd, background_ARG));
return pvmove_poll(cmd, pv_name, lvid ? lvid->s : NULL, vg_name, lv_name,
arg_is_set(cmd, background_ARG));
}

View File

@ -16,13 +16,6 @@
#include "pvmove_poll.h"
#include "tools.h"
struct volume_group *get_vg(struct cmd_context *cmd, const char *vgname)
{
dev_close_all();
return vg_read_for_update(cmd, vgname, NULL, 0);
}
static int _is_pvmove_image_removable(struct logical_volume *mimage_lv,
void *baton)
{
@ -201,23 +194,3 @@ int pvmove_finish(struct cmd_context *cmd, struct volume_group *vg,
return r;
}
struct volume_group *pvmove_get_copy_vg(struct cmd_context *cmd, const char *name,
const char *uuid __attribute__((unused)),
uint32_t flags __attribute__((unused)))
{
struct physical_volume *pv;
struct volume_group *vg;
/* Reread all metadata in case it got changed */
if (!(pv = find_pv_by_name(cmd, name, 0, 0))) {
log_error("ABORTING: Can't reread PV %s", name);
/* What more could we do here? */
return NULL;
}
vg = get_vg(cmd, pv_vg_name(pv));
free_pv_fid(pv);
return vg;
}

View File

@ -15,16 +15,11 @@
#ifndef _LVM_PVMOVE_H
#define _LVM_PVMOVE_H
/* FIXME: remove it after refactoring completes */
#include <stdint.h>
struct cmd_context;
struct dm_list;
struct logical_volume;
struct volume_group;
struct volume_group *get_vg(struct cmd_context *cmd, const char *vgname);
int pvmove_update_metadata(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv_mirr,
struct dm_list *lvs_changed, unsigned flags);
@ -32,8 +27,4 @@ int pvmove_update_metadata(struct cmd_context *cmd, struct volume_group *vg,
int pvmove_finish(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv_mirr, struct dm_list *lvs_changed);
struct volume_group *pvmove_get_copy_vg(struct cmd_context *cmd,
const char *name, const char *uuid,
uint32_t flags);
#endif /* _LVM_PVMOVE_H */

View File

@ -921,7 +921,7 @@ void lv_spawn_background_polling(struct cmd_context *cmd,
(pvname = get_pvmove_pvname_from_lv_mirr(lv_mirr))) {
log_verbose("Spawning background pvmove process for %s.",
pvname);
pvmove_poll(cmd, pvname, 1);
pvmove_poll(cmd, pvname, lv_mirr->lvid.s, lv_mirr->vg->name, lv_mirr->name, 1);
}
if (lv_is_converting(lv) || lv_is_merging(lv)) {

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@ -176,7 +176,8 @@ int32_t grouped_arg_int_value(const struct arg_values *av, int a, const int32_t
const char *command_name(struct cmd_context *cmd);
int pvmove_poll(struct cmd_context *cmd, const char *pv, unsigned background);
int pvmove_poll(struct cmd_context *cmd, const char *pv_name, const char *uuid,
const char *vg_name, const char *lv_name, unsigned background);
int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv, unsigned background);
int mirror_remove_missing(struct cmd_context *cmd,