From mboxrd@z Thu Jan 1 00:00:00 1970 From: Konstantin Khorenko Date: Tue, 25 Aug 2026 12:41:56 +0200 Subject: [Devel] [PATCH RHEL10 COMMIT] dm-qcow2: scan lower delta in one pass over empty L1 entry In-Reply-To: <20260819000745.28823-6-andrey.zhadchenko@virtuozzo.com> Message-ID: <202608251041.67PAfugu774831@f0.sw.ru> List-Id: The commit is pushed to "branch-rh10-6.12.0-211.39.1.16.x.vz10-ovz" and will appear at git at bitbucket.org:openvz/vzkernel.git after rh10-6.12.0-211.39.1.16.9.vz10 ------> commit 7af917e3954e3085a2c0aed3d3d6cf9db7797cf8 Author: Andrey Zhadchenko Date: Wed Aug 19 03:07:43 2026 +0300 dm-qcow2: scan lower delta in one pass over empty L1 entry When an L1 entry is absent and there is a backing image, the seek code descends into the lower delta one cluster at a time. Change advance_and_spawn_lower_seek_qio() to take limit instead of a size. Pass bigger range if L1 entry is empty. On a 16G image (128K clusters, extended L2) with no L1 entries over a backing image with data at 15G, warm-cache SEEK_DATA improves from 40.2 ms to 0.01 ms. https://virtuozzo.atlassian.net/browse/VSTOR-139407 Feature: dm-qcow2: block device over QCOW2 files driver Signed-off-by: Andrey Zhadchenko Reviewed-by: Pavel Tikhomirov Reviewed-by: Vasileios Almpanis --- drivers/md/dm-qcow2-map.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c index 43188ceebc9af..879d2f1827006 100644 --- a/drivers/md/dm-qcow2-map.c +++ b/drivers/md/dm-qcow2-map.c @@ -4439,26 +4439,19 @@ static inline void seek_qio_next_clu(struct qio *qio, struct qcow2_map *map) seek_qio_set_sector(qio, bi_sector); } -static struct qio *advance_and_spawn_lower_seek_qio(struct qio *old_qio, u32 size) +static struct qio *advance_and_spawn_lower_seek_qio(struct qio *old_qio, loff_t end) { + struct qcow2 *lower = old_qio->qcow2->lower; struct qio *new_qio; - loff_t start; - start = to_bytes(old_qio->bi_iter.bi_sector); + if (end > lower->hdr.size) + end = lower->hdr.size; - if (start + size > old_qio->qcow2->lower->hdr.size) - size = old_qio->qcow2->lower->hdr.size - start; - - new_qio = alloc_seek_qio(old_qio->qcow2->lower, old_qio, start + size); + new_qio = alloc_seek_qio(lower, old_qio, end); if (!new_qio) return NULL; - if (old_qio->bi_iter.bi_size == size) { - seek_qio_next_clu(old_qio, NULL); - } else { - old_qio->bi_iter.bi_sector += to_sector(size); - old_qio->bi_iter.bi_size -= size; - } + seek_qio_set_sector(old_qio, to_sector(end)); return new_qio; } @@ -4506,8 +4499,16 @@ static int qcow2_llseek_hole_qio(struct qio *qio, int whence, loff_t *result) */ if (to_bytes(qio->bi_iter.bi_sector) < qio->qcow2->lower->hdr.size) { struct qio *new_qio; + loff_t end; + + if (!(map.level & L2_LEVEL)) + end = min_t(loff_t, + to_bytes(get_next_l2(qio)), + SEEK_QIO_DATA(qio)->lim); + else + end = to_bytes(qio->bi_iter.bi_sector) + size; - new_qio = advance_and_spawn_lower_seek_qio(qio, size); + new_qio = advance_and_spawn_lower_seek_qio(qio, end); if (!new_qio) { ret = -ENOMEM; break;