Each qio is handled by its own work and process_one_qio() can now work with qios not requiring metadata. Try to process qios right after splitting. Insert all leftovers into respective lists for do_qcow2_work(), keeping the order of the splits.
Now process_one_qio() runs in parallel with do_qcow2_work(), so main kwork may change an L2 entry between the fast path parse and the data submit. A fast path write or partial discard is counted in md writers under the lock that checks its L2 entry, so a discard unmapping the cluster waits for it before the cluster is freed. Known limitation: reads are not counted, and nothing pins their cluster between the parse and the submit. Main kwork may discard the cluster, free it and reuse it for another allocation in that window, and a fast path read may then return the data of another guest offset. A follow-up series fixes this in VSTOR-154659. https://virtuozzo.atlassian.net/browse/VSTOR-95494 Feature: dm-qcow2: block device over QCOW2 files driver Signed-off-by: Andrey Zhadchenko <[email protected]> --- v2: list_add_tail() keeps the order of deferred splits; commit message mentions the race with md writeback; fixed "it's" typo v3: commit message describes the window between the fast path parse and the data submit and the known limitation for reads, which a follow-up series fixes; reworded the line starting with "From" drivers/md/dm-qcow2-map.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c index 496fbcc613488..fb2a1c7c42111 100644 --- a/drivers/md/dm-qcow2-map.c +++ b/drivers/md/dm-qcow2-map.c @@ -4817,9 +4817,18 @@ static void handle_cleanup_mask(struct qio *qio) } } +static void qio_try_fast(struct qio *qio, struct list_head *deferred_qios) +{ + list_del(&qio->link); + + if (process_one_qio(qio->qcow2, qio, true)) + list_add_tail(&qio->link, deferred_qios); +} + static void do_qio_work(struct work_struct *ws) { struct qio *qio = container_of(ws, struct qio, worker); + struct qio *i, *next; struct qcow2 *qcow2 = qio->qcow2; struct qcow2_target *tgt = qcow2->tgt; unsigned int pflags = current->flags; @@ -4829,8 +4838,12 @@ static void do_qio_work(struct work_struct *ws) switch (qio->state) { case QIO_STATE_START: { LIST_HEAD(deferred_qios); + LIST_HEAD(split_qios); + + prepare_one_embedded_qio(qio, &split_qios); + list_for_each_entry_safe(i, next, &split_qios, link) + qio_try_fast(i, &deferred_qios); - prepare_one_embedded_qio(qio, &deferred_qios); if (list_empty(&deferred_qios)) break; -- 2.43.5 _______________________________________________ Devel mailing list [email protected] https://lists.openvz.org/mailman/listinfo/devel
