aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2015-11-12 17:22:06 +0000
committerPeter Maydell <peter.maydell@linaro.org>2015-11-12 17:22:06 +0000
commitb2df6a79df6343d0ed4ea05d83b3ff1d849e8d25 (patch)
treedbdbb73641e92a85f29ff12b7d010320ef6cd619 /hw
parentcfcc7c144879ebe61ac2472216314fc1331b4450 (diff)
parentaece5edc96f211eec6febdafc9bbbb99315a2efd (diff)
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block layer patches (rebased Stefan's pull request) # gpg: Signature made Thu 12 Nov 2015 15:34:16 GMT using RSA key ID C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" * remotes/kevin/tags/for-upstream: (43 commits) block: Update copyright of the accounting code scsi-disk: Account for failed operations macio: Account for failed operations ide: Account for failed and invalid operations atapi: Account for failed and invalid operations xen_disk: Account for failed and invalid operations virtio-blk: Account for failed and invalid operations nvme: Account for failed and invalid operations iotests: Add test for the block device statistics block: Use QEMU_CLOCK_VIRTUAL for the accounting code in qtest mode qemu-io: Account for failed, invalid and flush operations block: New option to define the intervals for collecting I/O statistics block: Add average I/O queue depth to BlockDeviceTimedStats block: Compute minimum, maximum and average I/O latencies block: Allow configuring whether to account failed and invalid ops block: Add statistics for failed and invalid I/O operations block: Add idle_time_ns to BlockDeviceStats util: Infrastructure for computing recent averages block: define 'clock_type' for the accounting code ide: Account for write operations correctly ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/block/nvme.c11
-rw-r--r--hw/block/virtio-blk.c4
-rw-r--r--hw/block/xen_disk.c27
-rw-r--r--hw/ide/atapi.c31
-rw-r--r--hw/ide/core.c12
-rw-r--r--hw/ide/macio.c12
-rw-r--r--hw/scsi/scsi-disk.c46
7 files changed, 105 insertions, 38 deletions
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 5da41b23cf..169e4fa7a5 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -201,10 +201,11 @@ static void nvme_rw_cb(void *opaque, int ret)
NvmeCtrl *n = sq->ctrl;
NvmeCQueue *cq = n->cq[sq->cqid];
- block_acct_done(blk_get_stats(n->conf.blk), &req->acct);
if (!ret) {
+ block_acct_done(blk_get_stats(n->conf.blk), &req->acct);
req->status = NVME_SUCCESS;
} else {
+ block_acct_failed(blk_get_stats(n->conf.blk), &req->acct);
req->status = NVME_INTERNAL_DEV_ERROR;
}
if (req->has_sg) {
@@ -238,18 +239,22 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
uint64_t data_size = (uint64_t)nlb << data_shift;
uint64_t aio_slba = slba << (data_shift - BDRV_SECTOR_BITS);
int is_write = rw->opcode == NVME_CMD_WRITE ? 1 : 0;
+ enum BlockAcctType acct = is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ;
if ((slba + nlb) > ns->id_ns.nsze) {
+ block_acct_invalid(blk_get_stats(n->conf.blk), acct);
return NVME_LBA_RANGE | NVME_DNR;
}
+
if (nvme_map_prp(&req->qsg, prp1, prp2, data_size, n)) {
+ block_acct_invalid(blk_get_stats(n->conf.blk), acct);
return NVME_INVALID_FIELD | NVME_DNR;
}
+
assert((nlb << data_shift) == req->qsg.size);
req->has_sg = true;
- dma_acct_start(n->conf.blk, &req->acct, &req->qsg,
- is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
+ dma_acct_start(n->conf.blk, &req->acct, &req->qsg, acct);
req->aiocb = is_write ?
dma_blk_write(n->conf.blk, &req->qsg, aio_slba, nvme_rw_cb, req) :
dma_blk_read(n->conf.blk, &req->qsg, aio_slba, nvme_rw_cb, req);
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 093e475dc9..e70fccf80c 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -76,7 +76,7 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
s->rq = req;
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
- block_acct_done(blk_get_stats(s->blk), &req->acct);
+ block_acct_failed(blk_get_stats(s->blk), &req->acct);
virtio_blk_free_request(req);
}
@@ -536,6 +536,8 @@ void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
if (!virtio_blk_sect_range_ok(req->dev, req->sector_num,
req->qiov.size)) {
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
+ block_acct_invalid(blk_get_stats(req->dev->blk),
+ is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
virtio_blk_free_request(req);
return;
}
diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
index 1bbc111939..02eda6efbc 100644
--- a/hw/block/xen_disk.c
+++ b/hw/block/xen_disk.c
@@ -537,7 +537,11 @@ static void qemu_aio_complete(void *opaque, int ret)
break;
}
case BLKIF_OP_READ:
- block_acct_done(blk_get_stats(ioreq->blkdev->blk), &ioreq->acct);
+ if (ioreq->status == BLKIF_RSP_OKAY) {
+ block_acct_done(blk_get_stats(ioreq->blkdev->blk), &ioreq->acct);
+ } else {
+ block_acct_failed(blk_get_stats(ioreq->blkdev->blk), &ioreq->acct);
+ }
break;
case BLKIF_OP_DISCARD:
default:
@@ -576,7 +580,9 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
}
block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct,
- ioreq->v.size, BLOCK_ACCT_WRITE);
+ ioreq->v.size,
+ ioreq->req.operation == BLKIF_OP_WRITE ?
+ BLOCK_ACCT_WRITE : BLOCK_ACCT_FLUSH);
ioreq->aio_inflight++;
blk_aio_writev(blkdev->blk, ioreq->start / BLOCK_SIZE,
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
@@ -720,6 +726,23 @@ static void blk_handle_requests(struct XenBlkDev *blkdev)
/* parse them */
if (ioreq_parse(ioreq) != 0) {
+
+ switch (ioreq->req.operation) {
+ case BLKIF_OP_READ:
+ block_acct_invalid(blk_get_stats(blkdev->blk),
+ BLOCK_ACCT_READ);
+ break;
+ case BLKIF_OP_WRITE:
+ block_acct_invalid(blk_get_stats(blkdev->blk),
+ BLOCK_ACCT_WRITE);
+ break;
+ case BLKIF_OP_FLUSH_DISKCACHE:
+ block_acct_invalid(blk_get_stats(blkdev->blk),
+ BLOCK_ACCT_FLUSH);
+ default:
+ break;
+ };
+
if (blk_send_response_one(ioreq)) {
xen_be_send_notify(&blkdev->xendev);
}
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index 747f46611e..cf0b78e3a4 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -108,27 +108,30 @@ static void cd_data_to_raw(uint8_t *buf, int lba)
static int cd_read_sector(IDEState *s, int lba, uint8_t *buf, int sector_size)
{
int ret;
+ block_acct_start(blk_get_stats(s->blk), &s->acct,
+ 4 * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ);
switch(sector_size) {
case 2048:
- block_acct_start(blk_get_stats(s->blk), &s->acct,
- 4 * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ);
ret = blk_read(s->blk, (int64_t)lba << 2, buf, 4);
- block_acct_done(blk_get_stats(s->blk), &s->acct);
break;
case 2352:
- block_acct_start(blk_get_stats(s->blk), &s->acct,
- 4 * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ);
ret = blk_read(s->blk, (int64_t)lba << 2, buf + 16, 4);
- block_acct_done(blk_get_stats(s->blk), &s->acct);
- if (ret < 0)
- return ret;
- cd_data_to_raw(buf, lba);
+ if (ret >= 0) {
+ cd_data_to_raw(buf, lba);
+ }
break;
default:
- ret = -EIO;
- break;
+ block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_READ);
+ return -EIO;
+ }
+
+ if (ret < 0) {
+ block_acct_failed(blk_get_stats(s->blk), &s->acct);
+ } else {
+ block_acct_done(blk_get_stats(s->blk), &s->acct);
}
+
return ret;
}
@@ -357,7 +360,11 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
return;
eot:
- block_acct_done(blk_get_stats(s->blk), &s->acct);
+ if (ret < 0) {
+ block_acct_failed(blk_get_stats(s->blk), &s->acct);
+ } else {
+ block_acct_done(blk_get_stats(s->blk), &s->acct);
+ }
ide_set_inactive(s, false);
}
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 364ba21e0c..2725dd3b81 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -574,7 +574,6 @@ static void ide_sector_read_cb(void *opaque, int ret)
if (ret == -ECANCELED) {
return;
}
- block_acct_done(blk_get_stats(s->blk), &s->acct);
if (ret != 0) {
if (ide_handle_rw_error(s, -ret, IDE_RETRY_PIO |
IDE_RETRY_READ)) {
@@ -582,6 +581,8 @@ static void ide_sector_read_cb(void *opaque, int ret)
}
}
+ block_acct_done(blk_get_stats(s->blk), &s->acct);
+
n = s->nsector;
if (n > s->req_nb_sectors) {
n = s->req_nb_sectors;
@@ -621,6 +622,7 @@ static void ide_sector_read(IDEState *s)
if (!ide_sect_range_ok(s, sector_num, n)) {
ide_rw_error(s);
+ block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_READ);
return;
}
@@ -672,6 +674,7 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
assert(s->bus->retry_unit == s->unit);
s->bus->error_status = op;
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
+ block_acct_failed(blk_get_stats(s->blk), &s->acct);
if (op & IDE_RETRY_DMA) {
ide_dma_error(s);
} else {
@@ -750,6 +753,7 @@ static void ide_dma_cb(void *opaque, int ret)
if ((s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) &&
!ide_sect_range_ok(s, sector_num, n)) {
ide_dma_error(s);
+ block_acct_invalid(blk_get_stats(s->blk), s->acct.type);
return;
}
@@ -826,7 +830,6 @@ static void ide_sector_write_cb(void *opaque, int ret)
if (ret == -ECANCELED) {
return;
}
- block_acct_done(blk_get_stats(s->blk), &s->acct);
s->pio_aiocb = NULL;
s->status &= ~BUSY_STAT;
@@ -837,6 +840,8 @@ static void ide_sector_write_cb(void *opaque, int ret)
}
}
+ block_acct_done(blk_get_stats(s->blk), &s->acct);
+
n = s->nsector;
if (n > s->req_nb_sectors) {
n = s->req_nb_sectors;
@@ -887,6 +892,7 @@ static void ide_sector_write(IDEState *s)
if (!ide_sect_range_ok(s, sector_num, n)) {
ide_rw_error(s);
+ block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_WRITE);
return;
}
@@ -895,7 +901,7 @@ static void ide_sector_write(IDEState *s)
qemu_iovec_init_external(&s->qiov, &s->iov, 1);
block_acct_start(blk_get_stats(s->blk), &s->acct,
- n * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ);
+ n * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE);
s->pio_aiocb = blk_aio_writev(s->blk, sector_num, &s->qiov, n,
ide_sector_write_cb, s);
}
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index 893c9b9bae..3ee962f830 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -286,7 +286,11 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
return;
done:
- block_acct_done(blk_get_stats(s->blk), &s->acct);
+ if (ret < 0) {
+ block_acct_failed(blk_get_stats(s->blk), &s->acct);
+ } else {
+ block_acct_done(blk_get_stats(s->blk), &s->acct);
+ }
io->dma_end(opaque);
return;
@@ -348,7 +352,11 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
done:
if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
- block_acct_done(blk_get_stats(s->blk), &s->acct);
+ if (ret < 0) {
+ block_acct_failed(blk_get_stats(s->blk), &s->acct);
+ } else {
+ block_acct_done(blk_get_stats(s->blk), &s->acct);
+ }
}
io->dma_end(opaque);
}
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 707e7349a2..4797d83683 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -90,7 +90,7 @@ struct SCSIDiskState
bool tray_locked;
};
-static int scsi_handle_rw_error(SCSIDiskReq *r, int error);
+static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed);
static void scsi_free_request(SCSIRequest *req)
{
@@ -169,18 +169,18 @@ static void scsi_aio_complete(void *opaque, int ret)
assert(r->req.aiocb != NULL);
r->req.aiocb = NULL;
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
if (r->req.io_canceled) {
scsi_req_cancel_complete(&r->req);
goto done;
}
if (ret < 0) {
- if (scsi_handle_rw_error(r, -ret)) {
+ if (scsi_handle_rw_error(r, -ret, true)) {
goto done;
}
}
+ block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
scsi_req_complete(&r->req, GOOD);
done:
@@ -247,7 +247,7 @@ static void scsi_dma_complete_noio(SCSIDiskReq *r, int ret)
}
if (ret < 0) {
- if (scsi_handle_rw_error(r, -ret)) {
+ if (scsi_handle_rw_error(r, -ret, false)) {
goto done;
}
}
@@ -273,7 +273,11 @@ static void scsi_dma_complete(void *opaque, int ret)
assert(r->req.aiocb != NULL);
r->req.aiocb = NULL;
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ if (ret < 0) {
+ block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ } else {
+ block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ }
scsi_dma_complete_noio(r, ret);
}
@@ -285,18 +289,18 @@ static void scsi_read_complete(void * opaque, int ret)
assert(r->req.aiocb != NULL);
r->req.aiocb = NULL;
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
if (r->req.io_canceled) {
scsi_req_cancel_complete(&r->req);
goto done;
}
if (ret < 0) {
- if (scsi_handle_rw_error(r, -ret)) {
+ if (scsi_handle_rw_error(r, -ret, true)) {
goto done;
}
}
+ block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->qiov.size);
n = r->qiov.size / 512;
@@ -322,7 +326,7 @@ static void scsi_do_read(SCSIDiskReq *r, int ret)
}
if (ret < 0) {
- if (scsi_handle_rw_error(r, -ret)) {
+ if (scsi_handle_rw_error(r, -ret, false)) {
goto done;
}
}
@@ -355,7 +359,11 @@ static void scsi_do_read_cb(void *opaque, int ret)
assert (r->req.aiocb != NULL);
r->req.aiocb = NULL;
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ if (ret < 0) {
+ block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ } else {
+ block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ }
scsi_do_read(opaque, ret);
}
@@ -407,7 +415,7 @@ static void scsi_read_data(SCSIRequest *req)
* scsi_handle_rw_error always manages its reference counts, independent
* of the return value.
*/
-static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
+static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed)
{
bool is_read = (r->req.cmd.mode == SCSI_XFER_FROM_DEV);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
@@ -415,6 +423,9 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
is_read, error);
if (action == BLOCK_ERROR_ACTION_REPORT) {
+ if (acct_failed) {
+ block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ }
switch (error) {
case ENOMEDIUM:
scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
@@ -452,7 +463,7 @@ static void scsi_write_complete_noio(SCSIDiskReq *r, int ret)
}
if (ret < 0) {
- if (scsi_handle_rw_error(r, -ret)) {
+ if (scsi_handle_rw_error(r, -ret, false)) {
goto done;
}
}
@@ -481,7 +492,11 @@ static void scsi_write_complete(void * opaque, int ret)
assert (r->req.aiocb != NULL);
r->req.aiocb = NULL;
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ if (ret < 0) {
+ block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ } else {
+ block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ }
scsi_write_complete_noio(r, ret);
}
@@ -1592,7 +1607,7 @@ static void scsi_unmap_complete_noio(UnmapCBData *data, int ret)
}
if (ret < 0) {
- if (scsi_handle_rw_error(r, -ret)) {
+ if (scsi_handle_rw_error(r, -ret, false)) {
goto done;
}
}
@@ -1696,18 +1711,19 @@ static void scsi_write_same_complete(void *opaque, int ret)
assert(r->req.aiocb != NULL);
r->req.aiocb = NULL;
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
if (r->req.io_canceled) {
scsi_req_cancel_complete(&r->req);
goto done;
}
if (ret < 0) {
- if (scsi_handle_rw_error(r, -ret)) {
+ if (scsi_handle_rw_error(r, -ret, true)) {
goto done;
}
}
+ block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+
data->nb_sectors -= data->iov.iov_len / 512;
data->sector += data->iov.iov_len / 512;
data->iov.iov_len = MIN(data->nb_sectors * 512, data->iov.iov_len);