diff options
| -rw-r--r-- | tools/lvconvert.c | 154 |
1 files changed, 126 insertions, 28 deletions
diff --git a/tools/lvconvert.c b/tools/lvconvert.c index e673f53b6..df07a3c10 100644 --- a/tools/lvconvert.c +++ b/tools/lvconvert.c @@ -19,6 +19,33 @@ #include "lvconvert_poll.h" #include "lvmpolld-client.h" +/* + * lvconvert polling + * + * The main part of lvconvert starts the operation, and creates + * an "id" from the VG/LV that can be handed to the polling functions. + * + * lvconvert: + * lock vg + * vg_read + * process lvs + * "single" function uses vg/lv structs to start convert + * create_lv_id_to_poll uses vg/lv structs to create lvid_to_poll id + * unlock vg + * release vg + * _poll_logical_volume(): use lvid_to_poll to start polling, do not use lv struct + * _lvconvert_poll_lvid(lvid); + * poll_daemon(fns, id); + * + * The polling then independently does: + * lock vg + * vg_read + * find lv from the "id" + * check or finish the lv + * unlock vg + * release vg + */ + struct lvconvert_params { int cache; int force; @@ -41,6 +68,9 @@ struct lvconvert_params { int wait_completion; int need_polling; + int is_merging_origin; + int is_merging_origin_thin; + int thin_chunk_size_calc_policy; uint32_t chunk_size; uint32_t region_size; @@ -69,6 +99,7 @@ struct lvconvert_params { struct dm_list *replace_pvh; struct logical_volume *lv_to_poll; + struct poll_operation_id *lvid_to_poll; uint32_t pool_metadata_extents; int passed_args; @@ -763,32 +794,84 @@ static struct poll_operation_id *_create_id(struct cmd_context *cmd, return id; } -int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv, - unsigned background) +/* + * This is called from lvconvert internals with the VG lock held, to + * create lp->lvid_to_poll from lp->lv_to_poll. + * The lv in lp->lv_to_poll cannot be used after the command when the + * VG lock is released, so we need to use the lvid. + */ +static void create_lvid_to_poll(struct cmd_context *cmd, struct lvconvert_params *lp) { - int is_thin, r; - struct poll_operation_id *id = _create_id(cmd, lv->vg->name, lv->name, lv->lvid.s); + struct lvinfo info; + struct logical_volume *lv = lp->lv_to_poll; - if (!id) { + /* Prevent this lv being used in polling. */ + lp->lv_to_poll = NULL; + + if (!lv_info(cmd, lv, 0, &info, 0, 0) || !info.exists) { + log_print_unless_silent("Conversion starts after activation."); + return; + } + + if (!(lp->lvid_to_poll = _create_id(cmd, lv->vg->name, lv->name, lv->lvid.s))) { + /* + * FIXME: print a message indicating that another command + * should be run to do the polling. + */ log_error("Failed to allocate poll identifier for lvconvert."); - return ECMD_FAILED; + return; } + /* FIXME: check this in polling instead */ if (lv_is_merging_origin(lv)) { - is_thin = seg_is_thin_volume(find_snapshot(lv)); + lp->is_merging_origin = 1; + lp->is_merging_origin_thin = seg_is_thin_volume(find_snapshot(lv)); + } +} + +static int _lvconvert_poll_lvid(struct cmd_context *cmd, struct poll_operation_id *id, + unsigned background, + int is_merging_origin, + int is_merging_origin_thin) +{ + int r; + + if (is_merging_origin) { r = poll_daemon(cmd, background, - (MERGING | (is_thin ? THIN_VOLUME : SNAPSHOT)), - is_thin ? &_lvconvert_thin_merge_fns : &_lvconvert_merge_fns, + (MERGING | (is_merging_origin_thin ? THIN_VOLUME : SNAPSHOT)), + is_merging_origin_thin ? &_lvconvert_thin_merge_fns : &_lvconvert_merge_fns, "Merged", id); - } else + } else { r = poll_daemon(cmd, background, CONVERTING, &_lvconvert_mirror_fns, "Converted", id); + } _destroy_id(cmd, id); return r; } +int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv, + unsigned background) +{ + struct poll_operation_id *id = _create_id(cmd, lv->vg->name, lv->name, lv->lvid.s); + int is_merging_origin = 0; + int is_merging_origin_thin = 0; + + if (!id) { + log_error("Failed to allocate poll identifier for lvconvert."); + return ECMD_FAILED; + } + + /* FIXME: check this in polling instead */ + if (lv_is_merging_origin(lv)) { + is_merging_origin = 1; + is_merging_origin_thin = seg_is_thin_volume(find_snapshot(lv)); + } + + return _lvconvert_poll_lvid(cmd, id, background, is_merging_origin, is_merging_origin_thin); +} + static int _insert_lvconvert_layer(struct cmd_context *cmd, struct logical_volume *lv) { @@ -3330,17 +3413,19 @@ static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv, return ECMD_PROCESSED; } -static int _poll_logical_volume(struct cmd_context *cmd, struct logical_volume *lv, - int wait_completion) +/* + * The VG lock is not held, and VG/LV structs should not be used. + * lp->lvid_to_poll was created by create_lvid_to_poll() and identifies + * which LV to poll. + */ +static int _poll_logical_volume(struct cmd_context *cmd, struct lvconvert_params *lp) { - struct lvinfo info; - - if (!lv_info(cmd, lv, 0, &info, 0, 0) || !info.exists) { - log_print_unless_silent("Conversion starts after activation."); - return ECMD_PROCESSED; - } - - return lvconvert_poll(cmd, lv, wait_completion ? 0 : 1U); + if (lp->lvid_to_poll) + return _lvconvert_poll_lvid(cmd, lp->lvid_to_poll, + lp->wait_completion ? 0 : 1U, + lp->is_merging_origin, + lp->is_merging_origin_thin); + return 1; } static int lvconvert_single(struct cmd_context *cmd, struct lvconvert_params *lp) @@ -3402,7 +3487,11 @@ static int lvconvert_single(struct cmd_context *cmd, struct lvconvert_params *lp goto_bad; lp->lv_to_poll = lv; + ret = _lvconvert_single(cmd, lv, lp); + + if (ret == ECMD_PROCESSED && lp->need_polling) + create_lvid_to_poll(cmd, lp); bad: unlock_vg(cmd, lp->vg_name); @@ -3412,10 +3501,6 @@ bad: */ lockd_vg(cmd, lp->vg_name, "un", 0, &lockd_state); - if (ret == ECMD_PROCESSED && lp->need_polling) - ret = _poll_logical_volume(cmd, lp->lv_to_poll, - lp->wait_completion); - release_vg(vg); out: init_ignore_suspended_devices(saved_ignore_suspended_devices); @@ -3455,18 +3540,21 @@ static int _lvconvert_merge_single(struct cmd_context *cmd, struct logical_volum } lp->lv_to_poll = lv_fresh; + if ((ret = _lvconvert_single(cmd, lv_fresh, lp)) != ECMD_PROCESSED) stack; if (ret == ECMD_PROCESSED && lp->need_polling) { + create_lvid_to_poll(cmd, lp); + /* * Must drop VG lock, because lvconvert_poll() needs it, * then reacquire it after polling completes */ unlock_vg(cmd, vg_name); - if ((ret = _poll_logical_volume(cmd, lp->lv_to_poll, - lp->wait_completion)) != ECMD_PROCESSED) + /* FIXME: call this at the end of the command like the other cases. */ + if ((ret = _poll_logical_volume(cmd, lp)) != ECMD_PROCESSED) stack; /* use LCK_VG_WRITE to match lvconvert()'s READ_FOR_UPDATE */ @@ -3495,9 +3583,13 @@ static int _lvconvert_lvmpolld_merge_single(struct cmd_context *cmd, struct logi int ret; lp->lv_to_poll = lv; + if ((ret = _lvconvert_single(cmd, lv, lp)) != ECMD_PROCESSED) stack; + if (ret == ECMD_PROCESSED && lp->need_polling) + create_lvid_to_poll(cmd, lp); + return ret; } @@ -3528,11 +3620,17 @@ int lvconvert(struct cmd_context * cmd, int argc, char **argv) &_lvconvert_merge_single); if (ret == ECMD_PROCESSED && lvmpolld_use() && lp.need_polling) { - if ((ret = _poll_logical_volume(cmd, lp.lv_to_poll, lp.wait_completion)) != ECMD_PROCESSED) + if ((ret = _poll_logical_volume(cmd, &lp)) != ECMD_PROCESSED) stack; } - } else + } else { ret = lvconvert_single(cmd, &lp); + + if (ret == ECMD_PROCESSED && lp.need_polling) + if ((ret = _poll_logical_volume(cmd, &lp)) != ECMD_PROCESSED) + stack; + } + out: if (lp.policy_settings) dm_config_destroy(lp.policy_settings); |
