diff --git a/block.c b/block.c
index 061b4cc..95f2cd4 100644
--- a/block.c
+++ b/block.c
@@ -1969,6 +1969,9 @@ static void bdrv_stats_iter(QObject *data, void *opaque)
                         " wr_total_time_ns=%" PRId64
                         " rd_total_time_ns=%" PRId64
                         " flush_total_time_ns=%" PRId64
+                        " rd_errors=%" PRId64
+                        " wr_errors=%" PRId64
+                        " flush_errors=%" PRId64
                         "\n",
                         qdict_get_int(qdict, "rd_bytes"),
                         qdict_get_int(qdict, "wr_bytes"),
@@ -1977,7 +1980,10 @@ static void bdrv_stats_iter(QObject *data, void *opaque)
                         qdict_get_int(qdict, "flush_operations"),
                         qdict_get_int(qdict, "wr_total_time_ns"),
                         qdict_get_int(qdict, "rd_total_time_ns"),
-                        qdict_get_int(qdict, "flush_total_time_ns"));
+                        qdict_get_int(qdict, "flush_total_time_ns"),
+                        qdict_get_int(qdict, "rd_errors"),
+                        qdict_get_int(qdict, "wr_errors"),
+                        qdict_get_int(qdict, "flush_errors"));
 }
 
 void bdrv_stats_print(Monitor *mon, const QObject *data)
@@ -1999,7 +2005,10 @@ static QObject* bdrv_info_stats_bs(BlockDriverState *bs)
                              "'flush_operations': %" PRId64 ","
                              "'wr_total_time_ns': %" PRId64 ","
                              "'rd_total_time_ns': %" PRId64 ","
-                             "'flush_total_time_ns': %" PRId64
+                             "'flush_total_time_ns': %" PRId64 ","
+                             "'rd_errors': %" PRId64 ","
+                             "'wr_errors': %" PRId64 ","
+                             "'flush_errors': %" PRId64
                              "} }",
                              bs->nr_bytes[BDRV_ACCT_READ],
                              bs->nr_bytes[BDRV_ACCT_WRITE],
@@ -2010,7 +2019,10 @@ static QObject* bdrv_info_stats_bs(BlockDriverState *bs)
                              bs->nr_ops[BDRV_ACCT_FLUSH],
                              bs->total_time_ns[BDRV_ACCT_WRITE],
                              bs->total_time_ns[BDRV_ACCT_READ],
-                             bs->total_time_ns[BDRV_ACCT_FLUSH]);
+                             bs->total_time_ns[BDRV_ACCT_FLUSH],
+                             bs->nr_errors[BDRV_ACCT_READ],
+                             bs->nr_errors[BDRV_ACCT_WRITE],
+                             bs->nr_errors[BDRV_ACCT_FLUSH]);
     dict  = qobject_to_qdict(res);
 
     if (*bs->device_name) {
@@ -3250,13 +3262,17 @@ bdrv_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, int64_t bytes,
 }
 
 void
-bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie)
+bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie, int error)
 {
     assert(cookie->type < BDRV_MAX_IOTYPE);
 
-    bs->nr_bytes[cookie->type] += cookie->bytes;
-    bs->nr_ops[cookie->type]++;
-    bs->total_time_ns[cookie->type] += get_clock() - cookie->start_time_ns;
+    if (error < 0) {
+        bs->nr_errors[cookie->type]++;
+    } else {
+        bs->nr_bytes[cookie->type] += cookie->bytes;
+        bs->nr_ops[cookie->type]++;
+        bs->total_time_ns[cookie->type] += get_clock() - cookie->start_time_ns;
+    }
 }
 
 int bdrv_img_create(const char *filename, const char *fmt,
diff --git a/block.h b/block.h
index e77988e..2f33aca 100644
--- a/block.h
+++ b/block.h
@@ -309,7 +309,7 @@ typedef struct BlockAcctCookie {
 
 void bdrv_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie,
         int64_t bytes, enum BlockAcctType type);
-void bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie);
+void bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie, int error);
 
 typedef enum {
     BLKDBG_L1_UPDATE,
diff --git a/block_int.h b/block_int.h
index f2f4f2d..8c1a3cb 100644
--- a/block_int.h
+++ b/block_int.h
@@ -183,6 +183,7 @@ struct BlockDriverState {
     /* I/O stats (display with "info blockstats"). */
     uint64_t nr_bytes[BDRV_MAX_IOTYPE];
     uint64_t nr_ops[BDRV_MAX_IOTYPE];
+    uint64_t nr_errors[BDRV_MAX_IOTYPE];
     uint64_t total_time_ns[BDRV_MAX_IOTYPE];
     uint64_t wr_highest_sector;
 
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 1c7e3a0..1b8ee10 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -744,7 +744,7 @@ static void ncq_cb(void *opaque, int ret)
     DPRINTF(ncq_tfs->drive->port_no, "NCQ transfer tag %d finished\n",
             ncq_tfs->tag);
 
-    bdrv_acct_done(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct);
+    bdrv_acct_done(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct, ret);
     qemu_sglist_destroy(&ncq_tfs->sglist);
     ncq_tfs->used = 0;
 }
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index 3f909c3..1305515 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -112,12 +112,12 @@ static int cd_read_sector(IDEState *s, int lba, uint8_t *buf, int sector_size)
     case 2048:
         bdrv_acct_start(s->bs, &s->acct, 4 * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
         ret = bdrv_read(s->bs, (int64_t)lba << 2, buf, 4);
-        bdrv_acct_done(s->bs, &s->acct);
+        bdrv_acct_done(s->bs, &s->acct, ret);
         break;
     case 2352:
         bdrv_acct_start(s->bs, &s->acct, 4 * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
         ret = bdrv_read(s->bs, (int64_t)lba << 2, buf + 16, 4);
-        bdrv_acct_done(s->bs, &s->acct);
+        bdrv_acct_done(s->bs, &s->acct, ret);
         if (ret < 0)
             return ret;
         cd_data_to_raw(buf, lba);
@@ -361,7 +361,7 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
 
     return;
 eot:
-    bdrv_acct_done(s->bs, &s->acct);
+    bdrv_acct_done(s->bs, &s->acct, ret);
     s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
     ide_set_inactive(s);
 }
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 9ec1310..98922e4 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -477,7 +477,7 @@ void ide_sector_read(IDEState *s)
 
         bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
         ret = bdrv_read(s->bs, sector_num, s->io_buffer, n);
-        bdrv_acct_done(s->bs, &s->acct);
+        bdrv_acct_done(s->bs, &s->acct, ret);
         if (ret != 0) {
             if (ide_handle_rw_error(s, -ret,
                 BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ))
@@ -557,6 +557,10 @@ handle_rw_error:
         else if (s->dma_cmd == IDE_DMA_TRIM)
             op |= BM_STATUS_RETRY_TRIM;
 
+        if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
+            bdrv_acct_done(s->bs, &s->acct, ret);
+        }
+
         if (ide_handle_rw_error(s, -ret, op)) {
             return;
         }
@@ -616,7 +620,7 @@ handle_rw_error:
 
 eot:
     if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
-        bdrv_acct_done(s->bs, &s->acct);
+        bdrv_acct_done(s->bs, &s->acct, ret);
     }
     ide_set_inactive(s);
 }
@@ -666,7 +670,7 @@ void ide_sector_write(IDEState *s)
 
     bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
     ret = bdrv_write(s->bs, sector_num, s->io_buffer, n);
-    bdrv_acct_done(s->bs, &s->acct);
+    bdrv_acct_done(s->bs, &s->acct, ret);
 
     if (ret != 0) {
         if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY))
@@ -703,6 +707,7 @@ static void ide_flush_cb(void *opaque, int ret)
 {
     IDEState *s = opaque;
 
+    bdrv_acct_done(s->bs, &s->acct, ret);
     if (ret < 0) {
         /* XXX: What sector number to set here? */
         if (ide_handle_rw_error(s, -ret, BM_STATUS_RETRY_FLUSH)) {
@@ -710,7 +715,6 @@ static void ide_flush_cb(void *opaque, int ret)
         }
     }
 
-    bdrv_acct_done(s->bs, &s->acct);
     s->status = READY_STAT | SEEK_STAT;
     ide_set_irq(s->bus);
 }
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index 37b8239..11602d3 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -94,7 +94,7 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
     return;
 
 done:
-    bdrv_acct_done(s->bs, &s->acct);
+    bdrv_acct_done(s->bs, &s->acct, ret);
     io->dma_end(opaque);
     return;
 }
@@ -165,7 +165,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
     return;
 done:
     if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
-        bdrv_acct_done(s->bs, &s->acct);
+        bdrv_acct_done(s->bs, &s->acct, ret);
     }
     io->dma_end(io);
 }
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index a980a53..4545d93 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -132,7 +132,7 @@ static void scsi_read_complete(void * opaque, int ret)
 
     if (r->req.aiocb != NULL) {
         r->req.aiocb = NULL;
-        bdrv_acct_done(s->bs, &r->acct);
+        bdrv_acct_done(s->bs, &r->acct, ret);
     }
 
     if (ret) {
@@ -156,7 +156,7 @@ static void scsi_flush_complete(void * opaque, int ret)
 
     if (r->req.aiocb != NULL) {
         r->req.aiocb = NULL;
-        bdrv_acct_done(s->bs, &r->acct);
+        bdrv_acct_done(s->bs, &r->acct, ret);
     }
 
     if (ret < 0) {
@@ -254,7 +254,7 @@ static void scsi_write_complete(void * opaque, int ret)
 
     if (r->req.aiocb != NULL) {
         r->req.aiocb = NULL;
-        bdrv_acct_done(s->bs, &r->acct);
+        bdrv_acct_done(s->bs, &r->acct, ret);
     }
 
     if (ret) {
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index bd63a85..ca7dfa1 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -81,7 +81,6 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
         bdrv_iostatus_set_err(s->bs, error);
     } else {
         virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
-        bdrv_acct_done(s->bs, &req->acct);
         g_free(req);
         bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read);
     }
@@ -94,6 +93,7 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
     VirtIOBlockReq *req = opaque;
 
     trace_virtio_blk_rw_complete(req, ret);
+    bdrv_acct_done(req->dev->bs, &req->acct, ret);
 
     if (ret) {
         int is_read = !(ldl_p(&req->out->type) & VIRTIO_BLK_T_OUT);
@@ -102,7 +102,6 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
     }
 
     virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
-    bdrv_acct_done(req->dev->bs, &req->acct);
     g_free(req);
 }
 
@@ -110,6 +109,8 @@ static void virtio_blk_flush_complete(void *opaque, int ret)
 {
     VirtIOBlockReq *req = opaque;
 
+    bdrv_acct_done(req->dev->bs, &req->acct, ret);
+
     if (ret) {
         if (virtio_blk_handle_rw_error(req, -ret, 0)) {
             return;
@@ -117,7 +118,6 @@ static void virtio_blk_flush_complete(void *opaque, int ret)
     }
 
     virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
-    bdrv_acct_done(req->dev->bs, &req->acct);
     g_free(req);
 }
 
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 8a9fac4..d654694 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -402,7 +402,7 @@ static void qemu_aio_complete(void *opaque, int ret)
     ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
     ioreq_unmap(ioreq);
     ioreq_finish(ioreq);
-    bdrv_acct_done(ioreq->blkdev->bs, &ioreq->acct);
+    bdrv_acct_done(ioreq->blkdev->bs, &ioreq->acct, ret);
     qemu_bh_schedule(ioreq->blkdev->bh);
 }
 
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 34cc353..3d298a0 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1215,6 +1215,9 @@ Each json-object contain the following:
     - "flush_total_time_ns": total time spend on cache flushes in nano-seconds (json-int)
     - "wr_highest_offset": Highest offset of a sector written since the
                            BlockDriverState has been opened (json-int)
+    - "rd_errors": read errors (json-int)
+    - "wr_errors": write errors (json-int)
+    - "flush_errors": flush errors (json-int)
 - "parent": Contains recursively the statistics of the underlying
             protocol (e.g. the host file for a qcow2 image). If there is
             no underlying protocol, this field is omitted
@@ -1232,6 +1235,9 @@ Example:
                   "wr_highest_offset":3686448128,
                   "wr_bytes":9786368,
                   "wr_operations":751,
+		  "wr_errors":0,
+		  "rd_errors":0,
+		  "flush_errors":0,
                   "rd_bytes":122567168,
                   "rd_operations":36772
                   "wr_total_times_ns":313253456
@@ -1250,6 +1256,9 @@ Example:
                "wr_total_times_ns":313253456
                "rd_total_times_ns":3465673657
                "flush_total_times_ns":49653
+	       "wr_errors":0,
+	       "rd_errors":0,
+	       "flush_errors":0,
             }
          },
          {
@@ -1258,12 +1267,18 @@ Example:
                "wr_highest_offset":0,
                "wr_bytes":0,
                "wr_operations":0,
+	       "wr_errors":0,
+	       "rd_errors":0,
+               "flush_errors":0,
                "rd_bytes":0,
                "rd_operations":0
                "flush_operations":0,
                "wr_total_times_ns":0
                "rd_total_times_ns":0
                "flush_total_times_ns":0
+	       "wr_errors":0,
+	       "rd_errors":0,
+	       "flush_errors":0,
             }
          },
          {
@@ -1278,6 +1293,9 @@ Example:
                "wr_total_times_ns":0
                "rd_total_times_ns":0
                "flush_total_times_ns":0
+	       "wr_errors":0,
+	       "rd_errors":0,
+	       "flush_errors":0,
             }
          },
          {
@@ -1292,6 +1310,9 @@ Example:
                "wr_total_times_ns":0
                "rd_total_times_ns":0
                "flush_total_times_ns":0
+               "wr_errors":0,
+	       "rd_errors":0,
+	       "flush_errors":0,
             }
          }
       ]
