aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2014-07-30 09:53:30 +0100
committerStefan Hajnoczi <stefanha@redhat.com>2014-08-29 14:09:43 +0100
commit391827eb106d2d02062b2582d1545a7c221631c6 (patch)
tree74840acba94091d0ab90caa619f2dd9b0754ab00
parentf21492817bc426a3bc0b98fa852df95be9dea1e8 (diff)
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>
-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;