Blob Blame Raw
From b72ee3ebf0f00962872c69ad3576e1c8c0a208d9 Mon Sep 17 00:00:00 2001
From: Fam Zheng <>
Date: Thu, 21 Sep 2017 14:23:45 -0300
Subject: [PATCH] block: Limit multiwrite merge (downstream only)

RH-Author: Fam Zheng <>
Message-id: <>
Patchwork-id: 76502
O-Subject: [RHEL-7.4 qemu-kvm PATCH] block: Limit multiwrite merge (downstream only)
Bugzilla: 1492559
RH-Acked-by: Max Reitz <>
RH-Acked-by: John Snow <>
RH-Acked-by: Stefan Hajnoczi <>

Upstream: Fixed since 2.3, see below.

We don't limit the size of the final request of multiwrite_merge. The BZ
has a relatively stable reproducer: Attach an iscsi:// lun as
virtio-blk, then mkfs.ext4. When the guest kernel flushes the page
cache, iscsi driver gets two huge requests that are rejected by the LIO
iscsi target, then reports EIO.

Upstream QEMU and qemu-kvm-rhev don't have this problem because of two

1) multiread feature in virtio-blk added in 2.3 (95f7142abc8).

2) request fragmentation in block layer I/O in 2.7 (04ed95f484 and

For 1), we cannot do a faithful backport because it is a new feature,
and is invasive. The change of this patch can be seen as doing a small
part from it, though the implementation is totally different.

For 2), we would have a serious context conflict because upstream has a
lot of intermediate changes. The patch could possibly be rewritten in
downstream but is on the one hand much more risky than this patch as it
touches the very center of the block I/O code, and on the other hand
loses the meaning because the diff will completely deviate from

Signed-off-by: Fam Zheng <>
Signed-off-by: Wainer dos Santos Moschetta <>
 block.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/block.c b/block.c
index bdcd741389..b0373d0c16 100644
--- a/block.c
+++ b/block.c
@@ -4303,6 +4303,11 @@ static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,
             merge = 0;
+        if (reqs[outidx].qiov->size + reqs[i].qiov->size >=
+            bs->bl.max_transfer_length * BDRV_SECTOR_SIZE) {
+            merge = 0;
+        }
         if (merge) {
             size_t size;
             QEMUIOVector *qiov = g_malloc0(sizeof(*qiov));