* [Qemu-devel] [PATCH v3 2.1 1/4] virtio-blk: Factor common checks out of virtio_blk_handle_read/write()
2014-07-09 14:11 [Qemu-devel] [PATCH v3 2.1 0/4] Suppress error action on r/w beyond end Markus Armbruster
@ 2014-07-09 14:11 ` Markus Armbruster
2014-07-09 14:11 ` [Qemu-devel] [PATCH v3 2.1 2/4] virtio-blk: Bypass error action and I/O accounting on invalid r/w Markus Armbruster
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Markus Armbruster @ 2014-07-09 14:11 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, famz, uobergfe, stefanha
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
---
hw/block/virtio-blk.c | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index aec3146..d946fa9 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -288,6 +288,18 @@ 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)
+{
+ if (sector & dev->sector_mask) {
+ return false;
+ }
+ if (size % dev->conf->logical_block_size) {
+ return false;
+ }
+ return true;
+}
+
static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
{
BlockRequest *blkreq;
@@ -299,11 +311,7 @@ static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
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) {
+ if (!virtio_blk_sect_range_ok(req->dev, sector, req->qiov.size)) {
virtio_blk_rw_complete(req, -EIO);
return;
}
@@ -333,11 +341,7 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
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) {
+ if (!virtio_blk_sect_range_ok(req->dev, sector, req->qiov.size)) {
virtio_blk_rw_complete(req, -EIO);
return;
}
--
1.9.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH v3 2.1 2/4] virtio-blk: Bypass error action and I/O accounting on invalid r/w
2014-07-09 14:11 [Qemu-devel] [PATCH v3 2.1 0/4] Suppress error action on r/w beyond end Markus Armbruster
2014-07-09 14:11 ` [Qemu-devel] [PATCH v3 2.1 1/4] virtio-blk: Factor common checks out of virtio_blk_handle_read/write() Markus Armbruster
@ 2014-07-09 14:11 ` Markus Armbruster
2014-07-09 14:11 ` [Qemu-devel] [PATCH v3 2.1 3/4] virtio-blk: Treat read/write beyond end as invalid Markus Armbruster
2014-07-09 14:11 ` [Qemu-devel] [PATCH v3 2.1 4/4] ide: " Markus Armbruster
3 siblings, 0 replies; 5+ messages in thread
From: Markus Armbruster @ 2014-07-09 14:11 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, famz, uobergfe, stefanha
When a device model's I/O operation fails, we execute the error
action. This lets layers above QEMU implement thin provisioning, or
attempt to correct errors before they reach the guest. But when the
I/O operation fails because it's invalid, reporting the error to the
guest is the only sensible action.
If the guest's read or write asks for an invalid sector range, fail
the request right away, without considering the error action. No
change with error action BDRV_ACTION_REPORT.
Furthermore, bypass I/O accounting, because we want to track only I/O
that actually reaches the block layer.
The next commit will extend "invalid sector range" to cover attempts
to read/write beyond the end of the medium.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
hw/block/virtio-blk.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index d946fa9..53d6f92 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -307,15 +307,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 (!virtio_blk_sect_range_ok(req->dev, sector, req->qiov.size)) {
- virtio_blk_rw_complete(req, -EIO);
+ 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);
}
@@ -337,14 +338,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 (!virtio_blk_sect_range_ok(req->dev, sector, req->qiov.size)) {
- virtio_blk_rw_complete(req, -EIO);
+ 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);
--
1.9.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH v3 2.1 3/4] virtio-blk: Treat read/write beyond end as invalid
2014-07-09 14:11 [Qemu-devel] [PATCH v3 2.1 0/4] Suppress error action on r/w beyond end Markus Armbruster
2014-07-09 14:11 ` [Qemu-devel] [PATCH v3 2.1 1/4] virtio-blk: Factor common checks out of virtio_blk_handle_read/write() Markus Armbruster
2014-07-09 14:11 ` [Qemu-devel] [PATCH v3 2.1 2/4] virtio-blk: Bypass error action and I/O accounting on invalid r/w Markus Armbruster
@ 2014-07-09 14:11 ` Markus Armbruster
2014-07-09 14:11 ` [Qemu-devel] [PATCH v3 2.1 4/4] ide: " Markus Armbruster
3 siblings, 0 replies; 5+ messages in thread
From: Markus Armbruster @ 2014-07-09 14:11 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, famz, uobergfe, stefanha
The block layer fails such reads and writes just fine. However, they
then get treated like valid operations that fail: the error action
gets executed. Unwanted; reporting the error to the guest is the only
sensible action.
Reject them before passing them to the block layer. This bypasses the
error action and I/O accounting.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
---
hw/block/virtio-blk.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 53d6f92..8a2cff2 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -291,12 +291,19 @@ static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
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;
}
--
1.9.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH v3 2.1 4/4] ide: Treat read/write beyond end as invalid
2014-07-09 14:11 [Qemu-devel] [PATCH v3 2.1 0/4] Suppress error action on r/w beyond end Markus Armbruster
` (2 preceding siblings ...)
2014-07-09 14:11 ` [Qemu-devel] [PATCH v3 2.1 3/4] virtio-blk: Treat read/write beyond end as invalid Markus Armbruster
@ 2014-07-09 14:11 ` Markus Armbruster
3 siblings, 0 replies; 5+ messages in thread
From: Markus Armbruster @ 2014-07-09 14:11 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, famz, uobergfe, stefanha
The block layer fails such reads and writes just fine. However, they
then get treated like valid operations that fail: the error action
gets executed. Unwanted; reporting the error to the guest is the only
sensible action.
Reject them before passing them to the block layer. This bypasses the
error action and, for PIO but not DMA, I/O accounting. Tolerable,
because I/O accounting is an inconsistent mess anyway.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
hw/ide/core.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 3a38f1e..63a500d 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -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);
+ goto eot;
+ }
+
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);
--
1.9.3
^ permalink raw reply related [flat|nested] 5+ messages in thread