303 lines
10 KiB
Diff
303 lines
10 KiB
Diff
# HG changeset patch
|
|
# User Keir Fraser <keir.fraser@citrix.com>
|
|
# Date 1206697850 0
|
|
# Node ID 50efc4b3ffdb7996ab58a4cb6d4d48fed197454f
|
|
# Parent 7a3702ff0e8c2c9783de6e24edd79203d5e4c070
|
|
ioemu: Perform emulated IDE flushes asynchronously.
|
|
|
|
Fixes 'Windows Bug Check 0x101 issue' in which a VCPU gets tied up for
|
|
so long doing a synchronous flush to disc that it misses critical
|
|
timer events.
|
|
|
|
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
|
|
Modified-by: Ian Jackson <ian.jackson@eu.citrix.com>
|
|
Signed-off-by: Kouya Shimura <kouya@jp.fujitsu.com>
|
|
|
|
Index: xen-3.2.1-testing/tools/ioemu/block-qcow.c
|
|
===================================================================
|
|
--- xen-3.2.1-testing.orig/tools/ioemu/block-qcow.c
|
|
+++ xen-3.2.1-testing/tools/ioemu/block-qcow.c
|
|
@@ -725,6 +725,13 @@ static void qcow_aio_cancel(BlockDriverA
|
|
qemu_aio_release(acb);
|
|
}
|
|
|
|
+static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,
|
|
+ BlockDriverCompletionFunc *cb, void *opaque)
|
|
+{
|
|
+ BDRVQcowState *s = bs->opaque;
|
|
+ return bdrv_aio_flush(s->hd, cb, opaque);
|
|
+}
|
|
+
|
|
static void qcow_close(BlockDriverState *bs)
|
|
{
|
|
BDRVQcowState *s = bs->opaque;
|
|
@@ -899,6 +906,7 @@ BlockDriver bdrv_qcow = {
|
|
.bdrv_aio_read = qcow_aio_read,
|
|
.bdrv_aio_write = qcow_aio_write,
|
|
.bdrv_aio_cancel = qcow_aio_cancel,
|
|
+ .bdrv_aio_flush = qcow_aio_flush,
|
|
.aiocb_size = sizeof(QCowAIOCB),
|
|
.bdrv_write_compressed = qcow_write_compressed,
|
|
.bdrv_get_info = qcow_get_info,
|
|
Index: xen-3.2.1-testing/tools/ioemu/block-qcow2.c
|
|
===================================================================
|
|
--- xen-3.2.1-testing.orig/tools/ioemu/block-qcow2.c
|
|
+++ xen-3.2.1-testing/tools/ioemu/block-qcow2.c
|
|
@@ -1007,6 +1007,13 @@ static void qcow_aio_cancel(BlockDriverA
|
|
qemu_aio_release(acb);
|
|
}
|
|
|
|
+static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,
|
|
+ BlockDriverCompletionFunc *cb, void *opaque)
|
|
+{
|
|
+ BDRVQcowState *s = bs->opaque;
|
|
+ return bdrv_aio_flush(s->hd, cb, opaque);
|
|
+}
|
|
+
|
|
static void qcow_close(BlockDriverState *bs)
|
|
{
|
|
BDRVQcowState *s = bs->opaque;
|
|
@@ -2241,6 +2248,7 @@ BlockDriver bdrv_qcow2 = {
|
|
.bdrv_aio_read = qcow_aio_read,
|
|
.bdrv_aio_write = qcow_aio_write,
|
|
.bdrv_aio_cancel = qcow_aio_cancel,
|
|
+ .bdrv_aio_flush = qcow_aio_flush,
|
|
.aiocb_size = sizeof(QCowAIOCB),
|
|
.bdrv_write_compressed = qcow_write_compressed,
|
|
|
|
Index: xen-3.2.1-testing/tools/ioemu/block-raw.c
|
|
===================================================================
|
|
--- xen-3.2.1-testing.orig/tools/ioemu/block-raw.c
|
|
+++ xen-3.2.1-testing/tools/ioemu/block-raw.c
|
|
@@ -496,6 +496,21 @@ static void raw_aio_cancel(BlockDriverAI
|
|
pacb = &acb->next;
|
|
}
|
|
}
|
|
+
|
|
+static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
|
|
+ BlockDriverCompletionFunc *cb, void *opaque)
|
|
+{
|
|
+ RawAIOCB *acb;
|
|
+
|
|
+ acb = raw_aio_setup(bs, 0, NULL, 0, cb, opaque);
|
|
+ if (!acb)
|
|
+ return NULL;
|
|
+ if (aio_fsync(O_SYNC, &acb->aiocb) < 0) {
|
|
+ qemu_aio_release(acb);
|
|
+ return NULL;
|
|
+ }
|
|
+ return &acb->common;
|
|
+}
|
|
#endif
|
|
|
|
static void raw_close(BlockDriverState *bs)
|
|
@@ -621,6 +636,7 @@ BlockDriver bdrv_raw = {
|
|
.bdrv_aio_read = raw_aio_read,
|
|
.bdrv_aio_write = raw_aio_write,
|
|
.bdrv_aio_cancel = raw_aio_cancel,
|
|
+ .bdrv_aio_flush = raw_aio_flush,
|
|
.aiocb_size = sizeof(RawAIOCB),
|
|
#endif
|
|
.protocol_name = "file",
|
|
@@ -959,6 +975,7 @@ BlockDriver bdrv_host_device = {
|
|
.bdrv_aio_read = raw_aio_read,
|
|
.bdrv_aio_write = raw_aio_write,
|
|
.bdrv_aio_cancel = raw_aio_cancel,
|
|
+ .bdrv_aio_flush = raw_aio_flush,
|
|
.aiocb_size = sizeof(RawAIOCB),
|
|
#endif
|
|
.bdrv_pread = raw_pread,
|
|
Index: xen-3.2.1-testing/tools/ioemu/block.c
|
|
===================================================================
|
|
--- xen-3.2.1-testing.orig/tools/ioemu/block.c
|
|
+++ xen-3.2.1-testing/tools/ioemu/block.c
|
|
@@ -48,6 +48,8 @@ static BlockDriverAIOCB *bdrv_aio_write_
|
|
int64_t sector_num, const uint8_t *buf, int nb_sectors,
|
|
BlockDriverCompletionFunc *cb, void *opaque);
|
|
static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb);
|
|
+static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
|
|
+ BlockDriverCompletionFunc *cb, void *opaque);
|
|
static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
|
|
uint8_t *buf, int nb_sectors);
|
|
static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
|
|
@@ -155,6 +157,8 @@ void bdrv_register(BlockDriver *bdrv)
|
|
bdrv->bdrv_read = bdrv_read_em;
|
|
bdrv->bdrv_write = bdrv_write_em;
|
|
}
|
|
+ if (!bdrv->bdrv_aio_flush)
|
|
+ bdrv->bdrv_aio_flush = bdrv_aio_flush_em;
|
|
bdrv->next = first_drv;
|
|
first_drv = bdrv;
|
|
}
|
|
@@ -1138,6 +1142,17 @@ void bdrv_aio_cancel(BlockDriverAIOCB *a
|
|
drv->bdrv_aio_cancel(acb);
|
|
}
|
|
|
|
+BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
|
|
+ BlockDriverCompletionFunc *cb, void *opaque)
|
|
+{
|
|
+ BlockDriver *drv = bs->drv;
|
|
+
|
|
+ if (!drv)
|
|
+ return NULL;
|
|
+
|
|
+ return drv->bdrv_aio_flush(bs, cb, opaque);
|
|
+}
|
|
+
|
|
|
|
/**************************************************************/
|
|
/* async block device emulation */
|
|
@@ -1214,6 +1229,14 @@ static void bdrv_aio_cancel_em(BlockDriv
|
|
}
|
|
#endif /* !QEMU_TOOL */
|
|
|
|
+static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
|
|
+ BlockDriverCompletionFunc *cb, void *opaque)
|
|
+{
|
|
+ bdrv_flush(bs);
|
|
+ cb(opaque, 0);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
/**************************************************************/
|
|
/* sync block device emulation */
|
|
|
|
Index: xen-3.2.1-testing/tools/ioemu/block_int.h
|
|
===================================================================
|
|
--- xen-3.2.1-testing.orig/tools/ioemu/block_int.h
|
|
+++ xen-3.2.1-testing/tools/ioemu/block_int.h
|
|
@@ -49,6 +49,8 @@ struct BlockDriver {
|
|
int64_t sector_num, const uint8_t *buf, int nb_sectors,
|
|
BlockDriverCompletionFunc *cb, void *opaque);
|
|
void (*bdrv_aio_cancel)(BlockDriverAIOCB *acb);
|
|
+ BlockDriverAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs,
|
|
+ BlockDriverCompletionFunc *cb, void *opaque);
|
|
int aiocb_size;
|
|
|
|
const char *protocol_name;
|
|
Index: xen-3.2.1-testing/tools/ioemu/hw/ide.c
|
|
===================================================================
|
|
--- xen-3.2.1-testing.orig/tools/ioemu/hw/ide.c
|
|
+++ xen-3.2.1-testing/tools/ioemu/hw/ide.c
|
|
@@ -742,6 +742,7 @@ static inline void ide_abort_command(IDE
|
|
static inline void ide_set_irq(IDEState *s)
|
|
{
|
|
BMDMAState *bm = s->bmdma;
|
|
+ if (!s->bs) return; /* yikes */
|
|
if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) {
|
|
if (bm) {
|
|
bm->status |= BM_STATUS_INT;
|
|
@@ -907,6 +908,8 @@ static void ide_read_dma_cb(void *opaque
|
|
int n;
|
|
int64_t sector_num;
|
|
|
|
+ if (!s->bs) return; /* yikes */
|
|
+
|
|
n = s->io_buffer_size >> 9;
|
|
sector_num = ide_get_sector(s);
|
|
if (n > 0) {
|
|
@@ -1015,6 +1018,8 @@ static void ide_write_dma_cb(void *opaqu
|
|
int n;
|
|
int64_t sector_num;
|
|
|
|
+ if (!s->bs) return; /* yikes */
|
|
+
|
|
n = s->io_buffer_size >> 9;
|
|
sector_num = ide_get_sector(s);
|
|
if (n > 0) {
|
|
@@ -1063,6 +1068,39 @@ static void ide_sector_write_dma(IDEStat
|
|
ide_dma_start(s, ide_write_dma_cb);
|
|
}
|
|
|
|
+static void ide_device_utterly_broken(IDEState *s) {
|
|
+ s->status |= BUSY_STAT;
|
|
+ s->bs = NULL;
|
|
+ /* This prevents all future commands from working. All of the
|
|
+ * asynchronous callbacks (and ide_set_irq, as a safety measure)
|
|
+ * check to see whether this has happened and bail if so.
|
|
+ */
|
|
+}
|
|
+
|
|
+static void ide_flush_cb(void *opaque, int ret)
|
|
+{
|
|
+ IDEState *s = opaque;
|
|
+
|
|
+ if (!s->bs) return; /* yikes */
|
|
+
|
|
+ if (ret) {
|
|
+ /* We are completely doomed. The IDE spec does not permit us
|
|
+ * to return an error from a flush except via a protocol which
|
|
+ * requires us to say where the error is and which
|
|
+ * contemplates the guest repeating the flush attempt to
|
|
+ * attempt flush the remaining data. We can't support that
|
|
+ * because f(data)sync (which is what the block drivers use
|
|
+ * eventually) doesn't report the necessary information or
|
|
+ * give us the necessary control. So we make the disk vanish.
|
|
+ */
|
|
+ ide_device_utterly_broken(s);
|
|
+ return;
|
|
+ }
|
|
+ else
|
|
+ s->status = READY_STAT;
|
|
+ ide_set_irq(s);
|
|
+}
|
|
+
|
|
static void ide_atapi_cmd_ok(IDEState *s)
|
|
{
|
|
s->error = 0;
|
|
@@ -1289,6 +1327,8 @@ static void ide_atapi_cmd_read_dma_cb(vo
|
|
IDEState *s = bm->ide_if;
|
|
int data_offset, n;
|
|
|
|
+ if (!s->bs) return; /* yikes */
|
|
+
|
|
if (ret < 0) {
|
|
ide_atapi_io_error(s, ret);
|
|
goto eot;
|
|
@@ -1694,6 +1734,8 @@ static void cdrom_change_cb(void *opaque
|
|
IDEState *s = opaque;
|
|
int64_t nb_sectors;
|
|
|
|
+ if (!s->bs) return; /* yikes */
|
|
+
|
|
/* XXX: send interrupt too */
|
|
bdrv_get_geometry(s->bs, &nb_sectors);
|
|
s->nb_sectors = nb_sectors;
|
|
@@ -1797,8 +1839,8 @@ static void ide_ioport_write(void *opaqu
|
|
printf("ide: CMD=%02x\n", val);
|
|
#endif
|
|
s = ide_if->cur_drive;
|
|
- /* ignore commands to non existant slave */
|
|
- if (s != ide_if && !s->bs)
|
|
+ /* ignore commands to non existant device */
|
|
+ if (!s->bs)
|
|
break;
|
|
|
|
switch(val) {
|
|
@@ -1967,10 +2009,8 @@ static void ide_ioport_write(void *opaqu
|
|
break;
|
|
case WIN_FLUSH_CACHE:
|
|
case WIN_FLUSH_CACHE_EXT:
|
|
- if (s->bs)
|
|
- bdrv_flush(s->bs);
|
|
- s->status = READY_STAT;
|
|
- ide_set_irq(s);
|
|
+ s->status = BUSY_STAT;
|
|
+ bdrv_aio_flush(s->bs, ide_flush_cb, s);
|
|
break;
|
|
case WIN_IDLEIMMEDIATE:
|
|
case WIN_STANDBY:
|
|
Index: xen-3.2.1-testing/tools/ioemu/vl.h
|
|
===================================================================
|
|
--- xen-3.2.1-testing.orig/tools/ioemu/vl.h
|
|
+++ xen-3.2.1-testing/tools/ioemu/vl.h
|
|
@@ -650,6 +650,8 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDr
|
|
const uint8_t *buf, int nb_sectors,
|
|
BlockDriverCompletionFunc *cb, void *opaque);
|
|
void bdrv_aio_cancel(BlockDriverAIOCB *acb);
|
|
+BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
|
|
+ BlockDriverCompletionFunc *cb, void *opaque);
|
|
|
|
void qemu_aio_init(void);
|
|
void qemu_aio_poll(void);
|