[Devel] [PATCH VZ9 5/5] dm-qcow2: add merge_backward progress command

Pavel Tikhomirov ptikhomirov at virtuozzo.com
Fri Feb 28 07:21:08 MSK 2025


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.

https://virtuozzo.atlassian.net/browse/VSTOR-100466
Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
 drivers/md/dm-qcow2-cmd.c | 74 +++++++++++++++++++++++++++++++++++++++
 drivers/md/dm-qcow2.h     | 14 ++++++++
 2 files changed, 88 insertions(+)

diff --git a/drivers/md/dm-qcow2-cmd.c b/drivers/md/dm-qcow2-cmd.c
index 2959a8ffe8d49..32e28a2b08f11 100644
--- a/drivers/md/dm-qcow2-cmd.c
+++ b/drivers/md/dm-qcow2-cmd.c
@@ -54,6 +54,8 @@ 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, 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,
@@ -67,6 +69,8 @@ static int qcow2_service_iter(struct qcow2_target *tgt, struct qcow2 *qcow2,
 	WRITE_ONCE(service_status, BLK_STS_OK);
 
 	for (pos = 0; pos < end; pos += step) {
+		backward_merge_update_progress(tgt, pos, end);
+
 		if (qcow2_backward_merge_should_stop(tgt)) {
 			ret = -EINTR;
 			break;
@@ -165,6 +169,60 @@ 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_progress(struct qcow2_target *tgt,
+					   long long progress, long long max_progress)
+{
+	mutex_lock(&tgt->ctl_mutex);
+	tgt->backward_merge.progress = progress;
+	tgt->backward_merge.max_progress = max_progress;
+	mutex_unlock(&tgt->ctl_mutex);
+}
+
+char *backward_merge_stage_names[] = {
+	"none",
+	"break_l1cow",
+	"set_dirty",
+	"running",
+	"waiting_completion",
+	"completing",
+	"fail",
+};
+
+static int qcow2_merge_backward_progress(struct qcow2_target *tgt,
+					 char *result, unsigned int maxlen)
+{
+	unsigned int sz = 0;
+	int ret;
+
+	BUILD_BUG_ON(ARRAY_SIZE(backward_merge_stage_names) != BACKWARD_MERGE_STAGE_MAX);
+
+	mutex_lock(&tgt->ctl_mutex);
+	ret = DMEMIT("stage=%s\nprogress=%lld\nmax_progress=%lld\nerror=%d\n",
+			backward_merge_stage_names[tgt->backward_merge.stage],
+			tgt->backward_merge.progress,
+			tgt->backward_merge.max_progress,
+			tgt->backward_merge.error);
+	mutex_unlock(&tgt->ctl_mutex);
+
+	return ret ? 1 : 0;
+}
+
 static int qcow2_merge_backward_start(struct qcow2_target *tgt)
 {
 	struct qcow2 *qcow2 = tgt->top, *lower = qcow2->lower;
@@ -203,6 +261,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;
@@ -220,6 +279,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");
@@ -228,6 +288,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);
@@ -242,14 +303,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);
 	}
@@ -265,6 +329,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() */
@@ -278,6 +343,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;
 }
@@ -302,6 +368,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);
 
@@ -511,6 +578,13 @@ int qcow2_message(struct dm_target *ti, unsigned int argc, char **argv,
 			}
 			ret = qcow2_merge_backward_set_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 f95914190c8bb..9a34e9dcb51e1 100644
--- a/drivers/md/dm-qcow2.h
+++ b/drivers/md/dm-qcow2.h
@@ -116,11 +116,25 @@ enum qcow2_backward_merge_state {
 	BACKWARD_MERGE_STOP,
 };
 
+enum qcow2_backward_merge_stage {
+	BACKWARD_MERGE_STAGE_NONE = 0,
+	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 {
-- 
2.48.1



More information about the Devel mailing list