aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChunqiang Tang <ctang@us.ibm.com>2011-02-03 10:12:49 -0500
committerKevin Wolf <kwolf@redhat.com>2011-02-11 14:33:56 +0100
commit607a375709625a439c5bbdbfb62f8052276d33ad (patch)
tree7f4016651245bd030df574fa08e14c760c9a2b9b
parentac12a5af0bb48e2cee46232480dc5f6d8d8241b9 (diff)
downloadqemu-607a375709625a439c5bbdbfb62f8052276d33ad.zip
qemu-607a375709625a439c5bbdbfb62f8052276d33ad.tar.gz
qemu-607a375709625a439c5bbdbfb62f8052276d33ad.tar.bz2
QCOW2: bug fix - read base image beyond its size
This patch fixes the following bug in QCOW2. For a QCOW2 image that is larger than its base image, when handling a read request straddling over the end of the base image, the QCOW2 driver attempts to read beyond the end of the base image and the request would fail. This bug was found by Fast Virtual Disk (FVD)'s fully automated testing tool. The following test triggered the bug. dd if=/dev/zero of=/var/ramdisk/truth.raw count=0 bs=1 seek=1098561536 dd if=/dev/zero of=/var/ramdisk/zero-500M.raw count=0 bs=1 seek=593099264 ./qemu-img create -f qcow2 -ocluster_size=65536,backing_fmt=blksim -b /var/ramdisk/zero-500M.raw /var/ramdisk/test.qcow2 1098561536 ./qemu-io --auto --seed=30477694 --truth=/var/ramdisk/truth.raw --format=qcow2 --test=blksim:/var/ramdisk/test.qcow2 --verify_write=true --compare_before=false --compare_after=true --round=100000 --parallel=100 --io_size=10485760 --fail_prob=0 --cancel_prob=0 --instant_qemubh=true Signed-off-by: Chunqiang Tang <ctang@us.ibm.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> (cherry picked from commit e0d9c6f93729c9bfc98fcafcd73098bb8e131aeb)
-rw-r--r--block/qcow2.c5
-rw-r--r--cutils.c31
-rw-r--r--qemu-common.h2
3 files changed, 35 insertions, 3 deletions
diff --git a/block/qcow2.c b/block/qcow2.c
index a1773e4..28338bf 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -355,7 +355,7 @@ int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
else
n1 = bs->total_sectors - sector_num;
- qemu_iovec_memset(qiov, 0, 512 * (nb_sectors - n1));
+ qemu_iovec_memset_skip(qiov, 0, 512 * (nb_sectors - n1), 512 * n1);
return n1;
}
@@ -478,8 +478,7 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
if (n1 > 0) {
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
- &acb->hd_qiov, acb->cur_nr_sectors,
- qcow2_aio_read_cb, acb);
+ &acb->hd_qiov, n1, qcow2_aio_read_cb, acb);
if (acb->hd_aiocb == NULL)
goto done;
} else {
diff --git a/cutils.c b/cutils.c
index 8d562b2..f9a7e36 100644
--- a/cutils.c
+++ b/cutils.c
@@ -267,6 +267,37 @@ void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count)
}
}
+void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count,
+ size_t skip)
+{
+ int i;
+ size_t done;
+ void *iov_base;
+ uint64_t iov_len;
+
+ done = 0;
+ for (i = 0; (i < qiov->niov) && (done != count); i++) {
+ if (skip >= qiov->iov[i].iov_len) {
+ /* Skip the whole iov */
+ skip -= qiov->iov[i].iov_len;
+ continue;
+ } else {
+ /* Skip only part (or nothing) of the iov */
+ iov_base = (uint8_t*) qiov->iov[i].iov_base + skip;
+ iov_len = qiov->iov[i].iov_len - skip;
+ skip = 0;
+ }
+
+ if (done + iov_len > count) {
+ memset(iov_base, c, count - done);
+ break;
+ } else {
+ memset(iov_base, c, iov_len);
+ }
+ done += iov_len;
+ }
+}
+
#ifndef _WIN32
/* Sets a specific flag */
int fcntl_setfl(int fd, int flag)
diff --git a/qemu-common.h b/qemu-common.h
index c7ff280..cb4b7e0 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -322,6 +322,8 @@ void qemu_iovec_reset(QEMUIOVector *qiov);
void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf);
void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count);
void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count);
+void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count,
+ size_t skip);
struct Monitor;
typedef struct Monitor Monitor;