[Devel] [PATCH hci-8.1 v10 09/10] dm-qcow2: retry R1/R2 writeback that failed with ENOSPC

Alexander Ivanov alexander.ivanov at virtuozzo.com
Mon Nov 9 14:58:55 MSK 2026


A failed R1/R2 writeback sets MD_WRITEBACK_ERROR and drops MD_DIRTY.
Nothing writes the page again unless its refcounts change. On suspend
the md writeback flush finds the error and sets md_writeback_error, so
resume is refused until the image is checked and the target reloaded,
even if the failure was a transient ENOSPC of the underlying fs and
the space has been freed since.

Redirty the page on -ENOSPC, so the slow writeback timer retries it,
as data writes delayed on ENOSPC are retried. The suspend flush fires
the timer, which gives the page one more try. A page that still fails
then is not redirtied, as wants_suspend is set, so nothing is left
pending on a suspended device and md_writeback_error is set as before.

complete_metadata_writeback() turned every failed write into -EIO.
Pass the errno of the write through and keep -EIO for a short write.
A data request depending on a failed L1/L2 write then ends with
BLK_STS_NOSPC and is delayed and resubmitted like any other write
failing with ENOSPC, as already happens when fsync fails with it.

https://virtuozzo.atlassian.net/browse/VSTOR-148171
Feature: dm-qcow2: block device over QCOW2 files driver

Signed-off-by: Alexander Ivanov <alexander.ivanov at virtuozzo.com>
---
 drivers/md/dm-qcow2-map.c    | 6 ++++--
 drivers/md/dm-qcow2-target.c | 1 -
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c
index 4197f7704e18..27ae22495f37 100644
--- a/drivers/md/dm-qcow2-map.c
+++ b/drivers/md/dm-qcow2-map.c
@@ -1357,6 +1357,8 @@ static void clear_writeback_status(struct qcow2 *qcow2, struct md_page *md,
 		 * so here we care about R1R2 only.
 		 */
 		md->status |= MD_WRITEBACK_ERROR;
+		if (ret == -ENOSPC && !READ_ONCE(qcow2->tgt->wants_suspend))
+			qcow2_md_make_dirty(qcow2, md, true);
 	}
 	if (md->wbd) {
 		if (likely(ret == 0))
@@ -3864,9 +3866,9 @@ static int complete_metadata_writeback(struct qcow2 *qcow2)
 		md = qio->ext->md;
 		qvec = qio->data;
 		ret = qio->ret;
-		if (unlikely(ret != PAGE_SIZE))
+		if (unlikely(ret >= 0 && ret != PAGE_SIZE))
 			ret = -EIO;
-		else
+		else if (ret == PAGE_SIZE)
 			ret = fsync_ret;
 
 		do_md_page_write_complete(ret, qcow2, md);
diff --git a/drivers/md/dm-qcow2-target.c b/drivers/md/dm-qcow2-target.c
index 6824d95193ae..1b7a75239291 100644
--- a/drivers/md/dm-qcow2-target.c
+++ b/drivers/md/dm-qcow2-target.c
@@ -190,7 +190,6 @@ void qcow2_flush_deferred_activity(struct qcow2_target *tgt, struct qcow2 *qcow2
 	for (node = rb_first(&qcow2->md_pages);
 	     node; node = rb_next(node)) {
 		md = rb_entry(node, struct md_page, node);
-		/* FIXME: call md_make_dirty() and try once again? */
 		if (md->status & MD_WRITEBACK_ERROR) {
 			QC_ERR(tgt->ti, "Failed to write dirty pages");
 			tgt->md_writeback_error = true;
-- 
2.53.0



More information about the Devel mailing list