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

Pavel Tikhomirov ptikhomirov at virtuozzo.com
Fri Feb 28 08:29:12 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 7f9c582778d5f..3c6b965bf1e84 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;
@@ -205,6 +263,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;
@@ -222,6 +281,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");
@@ -230,6 +290,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);
@@ -244,14 +305,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);
@@ -267,6 +331,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() */
@@ -280,6 +345,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;
 }
@@ -306,6 +372,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);
 
@@ -515,6 +582,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 c4956e3fd0eb7..ed7cf79348052 100644
--- a/drivers/md/dm-qcow2.h
+++ b/drivers/md/dm-qcow2.h
@@ -158,11 +158,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