OpenVZ / Virtuozzo kernel development (devel@openvz.org)
 help / color / mirror / Atom feed
From: Andrey Zhadchenko <andrey.zhadchenko@virtuozzo.com>
To: ptikhomirov@virtuozzo.com, alexander.ivanov@virtuozzo.com
Cc: devel@openvz.org
Subject: Re: [Devel] [PATCH hci-8.1 7/7] drivers/md/dm-qcow2: process fast path qios in per-cpu batches on a workqueue
Date: Mon, 2 Nov 2026 11:49:54 +0100	[thread overview]
Message-ID: <2389814d-7efa-4844-a43e-c1d492ed6868@virtuozzo.com> (raw)
In-Reply-To: <010701a1880a9bac-d29e8150-1b34-460e-b4bb-59e288525a57-000000@eu-central-1.amazonses.com>



On 10/29/26 15:22, no-reply@sashiko.virtuozzo.com wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Medium] dm-qcow2: per-CPU fast-path worker serializes blocking qios, losing per-qio parallelism
> --
> 
> commit 899ab5e8861b55a2a4717a14d3e51773e55d3c87
> Author: Andrey Zhadchenko <andrey.zhadchenko@virtuozzo.com>
> 
> drivers/md/dm-qcow2: process fast path qios in per-cpu batches on a workqueue
> 
> This patch replaces the per-qio work_struct on the fast path with a
> per-CPU llist and one work item per CPU. A per-CPU busy flag limits
> queue_work() calls, and the worker drains the whole llist each time it
> runs.
> 
> Link: https://virtuozzo.atlassian.net/browse/VSTOR-95494
> 
>> diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c
>> --- a/drivers/md/dm-qcow2-map.c
>> +++ b/drivers/md/dm-qcow2-map.c
> 
> [ ... ]
> 
>> +static void qcow2_fast_submit(struct qcow2_target *tgt, struct qio *qio)
>> +{
>> +	struct qcow2_fast_cpu *fc = get_cpu_ptr(tgt->fast);
>> +
>> +	llist_add(&qio->fast_link, &fc->qios);
>> +	/* Pairs with smp_mb() in qcow2_fast_work() */
>> +	smp_mb();
>> +	if (!atomic_read(&fc->busy) && atomic_cmpxchg(&fc->busy, 0, 1) == 0)
>> +		queue_work(tgt->wq, &fc->work);
>> +	put_cpu_ptr(tgt->fast);
>> +}
> 
> [Severity: Medium]
> Does the busy flag reduce fast path concurrency compared to the old
> per-qio work items?
> 
> Before this patch each qio had its own work_struct on an unbound
> WQ_HIGHPRI workqueue, so a qio that slept delayed only itself. Now at
> most one work item per submitting CPU is queued or running.
> 
> qcow2_fast_work() then runs every qio on that CPU's llist serially:
> 
> qcow2_fast_work()
>    llist_for_each_entry_safe(qio, next, node, fast_link)
>        do_qio_work(qio);
> 
> do_qio_work() can sleep. For QIO_STATE_START it goes through
> prepare_one_embedded_qio() and then qio_try_fast():
> 
> do_qio_work()
>    prepare_one_embedded_qio()
>      create_bvec_from_rq()
>        kvmalloc_array(nr_bvec, sizeof(struct bio_vec), GFP_NOIO)
>    qio_try_fast()
>      process_one_qio(qio->qcow2, qio, true)
>        perform_rw_mapped()
>          map_and_submit_rw()
>            qcow2_call_rw_iter()
>              file->f_op->write_iter() / read_iter()
> 
> qcow2_call_rw_iter() uses a sync kiocb (init_sync_kiocb). On a
> buffered backing file, page cache, filesystem locking and writeback
> throttling can block there. process_one_qio() with the fast flag set
> only defers qios that need metadata changes, so plain mapped reads and
> writes are issued inline.

First of all, the backing file is not buffered. We explicitly require 
O_DIRECT.
Secondly we only submit IO here and this should be quite fast.
Also it is an still upgrade over single kwork.
In general this problem indeed exists but not in this configuration. If 
we add more stages like compressed read which can really sleep (for 
buffer allocation) this may become a problem.

> 
> If one qio sleeps in that path, every later qio on the same CPU's llist
> waits behind it, and no other kworker is queued for that CPU. Could a
> workload with a single submitting CPU and blocking backing-file I/O
> become effectively single-threaded?
> 
> The commit message gives savings in context switches and pool->lock
> time for 4 submitters on 12 CPUs. It gives no throughput or latency
> numbers for the blocking case. Could such numbers be provided?
> 
>> +static void qcow2_fast_work(struct work_struct *work)
>> +{
> 
> [ ... ]
> 
>> +	for (;;) {
>> +		node = llist_del_all(&fc->qios);
>> +		if (!node) {
>> +			atomic_set(&fc->busy, 0);
>> +			/* just to be sure we look at the list after busy is posted */
>> +			smp_mb();
>> +			if (llist_empty(&fc->qios))
>> +				break;
>> +			if (atomic_cmpxchg(&fc->busy, 0, 1) != 0)
>> +				break;
>> +			continue;
>> +		}
>> +		node = llist_reverse_order(node);
>> +		llist_for_each_entry_safe(qio, next, node, fast_link)
>> +			do_qio_work(qio);
>> +	}
> 
> [Severity: Medium]
> This is a minor point. The loop has no batch limit and no cond_resched()
> between iterations. Under sustained submission on one CPU, can this keep
> one WQ_HIGHPRI kworker busy and delay qcow2->worker and
> qcow2->fsync_worker, which are queued on the same workqueue?
> 

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

  reply	other threads:[~2026-11-02 10:51 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-29 14:03 [Devel] [PATCH 0/7] drivers/md/dm-qcow2: per-qio fast path Andrey Zhadchenko
2026-10-29 14:03 ` [Devel] [PATCH hci-8.1 1/7] drivers/md/dm-qcow2: repeat md page lookup if it was inserted in parallel Andrey Zhadchenko
2026-10-29 14:13   ` no-reply
2026-11-04 21:35   ` Konstantin Khorenko
2026-10-29 14:03 ` [Devel] [PATCH hci-8.1 2/7] drivers/md/dm-qcow2: check MD_DIRTY and md->wbd under lock in perform_rw_mapped() Andrey Zhadchenko
2026-10-29 14:13   ` no-reply
2026-11-04 21:35   ` Konstantin Khorenko
2026-10-29 14:03 ` [Devel] [PATCH hci-8.1 3/7] drivers/md/dm-qcow2: prepare process_one_qio() for fastpath Andrey Zhadchenko
2026-10-29 14:16   ` no-reply
2026-11-02 17:28   ` Alexander Ivanov
2026-11-04 21:35   ` Konstantin Khorenko
2026-10-29 14:03 ` [Devel] [PATCH hci-8.1 4/7] drivers/md/dm-qcow2: add per-qio work infrastructure Andrey Zhadchenko
2026-10-29 14:18   ` no-reply
2026-11-04 21:35   ` Konstantin Khorenko
2026-10-29 14:03 ` [Devel] [PATCH hci-8.1 5/7] drivers/md/dm-qcow2: implement per-qio fast processing Andrey Zhadchenko
2026-10-29 14:22   ` no-reply
2026-11-04 21:35   ` Konstantin Khorenko
2026-10-29 14:03 ` [Devel] [PATCH hci-8.1 6/7] drivers/md/dm-qcow2: declare DM_TARGET_NOWAIT Andrey Zhadchenko
2026-10-29 14:19   ` no-reply
2026-11-03  8:33   ` Alexander Ivanov
2026-11-04 21:35   ` Konstantin Khorenko
2026-10-29 14:03 ` [Devel] [PATCH hci-8.1 7/7] drivers/md/dm-qcow2: process fast path qios in per-cpu batches on a workqueue Andrey Zhadchenko
2026-10-29 14:22   ` no-reply
2026-11-02 10:49     ` Andrey Zhadchenko [this message]
2026-11-04 21:35   ` Konstantin Khorenko
2026-11-03  9:36 ` [Devel] [PATCH 0/7] drivers/md/dm-qcow2: per-qio fast path Alexander Ivanov
2026-11-04 21:35 ` Konstantin Khorenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2389814d-7efa-4844-a43e-c1d492ed6868@virtuozzo.com \
    --to=andrey.zhadchenko@virtuozzo.com \
    --cc=alexander.ivanov@virtuozzo.com \
    --cc=devel@openvz.org \
    --cc=ptikhomirov@virtuozzo.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox