+ char buf1[128], date_buf[128], clock_buf[128];
+#ifdef _WIN32
+ struct tm *ptm;
+#else
+ struct tm tm;
+#endif
+ time_t ti;
+ int64_t secs;
+
+ if (!sn) {
+ snprintf(buf, buf_size,
+ "%-10s%-20s%7s%20s%15s",
+ "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK");
+ } else {
+ ti = sn->date_sec;
+#ifdef _WIN32
+ ptm = localtime(&ti);
+ strftime(date_buf, sizeof(date_buf),
+ "%Y-%m-%d %H:%M:%S", ptm);
+#else
+ localtime_r(&ti, &tm);
+ strftime(date_buf, sizeof(date_buf),
+ "%Y-%m-%d %H:%M:%S", &tm);
+#endif
+ secs = sn->vm_clock_nsec / 1000000000;
+ snprintf(clock_buf, sizeof(clock_buf),
+ "%02d:%02d:%02d.%03d",
+ (int)(secs / 3600),
+ (int)((secs / 60) % 60),
+ (int)(secs % 60),
+ (int)((sn->vm_clock_nsec / 1000000) % 1000));
+ snprintf(buf, buf_size,
+ "%-10s%-20s%7s%20s%15s",
+ sn->id_str, sn->name,
+ get_human_readable_size(buf1, sizeof(buf1), sn->vm_state_size),
+ date_buf,
+ clock_buf);
+ }
+ return buf;
+}
+
+
+/**************************************************************/
+/* async I/Os */
+
+typedef struct VectorTranslationAIOCB {
+ BlockDriverAIOCB common;
+ QEMUIOVector *iov;
+ uint8_t *bounce;
+ int is_write;
+ BlockDriverAIOCB *aiocb;
+} VectorTranslationAIOCB;
+
+static void bdrv_aio_cancel_vector(BlockDriverAIOCB *_acb)
+{
+ VectorTranslationAIOCB *acb
+ = container_of(_acb, VectorTranslationAIOCB, common);
+
+ bdrv_aio_cancel(acb->aiocb);
+}
+
+static void bdrv_aio_rw_vector_cb(void *opaque, int ret)
+{
+ VectorTranslationAIOCB *s = (VectorTranslationAIOCB *)opaque;
+
+ if (!s->is_write) {
+ qemu_iovec_from_buffer(s->iov, s->bounce, s->iov->size);
+ }
+ qemu_vfree(s->bounce);
+ s->common.cb(s->common.opaque, ret);
+ qemu_aio_release(s);
+}
+
+static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
+ int64_t sector_num,
+ QEMUIOVector *iov,
+ int nb_sectors,
+ BlockDriverCompletionFunc *cb,
+ void *opaque,
+ int is_write)
+
+{
+ VectorTranslationAIOCB *s = qemu_aio_get_pool(&vectored_aio_pool, bs,
+ cb, opaque);
+
+ s->iov = iov;
+ s->bounce = qemu_memalign(512, nb_sectors * 512);
+ s->is_write = is_write;
+ if (is_write) {
+ qemu_iovec_to_buffer(s->iov, s->bounce);
+ s->aiocb = bdrv_aio_write(bs, sector_num, s->bounce, nb_sectors,
+ bdrv_aio_rw_vector_cb, s);
+ } else {
+ s->aiocb = bdrv_aio_read(bs, sector_num, s->bounce, nb_sectors,
+ bdrv_aio_rw_vector_cb, s);
+ }
+ if (!s->aiocb) {
+ qemu_vfree(s->bounce);
+ qemu_aio_release(s);
+ return NULL;
+ }
+ return &s->common;
+}
+
+BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
+ QEMUIOVector *iov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ if (bdrv_check_request(bs, sector_num, nb_sectors))
+ return NULL;
+
+ return bdrv_aio_rw_vector(bs, sector_num, iov, nb_sectors,
+ cb, opaque, 0);
+}
+
+BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
+ QEMUIOVector *iov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ if (bdrv_check_request(bs, sector_num, nb_sectors))
+ return NULL;
+
+ return bdrv_aio_rw_vector(bs, sector_num, iov, nb_sectors,
+ cb, opaque, 1);
+}
+
+BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
+ uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BlockDriver *drv = bs->drv;
+ BlockDriverAIOCB *ret;
+
+ if (!drv)
+ return NULL;
+ if (bdrv_check_request(bs, sector_num, nb_sectors))
+ return NULL;
+
+ ret = drv->bdrv_aio_read(bs, sector_num, buf, nb_sectors, cb, opaque);
+
+ if (ret) {
+ /* Update stats even though technically transfer has not happened. */
+ bs->rd_bytes += (unsigned) nb_sectors * SECTOR_SIZE;
+ bs->rd_ops ++;
+ }
+
+ return ret;
+}
+
+BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,
+ const uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BlockDriver *drv = bs->drv;
+ BlockDriverAIOCB *ret;
+
+ if (!drv)
+ return NULL;
+ if (bs->read_only)
+ return NULL;
+ if (bdrv_check_request(bs, sector_num, nb_sectors))
+ return NULL;
+
+ ret = drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque);
+
+ if (ret) {
+ /* Update stats even though technically transfer has not happened. */
+ bs->wr_bytes += (unsigned) nb_sectors * SECTOR_SIZE;
+ bs->wr_ops ++;
+ }
+
+ return ret;
+}
+
+void bdrv_aio_cancel(BlockDriverAIOCB *acb)
+{
+ acb->pool->cancel(acb);
+}
+
+
+/**************************************************************/
+/* async block device emulation */
+
+static void bdrv_aio_bh_cb(void *opaque)
+{
+ BlockDriverAIOCBSync *acb = opaque;
+ acb->common.cb(acb->common.opaque, acb->ret);
+ qemu_aio_release(acb);
+}
+
+static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs,
+ int64_t sector_num, uint8_t *buf, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BlockDriverAIOCBSync *acb;