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

Reply via email to