mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-12-11 16:00:50 -07:00
Block patches for 2.1.0-rc2 (v2)
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJTw6scAAoJEH8JsnLIjy/WWk8QAMmThVQhJqajBbriVJWfB5w4 A4ZaRpk+NsDUZhzbsVBJ06ZdlQSX76JOT17V1hDFe7wcu1Aq8XL2b0PzV4iDNRgJ QPjW7vKAfFq/ANziGfgfAhpeQkq8o5+R8OepmdqJXzIDCjg+nDtJVdsc7G8DIWOx 1ssEqW8zaRuZMck61mo3hpdCCA+m+3HTHhcDEf/lzS69XHi2+BZ6ATVh3zShJqxy +68hDHdPNMTWESkN5MBQAo82flbdmNjqpD5SYYuJsoCOV+Tb5jLUGbED/VM1LqCf 8ukXlu4TO0u3ZmO+3XeQJiNsBSQEGOp9/9gOYj8J7AaZcZzC4cON3RmiYLZLgapj zdKIvgCxuFzyFheJYPCwpr3483w6/mh4uMzasZ+jHETqieAyvy1L860FNdWQaXoX K96m/1yIaQ2NOogcWrxZZ4Jt/diKh+NWynBFm8MZON6MK46FLiCcma2ZedoX6dNc R+Ul0qiYMo5B9fX05uhf15dU8cmVQuVFRo2ftIIqxZDY9IPjJjrJPw9EjHajGIJb MpU25NRHCdf0BscgYufuf1W9llasl0fbAd3SIA4FccTFdAeDwu5SQXHTodhu64hh 7gf23N7Let/Gnucxx7gOTi1Jz3uR8V7MbIYRgBBvyRqhNRRRjYDwpg2c8guCzM2F VObGeTRdNa9QhTXqBPdQ =YxHy -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging Block patches for 2.1.0-rc2 (v2) # gpg: Signature made Mon 14 Jul 2014 11:04:12 BST using RSA key ID C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" * remotes/kevin/tags/for-upstream: (22 commits) ide: Treat read/write beyond end as invalid virtio-blk: Treat read/write beyond end as invalid virtio-blk: Bypass error action and I/O accounting on invalid r/w virtio-blk: Factor common checks out of virtio_blk_handle_read/write() dma-helpers: Fix too long qiov qtest: fix vhost-user-test compilation with old GLib tests: Fix unterminated string output visitor enum human string AioContext: do not rely on aio_poll(ctx, true) result to end a loop virtio-blk: embed VirtQueueElement in VirtIOBlockReq virtio-blk: avoid g_slice_new0() for VirtIOBlockReq and VirtQueueElement dataplane: do not free VirtQueueElement in vring_push() virtio-blk: avoid dataplane VirtIOBlockReq early free block: Assert qiov length matches request length qed: Make qiov match request size until backing file EOF qcow2: Make qiov match request size until backing file EOF block: Make qiov match the request size until EOF AioContext: speed up aio_notify test-aio: fix GSource-based timer test block: drop aio functions that operate on the main AioContext block: prefer aio_poll to qemu_aio_wait ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
7a6d04e73f
30 changed files with 699 additions and 167 deletions
|
|
@ -65,43 +65,41 @@ static void complete_request_vring(VirtIOBlockReq *req, unsigned char status)
|
|||
{
|
||||
stb_p(&req->in->status, status);
|
||||
|
||||
vring_push(&req->dev->dataplane->vring, req->elem,
|
||||
vring_push(&req->dev->dataplane->vring, &req->elem,
|
||||
req->qiov.size + sizeof(*req->in));
|
||||
notify_guest(req->dev->dataplane);
|
||||
g_slice_free(VirtIOBlockReq, req);
|
||||
}
|
||||
|
||||
static void handle_notify(EventNotifier *e)
|
||||
{
|
||||
VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane,
|
||||
host_notifier);
|
||||
|
||||
VirtQueueElement *elem;
|
||||
VirtIOBlockReq *req;
|
||||
int ret;
|
||||
MultiReqBuffer mrb = {
|
||||
.num_writes = 0,
|
||||
};
|
||||
VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
|
||||
|
||||
event_notifier_test_and_clear(&s->host_notifier);
|
||||
bdrv_io_plug(s->blk->conf.bs);
|
||||
for (;;) {
|
||||
MultiReqBuffer mrb = {
|
||||
.num_writes = 0,
|
||||
};
|
||||
int ret;
|
||||
|
||||
/* Disable guest->host notifies to avoid unnecessary vmexits */
|
||||
vring_disable_notification(s->vdev, &s->vring);
|
||||
|
||||
for (;;) {
|
||||
ret = vring_pop(s->vdev, &s->vring, &elem);
|
||||
VirtIOBlockReq *req = virtio_blk_alloc_request(vblk);
|
||||
|
||||
ret = vring_pop(s->vdev, &s->vring, &req->elem);
|
||||
if (ret < 0) {
|
||||
assert(elem == NULL);
|
||||
virtio_blk_free_request(req);
|
||||
break; /* no more requests */
|
||||
}
|
||||
|
||||
trace_virtio_blk_data_plane_process_request(s, elem->out_num,
|
||||
elem->in_num, elem->index);
|
||||
trace_virtio_blk_data_plane_process_request(s, req->elem.out_num,
|
||||
req->elem.in_num,
|
||||
req->elem.index);
|
||||
|
||||
req = g_slice_new(VirtIOBlockReq);
|
||||
req->dev = VIRTIO_BLK(s->vdev);
|
||||
req->elem = elem;
|
||||
virtio_blk_handle_request(req, &mrb);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,18 +29,18 @@
|
|||
#include "hw/virtio/virtio-bus.h"
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
|
||||
static VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
|
||||
VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
|
||||
{
|
||||
VirtIOBlockReq *req = g_slice_new0(VirtIOBlockReq);
|
||||
VirtIOBlockReq *req = g_slice_new(VirtIOBlockReq);
|
||||
req->dev = s;
|
||||
req->elem = g_slice_new0(VirtQueueElement);
|
||||
req->qiov.size = 0;
|
||||
req->next = NULL;
|
||||
return req;
|
||||
}
|
||||
|
||||
static void virtio_blk_free_request(VirtIOBlockReq *req)
|
||||
void virtio_blk_free_request(VirtIOBlockReq *req)
|
||||
{
|
||||
if (req) {
|
||||
g_slice_free(VirtQueueElement, req->elem);
|
||||
g_slice_free(VirtIOBlockReq, req);
|
||||
}
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ static void virtio_blk_complete_request(VirtIOBlockReq *req,
|
|||
trace_virtio_blk_req_complete(req, status);
|
||||
|
||||
stb_p(&req->in->status, status);
|
||||
virtqueue_push(s->vq, req->elem, req->qiov.size + sizeof(*req->in));
|
||||
virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
|
||||
virtio_notify(vdev, s->vq);
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +119,7 @@ static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
|
|||
{
|
||||
VirtIOBlockReq *req = virtio_blk_alloc_request(s);
|
||||
|
||||
if (!virtqueue_pop(s->vq, req->elem)) {
|
||||
if (!virtqueue_pop(s->vq, &req->elem)) {
|
||||
virtio_blk_free_request(req);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -252,7 +252,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
|
|||
{
|
||||
int status;
|
||||
|
||||
status = virtio_blk_handle_scsi_req(req->dev, req->elem);
|
||||
status = virtio_blk_handle_scsi_req(req->dev, &req->elem);
|
||||
virtio_blk_req_complete(req, status);
|
||||
virtio_blk_free_request(req);
|
||||
}
|
||||
|
|
@ -288,6 +288,25 @@ static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
|||
bdrv_aio_flush(req->dev->bs, virtio_blk_flush_complete, req);
|
||||
}
|
||||
|
||||
static bool virtio_blk_sect_range_ok(VirtIOBlock *dev,
|
||||
uint64_t sector, size_t size)
|
||||
{
|
||||
uint64_t nb_sectors = size >> BDRV_SECTOR_BITS;
|
||||
uint64_t total_sectors;
|
||||
|
||||
if (sector & dev->sector_mask) {
|
||||
return false;
|
||||
}
|
||||
if (size % dev->conf->logical_block_size) {
|
||||
return false;
|
||||
}
|
||||
bdrv_get_geometry(dev->bs, &total_sectors);
|
||||
if (sector > total_sectors || nb_sectors > total_sectors - sector) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
||||
{
|
||||
BlockRequest *blkreq;
|
||||
|
|
@ -295,19 +314,16 @@ static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
|||
|
||||
sector = virtio_ldq_p(VIRTIO_DEVICE(req->dev), &req->out.sector);
|
||||
|
||||
bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_WRITE);
|
||||
|
||||
trace_virtio_blk_handle_write(req, sector, req->qiov.size / 512);
|
||||
|
||||
if (sector & req->dev->sector_mask) {
|
||||
virtio_blk_rw_complete(req, -EIO);
|
||||
return;
|
||||
}
|
||||
if (req->qiov.size % req->dev->conf->logical_block_size) {
|
||||
virtio_blk_rw_complete(req, -EIO);
|
||||
if (!virtio_blk_sect_range_ok(req->dev, sector, req->qiov.size)) {
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
|
||||
virtio_blk_free_request(req);
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_WRITE);
|
||||
|
||||
if (mrb->num_writes == 32) {
|
||||
virtio_submit_multiwrite(req->dev->bs, mrb);
|
||||
}
|
||||
|
|
@ -329,18 +345,15 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
|
|||
|
||||
sector = virtio_ldq_p(VIRTIO_DEVICE(req->dev), &req->out.sector);
|
||||
|
||||
bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_READ);
|
||||
|
||||
trace_virtio_blk_handle_read(req, sector, req->qiov.size / 512);
|
||||
|
||||
if (sector & req->dev->sector_mask) {
|
||||
virtio_blk_rw_complete(req, -EIO);
|
||||
return;
|
||||
}
|
||||
if (req->qiov.size % req->dev->conf->logical_block_size) {
|
||||
virtio_blk_rw_complete(req, -EIO);
|
||||
if (!virtio_blk_sect_range_ok(req->dev, sector, req->qiov.size)) {
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
|
||||
virtio_blk_free_request(req);
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_READ);
|
||||
bdrv_aio_readv(req->dev->bs, sector, &req->qiov,
|
||||
req->qiov.size / BDRV_SECTOR_SIZE,
|
||||
virtio_blk_rw_complete, req);
|
||||
|
|
@ -349,12 +362,12 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
|
|||
void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
||||
{
|
||||
uint32_t type;
|
||||
struct iovec *in_iov = req->elem->in_sg;
|
||||
struct iovec *iov = req->elem->out_sg;
|
||||
unsigned in_num = req->elem->in_num;
|
||||
unsigned out_num = req->elem->out_num;
|
||||
struct iovec *in_iov = req->elem.in_sg;
|
||||
struct iovec *iov = req->elem.out_sg;
|
||||
unsigned in_num = req->elem.in_num;
|
||||
unsigned out_num = req->elem.out_num;
|
||||
|
||||
if (req->elem->out_num < 1 || req->elem->in_num < 1) {
|
||||
if (req->elem.out_num < 1 || req->elem.in_num < 1) {
|
||||
error_report("virtio-blk missing headers");
|
||||
exit(1);
|
||||
}
|
||||
|
|
@ -391,19 +404,19 @@ void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
|||
* NB: per existing s/n string convention the string is
|
||||
* terminated by '\0' only when shorter than buffer.
|
||||
*/
|
||||
strncpy(req->elem->in_sg[0].iov_base,
|
||||
strncpy(req->elem.in_sg[0].iov_base,
|
||||
s->blk.serial ? s->blk.serial : "",
|
||||
MIN(req->elem->in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES));
|
||||
MIN(req->elem.in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES));
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
|
||||
virtio_blk_free_request(req);
|
||||
} else if (type & VIRTIO_BLK_T_OUT) {
|
||||
qemu_iovec_init_external(&req->qiov, &req->elem->out_sg[1],
|
||||
req->elem->out_num - 1);
|
||||
qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
|
||||
req->elem.out_num - 1);
|
||||
virtio_blk_handle_write(req, mrb);
|
||||
} else if (type == VIRTIO_BLK_T_IN || type == VIRTIO_BLK_T_BARRIER) {
|
||||
/* VIRTIO_BLK_T_IN is 0, so we can't just & it. */
|
||||
qemu_iovec_init_external(&req->qiov, &req->elem->in_sg[0],
|
||||
req->elem->in_num - 1);
|
||||
qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
|
||||
req->elem.in_num - 1);
|
||||
virtio_blk_handle_read(req);
|
||||
} else {
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
|
||||
|
|
@ -627,7 +640,7 @@ static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f)
|
|||
|
||||
while (req) {
|
||||
qemu_put_sbyte(f, 1);
|
||||
qemu_put_buffer(f, (unsigned char *)req->elem,
|
||||
qemu_put_buffer(f, (unsigned char *)&req->elem,
|
||||
sizeof(VirtQueueElement));
|
||||
req = req->next;
|
||||
}
|
||||
|
|
@ -652,15 +665,15 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f,
|
|||
|
||||
while (qemu_get_sbyte(f)) {
|
||||
VirtIOBlockReq *req = virtio_blk_alloc_request(s);
|
||||
qemu_get_buffer(f, (unsigned char *)req->elem,
|
||||
qemu_get_buffer(f, (unsigned char *)&req->elem,
|
||||
sizeof(VirtQueueElement));
|
||||
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);
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -499,6 +499,18 @@ static void ide_rw_error(IDEState *s) {
|
|||
ide_set_irq(s->bus);
|
||||
}
|
||||
|
||||
static bool ide_sect_range_ok(IDEState *s,
|
||||
uint64_t sector, uint64_t nb_sectors)
|
||||
{
|
||||
uint64_t total_sectors;
|
||||
|
||||
bdrv_get_geometry(s->bs, &total_sectors);
|
||||
if (sector > total_sectors || nb_sectors > total_sectors - sector) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ide_sector_read_cb(void *opaque, int ret)
|
||||
{
|
||||
IDEState *s = opaque;
|
||||
|
|
@ -554,6 +566,11 @@ void ide_sector_read(IDEState *s)
|
|||
printf("sector=%" PRId64 "\n", sector_num);
|
||||
#endif
|
||||
|
||||
if (!ide_sect_range_ok(s, sector_num, n)) {
|
||||
ide_rw_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
s->iov.iov_base = s->io_buffer;
|
||||
s->iov.iov_len = n * BDRV_SECTOR_SIZE;
|
||||
qemu_iovec_init_external(&s->qiov, &s->iov, 1);
|
||||
|
|
@ -671,6 +688,12 @@ void ide_dma_cb(void *opaque, int ret)
|
|||
sector_num, n, s->dma_cmd);
|
||||
#endif
|
||||
|
||||
if (!ide_sect_range_ok(s, sector_num, n)) {
|
||||
dma_buf_commit(s);
|
||||
ide_dma_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (s->dma_cmd) {
|
||||
case IDE_DMA_READ:
|
||||
s->bus->dma->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
|
||||
|
|
@ -790,6 +813,11 @@ void ide_sector_write(IDEState *s)
|
|||
n = s->req_nb_sectors;
|
||||
}
|
||||
|
||||
if (!ide_sect_range_ok(s, sector_num, n)) {
|
||||
ide_rw_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
s->iov.iov_base = s->io_buffer;
|
||||
s->iov.iov_len = n * BDRV_SECTOR_SIZE;
|
||||
qemu_iovec_init_external(&s->qiov, &s->iov, 1);
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ static int get_indirect(Vring *vring, VirtQueueElement *elem,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void vring_free_element(VirtQueueElement *elem)
|
||||
static void vring_unmap_element(VirtQueueElement *elem)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -287,8 +287,6 @@ void vring_free_element(VirtQueueElement *elem)
|
|||
for (i = 0; i < elem->in_num; i++) {
|
||||
vring_unmap(elem->in_sg[i].iov_base, true);
|
||||
}
|
||||
|
||||
g_slice_free(VirtQueueElement, elem);
|
||||
}
|
||||
|
||||
/* This looks in the virtqueue and for the first available buffer, and converts
|
||||
|
|
@ -303,14 +301,16 @@ void vring_free_element(VirtQueueElement *elem)
|
|||
* Stolen from linux/drivers/vhost/vhost.c.
|
||||
*/
|
||||
int vring_pop(VirtIODevice *vdev, Vring *vring,
|
||||
VirtQueueElement **p_elem)
|
||||
VirtQueueElement *elem)
|
||||
{
|
||||
struct vring_desc desc;
|
||||
unsigned int i, head, found = 0, num = vring->vr.num;
|
||||
uint16_t avail_idx, last_avail_idx;
|
||||
VirtQueueElement *elem = NULL;
|
||||
int ret;
|
||||
|
||||
/* Initialize elem so it can be safely unmapped */
|
||||
elem->in_num = elem->out_num = 0;
|
||||
|
||||
/* If there was a fatal error then refuse operation */
|
||||
if (vring->broken) {
|
||||
ret = -EFAULT;
|
||||
|
|
@ -342,10 +342,8 @@ int vring_pop(VirtIODevice *vdev, Vring *vring,
|
|||
* the index we've seen. */
|
||||
head = vring->vr.avail->ring[last_avail_idx % num];
|
||||
|
||||
elem = g_slice_new(VirtQueueElement);
|
||||
elem->index = head;
|
||||
elem->in_num = elem->out_num = 0;
|
||||
|
||||
|
||||
/* If their number is silly, that's an error. */
|
||||
if (unlikely(head >= num)) {
|
||||
error_report("Guest says index %u > %u is available", head, num);
|
||||
|
|
@ -393,7 +391,6 @@ int vring_pop(VirtIODevice *vdev, Vring *vring,
|
|||
|
||||
/* On success, increment avail index. */
|
||||
vring->last_avail_idx++;
|
||||
*p_elem = elem;
|
||||
return head;
|
||||
|
||||
out:
|
||||
|
|
@ -401,10 +398,7 @@ out:
|
|||
if (ret == -EFAULT) {
|
||||
vring->broken = true;
|
||||
}
|
||||
if (elem) {
|
||||
vring_free_element(elem);
|
||||
}
|
||||
*p_elem = NULL;
|
||||
vring_unmap_element(elem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -418,7 +412,7 @@ void vring_push(Vring *vring, VirtQueueElement *elem, int len)
|
|||
unsigned int head = elem->index;
|
||||
uint16_t new;
|
||||
|
||||
vring_free_element(elem);
|
||||
vring_unmap_element(elem);
|
||||
|
||||
/* Don't touch vring if a fatal error occurred */
|
||||
if (vring->broken) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue