summaryrefslogtreecommitdiffstats
path: root/block.c
diff options
context:
space:
mode:
authorStefan Hajnoczi2014-07-30 10:53:30 +0200
committerStefan Hajnoczi2014-08-29 15:09:43 +0200
commit391827eb106d2d02062b2582d1545a7c221631c6 (patch)
tree74840acba94091d0ab90caa619f2dd9b0754ab00 /block.c
parentnbd: Follow the BDS' AIO context (diff)
downloadqemu-391827eb106d2d02062b2582d1545a7c221631c6.tar.gz
qemu-391827eb106d2d02062b2582d1545a7c221631c6.tar.xz
qemu-391827eb106d2d02062b2582d1545a7c221631c6.zip
block: fix overlapping multiwrite requests
When request A is a strict superset of request B: AAAAAAAA BBBB multiwrite_merge() merges them as follows: AABBBB The tail of request A should have been included: AABBBBAA This patch fixes data loss but this code path is probably rare. Since guests cannot assume ordering between in-flight requests, few applications submit overlapping write requests. Reported-by: Slava Pestov <sviatoslav.pestov@gmail.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Reviewed-by: Benoit Canet <benoit@irqsave.net>
Diffstat (limited to 'block.c')
-rw-r--r--block.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/block.c b/block.c
index 9c5566b55b..cb670fd54d 100644
--- a/block.c
+++ b/block.c
@@ -4553,6 +4553,12 @@ static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,
// Add the second request
qemu_iovec_concat(qiov, reqs[i].qiov, 0, reqs[i].qiov->size);
+ // Add tail of first request, if necessary
+ if (qiov->size < reqs[outidx].qiov->size) {
+ qemu_iovec_concat(qiov, reqs[outidx].qiov, qiov->size,
+ reqs[outidx].qiov->size - qiov->size);
+ }
+
reqs[outidx].nb_sectors = qiov->size >> 9;
reqs[outidx].qiov = qiov;