clear_writeback_status() unconditionally re-dispatched md->wait_list (qios
postponed by delay_if_dirty()/delay_if_writeback()/delay_if_locked()/
delay_if_wpc_readers_locked() while an L1/L2/R1/R2 metadata page was
dirty/under writeback/locked) for retry, regardless of whether the writeback
that just completed succeeded or failed.
On a persistently failing backing file (a real I/O error, e.g. the backing
device going bad or being remapped to an error target), the retried qio
re-marks the same metadata page dirty, its writeback is submitted again,
fails again with the same error, and clear_writeback_status() requeues the
waiters again - an unbounded retry storm. The write() that originally
triggered the cluster allocation stays blocked in submit_bio_wait() forever:
that wait is uninterruptible (TASK_UNINTERRUPTIBLE), so the process cannot
be killed and sits in D state permanently. Live-reproduced: a write to a
qcow2 image backed by a dm-error target hung indefinitely, the kernel
logging "can't sync md: -5" every ~200ms, while `dmsetup remove`/`ploop
umount` and eventually an orderly `reboot` all hang on the stuck task.
A metadata write failure means the page's dirty state was not persisted, so
retrying it as if nothing happened is not safe or productive. Route
md->wait_list to end_list (fail the waiters with the write's error) on
failure, exactly like the analogous md->wbd->dependent_list handling a few
lines below already does. The success path (ret == 0) is unchanged.
Fixes: 59d2cb3de264 ("dm-qcow2: Introduce driver to create block devices over
QCOW2 files")
Feature: dm-qcow2: block device over QCOW2 files driver
https://virtuozzo.atlassian.net/browse/VSTOR-137234
Signed-off-by: Konstantin Khorenko <[email protected]>
---
drivers/md/dm-qcow2-map.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c
index db21efb45e17..ed01902be184 100644
--- a/drivers/md/dm-qcow2-map.c
+++ b/drivers/md/dm-qcow2-map.c
@@ -1344,7 +1344,22 @@ static void clear_writeback_status(struct qcow2 *qcow2,
struct md_page *md,
lockdep_assert_held(&qcow2->md_pages_lock);
md->status &= ~(MD_WRITEBACK|MD_WRITEBACK_ERROR);
- list_splice_init(&md->wait_list, wait_list);
+ /*
+ * Qios postponed on this page (delay_if_dirty()/delay_if_writeback()/
+ * delay_if_locked()/delay_if_wpc_readers_locked()) were waiting for
+ * this writeback to finish before retrying their own metadata
+ * update. If it failed, this page's on-disk state was not
+ * persisted, so retrying is not safe: on a persistently failing
+ * backing file (I/O error) it would immediately redirty and
+ * rewrite the very page, fail again, and requeue itself here again
+ * -- an unbounded retry storm that keeps the originating I/O
+ * (and its uninterruptible submit_bio_wait() caller) blocked
+ * forever. Fail them instead, same as the wbd->dependent_list below.
+ */
+ if (likely(ret == 0))
+ list_splice_init(&md->wait_list, wait_list);
+ else
+ list_splice_init(&md->wait_list, end_list);
if (ret && !md->wbd) {
/*
* L1L2 updates can do safe revert,
--
2.47.1
_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel