From ada70b452236757a07df73e8ab44cb343c3ab2fe Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 28 Jul 2010 11:26:29 +0200 Subject: block: Fix bdrv_has_zero_init Assuming that any image on a block device is not properly zero-initialized is actually wrong: Only raw images have this problem. Any other image format shouldn't care about it, they initialize everything properly themselves. Signed-off-by: Kevin Wolf (cherry picked from commit 336c1c12551ff0a6e1a2af226d6cbdbadd2e02b5) --- block.c | 6 ++---- block/raw-posix.c | 13 +++++++++---- block/raw-win32.c | 6 ++++++ block/raw.c | 6 ++++++ block_int.h | 7 +++++-- 5 files changed, 28 insertions(+), 10 deletions(-) diff --git a/block.c b/block.c index 452ae94ee..40e78f9ae 100644 --- a/block.c +++ b/block.c @@ -1476,10 +1476,8 @@ int bdrv_has_zero_init(BlockDriverState *bs) { assert(bs->drv); - if (bs->drv->no_zero_init) { - return 0; - } else if (bs->file) { - return bdrv_has_zero_init(bs->file); + if (bs->drv->bdrv_has_zero_init) { + return bs->drv->bdrv_has_zero_init(bs); } return 1; diff --git a/block/raw-posix.c b/block/raw-posix.c index a11170ed1..72fb8cebd 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -993,6 +993,11 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options) return ret; } +static int hdev_has_zero_init(BlockDriverState *bs) +{ + return 0; +} + static BlockDriver bdrv_host_device = { .format_name = "host_device", .protocol_name = "host_device", @@ -1002,7 +1007,7 @@ static BlockDriver bdrv_host_device = { .bdrv_close = raw_close, .bdrv_create = hdev_create, .create_options = raw_create_options, - .no_zero_init = 1, + .bdrv_has_zero_init = hdev_has_zero_init, .bdrv_flush = raw_flush, .bdrv_aio_readv = raw_aio_readv, @@ -1117,7 +1122,7 @@ static BlockDriver bdrv_host_floppy = { .bdrv_close = raw_close, .bdrv_create = hdev_create, .create_options = raw_create_options, - .no_zero_init = 1, + .bdrv_has_zero_init = hdev_has_zero_init, .bdrv_flush = raw_flush, .bdrv_aio_readv = raw_aio_readv, @@ -1217,7 +1222,7 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_close = raw_close, .bdrv_create = hdev_create, .create_options = raw_create_options, - .no_zero_init = 1, + .bdrv_has_zero_init = hdev_has_zero_init, .bdrv_flush = raw_flush, .bdrv_aio_readv = raw_aio_readv, @@ -1340,7 +1345,7 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_close = raw_close, .bdrv_create = hdev_create, .create_options = raw_create_options, - .no_zero_init = 1, + .bdrv_has_zero_init = hdev_has_zero_init, .bdrv_flush = raw_flush, .bdrv_aio_readv = raw_aio_readv, diff --git a/block/raw-win32.c b/block/raw-win32.c index 745bbde67..503ed3959 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -394,6 +394,11 @@ static int raw_set_locked(BlockDriverState *bs, int locked) } #endif +static int hdev_has_zero_init(BlockDriverState *bs) +{ + return 0; +} + static BlockDriver bdrv_host_device = { .format_name = "host_device", .protocol_name = "host_device", @@ -402,6 +407,7 @@ static BlockDriver bdrv_host_device = { .bdrv_file_open = hdev_open, .bdrv_close = raw_close, .bdrv_flush = raw_flush, + .bdrv_has_zero_init = hdev_has_zero_init, .bdrv_read = raw_read, .bdrv_write = raw_write, diff --git a/block/raw.c b/block/raw.c index 1414e777b..61e674856 100644 --- a/block/raw.c +++ b/block/raw.c @@ -237,6 +237,11 @@ static QEMUOptionParameter raw_create_options[] = { { NULL } }; +static int raw_has_zero_init(BlockDriverState *bs) +{ + return bdrv_has_zero_init(bs->file); +} + static BlockDriver bdrv_raw = { .format_name = "raw", @@ -264,6 +269,7 @@ static BlockDriver bdrv_raw = { .bdrv_create = raw_create, .create_options = raw_create_options, + .bdrv_has_zero_init = raw_has_zero_init, }; static void bdrv_raw_init(void) diff --git a/block_int.h b/block_int.h index f075a8cba..7d5e7515d 100644 --- a/block_int.h +++ b/block_int.h @@ -127,8 +127,11 @@ struct BlockDriver { void (*bdrv_debug_event)(BlockDriverState *bs, BlkDebugEvent event); - /* Set if newly created images are not guaranteed to contain only zeros */ - int no_zero_init; + /* + * Returns 1 if newly created images are guaranteed to contain only + * zeros, 0 otherwise. + */ + int (*bdrv_has_zero_init)(BlockDriverState *bs); QLIST_ENTRY(BlockDriver) list; }; -- cgit v1.2.3 From 08e90b3cadfa7ce83efe45e7f211dd868fd8bf27 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 27 Jul 2010 14:02:01 +0200 Subject: block: Change bdrv_eject() not to drop the image bdrv_eject() gets called when a device model opens or closes the tray. If the block driver implements method bdrv_eject(), that method gets called. Drivers host_cdrom implements it, and it opens and closes the physical tray, and nothing else. When a device model opens, then closes the tray, media changes only if the user actively changes the physical media while the tray is open. This is matches how physical hardware behaves. If the block driver doesn't implement method bdrv_eject(), we do something quite different: opening the tray severs the connection to the image by calling bdrv_close(), and closing the tray does nothing. When the device model opens, then closes the tray, media is gone, unless the user actively inserts another one while the tray is open, with a suitable change command in the monitor. This isn't how physical hardware behaves. Rather inconvenient when programs "helpfully" eject media to give you a chance to change it. The way bdrv_eject() behaves here turns that chance into a must, which is not what these programs or their users expect. Change the default action not to call bdrv_close(). Instead, note the tray status in new BlockDriverState member tray_open. Use it in bdrv_is_inserted(). Arguably, the device models should keep track of tray status themselves. But this is less invasive. Signed-off-by: Markus Armbruster Signed-off-by: Kevin Wolf (cherry picked from commit 4be9762adb0947a353e6efef2fed354f69218bfb) --- block.c | 7 ++++--- block_int.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index 40e78f9ae..8014a5c26 100644 --- a/block.c +++ b/block.c @@ -2516,7 +2516,7 @@ int bdrv_is_inserted(BlockDriverState *bs) if (!drv) return 0; if (!drv->bdrv_is_inserted) - return 1; + return !bs->tray_open; ret = drv->bdrv_is_inserted(bs); return ret; } @@ -2558,10 +2558,11 @@ int bdrv_eject(BlockDriverState *bs, int eject_flag) ret = drv->bdrv_eject(bs, eject_flag); } if (ret == -ENOTSUP) { - if (eject_flag) - bdrv_close(bs); ret = 0; } + if (ret >= 0) { + bs->tray_open = eject_flag; + } return ret; } diff --git a/block_int.h b/block_int.h index 7d5e7515d..b86345177 100644 --- a/block_int.h +++ b/block_int.h @@ -144,6 +144,7 @@ struct BlockDriverState { int open_flags; /* flags used to open the file, re-used for re-open */ int removable; /* if true, the media can be removed */ int locked; /* if true, the media cannot temporarily be ejected */ + int tray_open; /* if true, the virtual tray is open */ int encrypted; /* if true, the media is encrypted */ int valid_key; /* if true, a valid encryption key has been set */ int sg; /* if true, the device is a /dev/sg* */ -- cgit v1.2.3 From 96638e706cd431528690cf611adcb04e1bc3255d Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Tue, 27 Jul 2010 21:04:36 +0200 Subject: ide: Avoid canceling IDE DMA The reason for not actually canceling the I/O is because with virtualization and lots of VM running, a guest fs may mistake a overload of the host, as an IDE timeout. So rather than canceling the I/O, it's safer to wait I/O completion and simulate that the I/O has completed just before the io cancellation was requested by the guest. This way if ntfs or an app writes data without checking for -EIO retval, and it thinks the write has succeeded, it's less likely to run into troubles. Similar issues for reads. Furthermore because the DMA operation is splitted into many synchronous aio_read/write if there's more than one entry in the SG table, without this patch the DMA would be cancelled in the middle, something we've no idea if it happens on real hardware too or not. Overall this seems a great risk for zero gain. This approach is sure safer than previous code given we can't pretend all guest fs code out there to check for errors and reply the DMA if it was completed partially, given a timeout would never materialize on a real harddisk unless there are defective blocks (and defective blocks are practically only an issue for reads never for writes in any recent hardware as writing to blocks is the way to fix them) or the harddisk breaks as a whole. Signed-off-by: Izik Eidus Signed-off-by: Andrea Arcangeli Signed-off-by: Kevin Wolf (cherry picked from commit 953844d102f5b682f0835f021f2ed2ad9fb7734c) --- hw/ide/pci.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 4331d7723..ec90f266e 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -40,8 +40,27 @@ void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) printf("%s: 0x%08x\n", __func__, val); #endif if (!(val & BM_CMD_START)) { - /* XXX: do it better */ - ide_dma_cancel(bm); + /* + * We can't cancel Scatter Gather DMA in the middle of the + * operation or a partial (not full) DMA transfer would reach + * the storage so we wait for completion instead (we beahve + * like if the DMA was completed by the time the guest trying + * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not + * set). + * + * In the future we'll be able to safely cancel the I/O if the + * whole DMA operation will be submitted to disk with a single + * aio operation with preadv/pwritev. + */ + if (bm->aiocb) { + qemu_aio_flush(); +#ifdef DEBUG_IDE + if (bm->aiocb) + printf("ide_dma_cancel: aiocb still pending"); + if (bm->status & BM_STATUS_DMAING) + printf("ide_dma_cancel: BM_STATUS_DMAING still pending"); +#endif + } bm->cmd = val & 0x09; } else { if (!(bm->status & BM_STATUS_DMAING)) { -- cgit v1.2.3 From 6674dc4269030567dd6c463b7eedc8a5b9ad1888 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 3 Aug 2010 16:54:38 +0200 Subject: virtio: Factor virtqueue_map_sg out Separate the mapping of requests to host memory from the descriptor iteration. The next patch will make use of it in a different context. Signed-off-by: Kevin Wolf (cherry picked from commit 42fb2e0720511fa1da2f8e751be393f851b71d80) --- hw/virtio.c | 38 ++++++++++++++++++++++++-------------- hw/virtio.h | 3 +++ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/hw/virtio.c b/hw/virtio.c index 4475bb3e4..85312b3eb 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -360,11 +360,26 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes) return 0; } +void virtqueue_map_sg(struct iovec *sg, target_phys_addr_t *addr, + size_t num_sg, int is_write) +{ + unsigned int i; + target_phys_addr_t len; + + for (i = 0; i < num_sg; i++) { + len = sg[i].iov_len; + sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write); + if (sg[i].iov_base == NULL || len != sg[i].iov_len) { + fprintf(stderr, "virtio: trying to map MMIO memory\n"); + exit(1); + } + } +} + int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) { unsigned int i, head, max; target_phys_addr_t desc_pa = vq->vring.desc; - target_phys_addr_t len; if (!virtqueue_num_heads(vq, vq->last_avail_idx)) return 0; @@ -388,28 +403,19 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) i = 0; } + /* Collect all the descriptors */ do { struct iovec *sg; - int is_write = 0; if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) { elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i); sg = &elem->in_sg[elem->in_num++]; - is_write = 1; - } else + } else { + elem->out_addr[elem->out_num] = vring_desc_addr(desc_pa, i); sg = &elem->out_sg[elem->out_num++]; + } - /* Grab the first descriptor, and check it's OK. */ sg->iov_len = vring_desc_len(desc_pa, i); - len = sg->iov_len; - - sg->iov_base = cpu_physical_memory_map(vring_desc_addr(desc_pa, i), - &len, is_write); - - if (sg->iov_base == NULL || len != sg->iov_len) { - fprintf(stderr, "virtio: trying to map MMIO memory\n"); - exit(1); - } /* If we've got too many, that implies a descriptor loop. */ if ((elem->in_num + elem->out_num) > max) { @@ -418,6 +424,10 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) } } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max); + /* Now map what we have collected */ + virtqueue_map_sg(elem->in_sg, elem->in_addr, elem->in_num, 1); + virtqueue_map_sg(elem->out_sg, elem->out_addr, elem->out_num, 0); + elem->index = head; vq->inuse++; diff --git a/hw/virtio.h b/hw/virtio.h index 30e472aba..764970c3e 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -81,6 +81,7 @@ typedef struct VirtQueueElement unsigned int out_num; unsigned int in_num; target_phys_addr_t in_addr[VIRTQUEUE_MAX_SIZE]; + target_phys_addr_t out_addr[VIRTQUEUE_MAX_SIZE]; struct iovec in_sg[VIRTQUEUE_MAX_SIZE]; struct iovec out_sg[VIRTQUEUE_MAX_SIZE]; } VirtQueueElement; @@ -142,6 +143,8 @@ void virtqueue_flush(VirtQueue *vq, unsigned int count); void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, unsigned int len, unsigned int idx); +void virtqueue_map_sg(struct iovec *sg, target_phys_addr_t *addr, + size_t num_sg, int is_write); int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem); int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes); -- cgit v1.2.3 From 55ee7b38e820601e9e226061f1b68f9275553ec5 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 3 Aug 2010 16:57:02 +0200 Subject: virtio-blk: Fix migration of queued requests in_sg[].iovec and out_sg[].ioved are pointer to (source) host memory and therefore invalid after migration. When loading the device state we must create a new mapping on the destination host. Signed-off-by: Kevin Wolf (cherry picked from commit b6a4805b55b409134dc712677fdc4f6a8795e965) --- hw/virtio-blk.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 490cd4105..251779ca7 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -480,6 +480,11 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id) qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem)); req->next = s->rq; s->rq = req; + + virtqueue_map_sg(req->elem.in_sg, req->elem.in_addr, + req->elem.in_num, 1); + virtqueue_map_sg(req->elem.out_sg, req->elem.out_addr, + req->elem.out_num, 0); } return 0; -- cgit v1.2.3 From 2c1064ed2dd30494e4a5484f4b1a24e9dc24c2b8 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 30 Aug 2010 18:42:15 +0200 Subject: block: Fix image re-open in bdrv_commit Arguably we should re-open the backing file with the backing file format and not with the format of the snapshot image. Signed-off-by: Kevin Wolf (cherry picked from commit ee1811965fd15e0b41f8d508b951a8ab826ae3a7) Conflicts: block.c Signed-off-by: Kevin Wolf --- block.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/block.c b/block.c index 8014a5c26..e6087f3cb 100644 --- a/block.c +++ b/block.c @@ -743,6 +743,7 @@ int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res) int bdrv_commit(BlockDriverState *bs) { BlockDriver *drv = bs->drv; + BlockDriver *backing_drv; int64_t i, total_sectors; int n, j, ro, open_flags; int ret = 0, rw_ret = 0; @@ -760,7 +761,8 @@ int bdrv_commit(BlockDriverState *bs) if (bs->backing_hd->keep_read_only) { return -EACCES; } - + + backing_drv = bs->backing_hd->drv; ro = bs->backing_hd->read_only; strncpy(filename, bs->backing_hd->filename, sizeof(filename)); open_flags = bs->backing_hd->open_flags; @@ -770,12 +772,14 @@ int bdrv_commit(BlockDriverState *bs) bdrv_delete(bs->backing_hd); bs->backing_hd = NULL; bs_rw = bdrv_new(""); - rw_ret = bdrv_open(bs_rw, filename, open_flags | BDRV_O_RDWR, drv); + rw_ret = bdrv_open(bs_rw, filename, open_flags | BDRV_O_RDWR, + backing_drv); if (rw_ret < 0) { bdrv_delete(bs_rw); /* try to re-open read-only */ bs_ro = bdrv_new(""); - ret = bdrv_open(bs_ro, filename, open_flags & ~BDRV_O_RDWR, drv); + ret = bdrv_open(bs_ro, filename, open_flags & ~BDRV_O_RDWR, + backing_drv); if (ret < 0) { bdrv_delete(bs_ro); /* drive not functional anymore */ @@ -827,7 +831,8 @@ ro_cleanup: bdrv_delete(bs->backing_hd); bs->backing_hd = NULL; bs_ro = bdrv_new(""); - ret = bdrv_open(bs_ro, filename, open_flags & ~BDRV_O_RDWR, drv); + ret = bdrv_open(bs_ro, filename, open_flags & ~BDRV_O_RDWR, + backing_drv); if (ret < 0) { bdrv_delete(bs_ro); /* drive not functional anymore */ -- cgit v1.2.3 From 271a24e7bf5f9e98b8d6180ed9462719c0e755f9 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 17 Aug 2010 18:58:55 +0200 Subject: qemu-img rebase: Open new backing file read-only We never write to a backing file, so opening rw is useless. It just means that you can't rebase on top of a file for which you don't have write permissions. Signed-off-by: Kevin Wolf (cherry picked from commit cdbae85169c384d1641aa1ae86cdeefe16285745) --- qemu-img.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-img.c b/qemu-img.c index e300f911c..d2a978b91 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1286,7 +1286,7 @@ static int img_rebase(int argc, char **argv) } bs_new_backing = bdrv_new("new_backing"); - ret = bdrv_open(bs_new_backing, out_baseimg, BDRV_O_FLAGS | BDRV_O_RDWR, + ret = bdrv_open(bs_new_backing, out_baseimg, BDRV_O_FLAGS, new_backing_drv); if (ret) { error("Could not open new backing file '%s'", out_baseimg); -- cgit v1.2.3 From f891f9f74dac3622848ea3c10d11ac1c0b81869c Mon Sep 17 00:00:00 2001 From: Loïc Minier Date: Sun, 22 Aug 2010 00:47:23 +0200 Subject: vvfat: fat_chksum(): fix access above array bounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Loïc Minier Signed-off-by: Kevin Wolf (cherry picked from commit 2aa326be0d2039f51192707bdb2fc935d0e87c21) --- block/vvfat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/vvfat.c b/block/vvfat.c index 6d61c2e6c..365332aa2 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -512,7 +512,7 @@ static inline uint8_t fat_chksum(const direntry_t* entry) for(i=0;i<11;i++) { unsigned char c; - c = (i <= 8) ? entry->name[i] : entry->extension[i-8]; + c = (i < 8) ? entry->name[i] : entry->extension[i-8]; chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0)) + c; } -- cgit v1.2.3 From a9b56f82895d1fd86c3fa2bb9c913625d350ff47 Mon Sep 17 00:00:00 2001 From: Andrew de Quincey Date: Sun, 8 Aug 2010 21:04:50 +0100 Subject: posix-aio-compat: Fix async_conmtext for ioctl Set the async_context_id field when queuing an async ioctl call Signed-off-by: Andrew de Quincey Signed-off-by: Kevin Wolf (cherry picked from commit 34cf0081294513bc734896c9051c20ca6c19c3db) --- posix-aio-compat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/posix-aio-compat.c b/posix-aio-compat.c index a67ffe311..efc59683c 100644 --- a/posix-aio-compat.c +++ b/posix-aio-compat.c @@ -599,6 +599,7 @@ BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd, acb->aio_type = QEMU_AIO_IOCTL; acb->aio_fildes = fd; acb->ev_signo = SIGUSR2; + acb->async_context_id = get_async_context_id(); acb->aio_offset = 0; acb->aio_ioctl_buf = buf; acb->aio_ioctl_cmd = req; -- cgit v1.2.3 From 72230c523bda18d4dd2f7d16f96cc59e8fbbd6c9 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 31 Aug 2010 08:19:23 -0500 Subject: Update version for 0.13.0-rc1 Signed-off-by: Anthony Liguori --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index bc4cbfa42..0eb28840f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.12.90 +0.12.91 -- cgit v1.2.3