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
