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 <[email protected]>
---
 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

_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to