The commit is pushed to "branch-rh9-5.14.0-427.44.1.vz9.80.x-ovz" and will appear at g...@bitbucket.org:openvz/vzkernel.git after rh9-5.14.0-427.44.1.vz9.80.19 ------> commit 4a2265edbd0d2e6313e7a145a6499a99192f2795 Author: Pavel Tikhomirov <ptikhomi...@virtuozzo.com> Date: Wed Mar 5 19:45:25 2025 +0800
dm-qcow2: add merge_backward progress command This allows to see progress of backward merge. It shows the stage we are at and for iterative stages it provides progress in form of how many iteratious are done and how many iterations there are in total. Locking: The progress data consistency is protected by tgt->ctl_mutex, we always update stage and error consistently under lock. Inside iterative stages for progress updating we have xchg instead of lock so that changes to progress are atomic and imply memory barrier (this way we would not see progress greater than max_progress in progress reporting), but at the same time there is less contention on tgt->ctl_mutex. https://virtuozzo.atlassian.net/browse/VSTOR-100466 Signed-off-by: Pavel Tikhomirov <ptikhomi...@virtuozzo.com> Reviewed-by: Andrey Zhadchenko <andrey.zhadche...@virtuozzo.com> ====== Patchset description: dm-qcow2: make backward merge asyncronous That can be usefull for restarting qemu process while allowing backward merging to run asyncronously in kernel. Feature: dm-qcow2: block device over QCOW2 files driver --- drivers/md/dm-qcow2-cmd.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/md/dm-qcow2.h | 15 +++++++++ 2 files changed, 100 insertions(+) diff --git a/drivers/md/dm-qcow2-cmd.c b/drivers/md/dm-qcow2-cmd.c index cd416ffc1814..89828f64cfe3 100644 --- a/drivers/md/dm-qcow2-cmd.c +++ b/drivers/md/dm-qcow2-cmd.c @@ -56,6 +56,10 @@ static void service_qio_endio(struct qcow2_target *tgt, struct qio *qio, wake_up(&tgt->service_wq); } +static void backward_merge_update_progress(struct qcow2_target *tgt, + long long progress); +static void backward_merge_update_max_progress(struct qcow2_target *tgt, + long long max_progress); static bool qcow2_backward_merge_should_stop(struct qcow2_target *tgt); static int qcow2_service_iter(struct qcow2_target *tgt, struct qcow2 *qcow2, @@ -68,7 +72,10 @@ static int qcow2_service_iter(struct qcow2_target *tgt, struct qcow2 *qcow2, WRITE_ONCE(service_status, BLK_STS_OK); + backward_merge_update_max_progress(tgt, end); for (pos = 0; pos < end; pos += step) { + backward_merge_update_progress(tgt, pos); + if (qcow2_backward_merge_should_stop(tgt)) { ret = -EINTR; break; @@ -167,6 +174,67 @@ static void set_backward_merge_in_process(struct qcow2_target *tgt, qcow2_submit_embedded_qios(tgt, &list); } +static void __backward_merge_update_stage(struct qcow2_target *tgt, + enum qcow2_backward_merge_stage stage) +{ + tgt->backward_merge.stage = stage; + tgt->backward_merge.progress = 0; + tgt->backward_merge.max_progress = 0; +} + +static void backward_merge_update_stage(struct qcow2_target *tgt, + enum qcow2_backward_merge_stage stage) +{ + mutex_lock(&tgt->ctl_mutex); + __backward_merge_update_stage(tgt, stage); + mutex_unlock(&tgt->ctl_mutex); +} + +static void backward_merge_update_max_progress(struct qcow2_target *tgt, + long long max_progress) +{ + xchg(&tgt->backward_merge.max_progress, max_progress); +} + +static void backward_merge_update_progress(struct qcow2_target *tgt, + long long progress) +{ + xchg(&tgt->backward_merge.progress, progress); +} + +char *backward_merge_stage_names[] = { + "none", + "start", + "break_l1cow", + "set_dirty", + "running", + "waiting_completion", + "completing", + "fail", +}; + +static int qcow2_merge_backward_progress(struct qcow2_target *tgt, + char *result, unsigned int maxlen) +{ + struct qcow2_backward_merge backward_merge; + unsigned int sz = 0; + int ret; + + BUILD_BUG_ON(ARRAY_SIZE(backward_merge_stage_names) != BACKWARD_MERGE_STAGE_MAX); + + mutex_lock(&tgt->ctl_mutex); + backward_merge = tgt->backward_merge; + mutex_unlock(&tgt->ctl_mutex); + + ret = DMEMIT("stage=%s\nprogress=%lld\nmax_progress=%lld\nerror=%d\n", + backward_merge_stage_names[backward_merge.stage], + backward_merge.progress, + backward_merge.max_progress, + backward_merge.error); + + return ret ? 1 : 0; +} + static int qcow2_merge_backward_set_eventfd(struct qcow2_target *tgt, int efd); static int qcow2_merge_backward_start(struct qcow2_target *tgt, int efd) @@ -193,6 +261,7 @@ static int qcow2_merge_backward_start(struct qcow2_target *tgt, int efd) return ret; tgt->backward_merge.state = BACKWARD_MERGE_START; + __backward_merge_update_stage(tgt, BACKWARD_MERGE_STAGE_START); tgt->backward_merge.error = 0; schedule_work(&tgt->backward_merge.work); @@ -216,6 +285,7 @@ void qcow2_merge_backward_work(struct work_struct *work) return; } tgt->backward_merge.state = BACKWARD_MERGE_RUN; + __backward_merge_update_stage(tgt, BACKWARD_MERGE_STAGE_BREAK_L1COW); mutex_unlock(&tgt->ctl_mutex); qcow2 = tgt->top; @@ -233,6 +303,7 @@ void qcow2_merge_backward_work(struct work_struct *work) goto out_err; } + backward_merge_update_stage(tgt, BACKWARD_MERGE_STAGE_SET_DIRTY); ret = qcow2_set_image_file_features(lower, true); if (ret) { QC_ERR(tgt->ti, "Can't set dirty bit"); @@ -241,6 +312,7 @@ void qcow2_merge_backward_work(struct work_struct *work) set_backward_merge_in_process(tgt, qcow2, true); /* Start merge */ + backward_merge_update_stage(tgt, BACKWARD_MERGE_STAGE_RUNNING); ret = qcow2_merge_common(tgt); if (ret) { set_backward_merge_in_process(tgt, qcow2, false); @@ -255,14 +327,17 @@ void qcow2_merge_backward_work(struct work_struct *work) /* Error */ tgt->backward_merge.state = BACKWARD_MERGE_STOPPED; tgt->backward_merge.error = ret; + __backward_merge_update_stage(tgt, BACKWARD_MERGE_STAGE_FAIL); } else if (tgt->backward_merge.state == BACKWARD_MERGE_STOP) { /* Merge is canceled */ set_backward_merge_in_process(tgt, qcow2, false); tgt->backward_merge.state = BACKWARD_MERGE_STOPPED; tgt->backward_merge.error = -EINTR; + __backward_merge_update_stage(tgt, BACKWARD_MERGE_STAGE_FAIL); } else { /* Finish merge */ tgt->backward_merge.state = BACKWARD_MERGE_WAIT_COMPLETION; + __backward_merge_update_stage(tgt, BACKWARD_MERGE_STAGE_WAITING_COMPLETION); } if (tgt->backward_merge.eventfd_ctx) eventfd_signal(tgt->backward_merge.eventfd_ctx, 1); @@ -279,6 +354,7 @@ static int qcow2_merge_backward_complete(struct qcow2_target *tgt) if (tgt->backward_merge.state != BACKWARD_MERGE_WAIT_COMPLETION) return -EBUSY; + __backward_merge_update_stage(tgt, BACKWARD_MERGE_STAGE_COMPLETING); tgt->top = lower; smp_wmb(); /* Pairs with qcow2_ref_inc() */ @@ -292,6 +368,7 @@ static int qcow2_merge_backward_complete(struct qcow2_target *tgt) qcow2_destroy(qcow2); tgt->backward_merge.state = BACKWARD_MERGE_STOPPED; + __backward_merge_update_stage(tgt, BACKWARD_MERGE_STAGE_NONE); return 0; } @@ -318,6 +395,7 @@ void qcow2_merge_backward_cancel(struct qcow2_target *tgt) } else if (tgt->backward_merge.state == BACKWARD_MERGE_WAIT_COMPLETION) { set_backward_merge_in_process(tgt, tgt->top, false); tgt->backward_merge.state = BACKWARD_MERGE_STOPPED; + __backward_merge_update_stage(tgt, BACKWARD_MERGE_STAGE_NONE); } mutex_unlock(&tgt->ctl_mutex); @@ -549,6 +627,13 @@ int qcow2_message(struct dm_target *ti, unsigned int argc, char **argv, } ret = qcow2_merge_backward_update_eventfd(tgt, efd); goto out; + } else if (!strcmp(argv[1], "progress")) { + if (argc != 2) { + ret = -EINVAL; + goto out; + } + ret = qcow2_merge_backward_progress(tgt, result, maxlen); + goto out; } } diff --git a/drivers/md/dm-qcow2.h b/drivers/md/dm-qcow2.h index ca43e13d35c3..5aa00c6a5ebd 100644 --- a/drivers/md/dm-qcow2.h +++ b/drivers/md/dm-qcow2.h @@ -158,11 +158,26 @@ enum qcow2_backward_merge_state { BACKWARD_MERGE_STOP, }; +enum qcow2_backward_merge_stage { + BACKWARD_MERGE_STAGE_NONE = 0, + BACKWARD_MERGE_STAGE_START, + BACKWARD_MERGE_STAGE_BREAK_L1COW, + BACKWARD_MERGE_STAGE_SET_DIRTY, + BACKWARD_MERGE_STAGE_RUNNING, + BACKWARD_MERGE_STAGE_WAITING_COMPLETION, + BACKWARD_MERGE_STAGE_COMPLETING, + BACKWARD_MERGE_STAGE_FAIL, + BACKWARD_MERGE_STAGE_MAX, +}; + struct qcow2_backward_merge { struct work_struct work; enum qcow2_backward_merge_state state; int error; struct eventfd_ctx *eventfd_ctx; + enum qcow2_backward_merge_stage stage; + long long progress; + long long max_progress; }; struct qcow2_target { _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel