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;
.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,
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;
.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,
{
return 0;
}
+
+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
#if defined(__linux__)
.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),
.bdrv_pread = raw_pread,
.bdrv_pwrite = raw_pwrite,
static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs,
int64_t sector_num, const uint8_t *buf, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
+static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque);
static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb);
static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
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;
}
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 */
return NULL;
}
+static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ int ret;
+ ret = bdrv_flush(bs);
+ cb(opaque, ret);
+ return NULL;
+}
+
static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb)
{
}
return &acb->common;
}
+static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BlockDriverAIOCBSync *acb;
+ int ret;
+
+ acb = qemu_aio_get(bs, cb, opaque);
+ if (!acb->bh)
+ acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
+ ret = bdrv_flush(bs);
+ acb->ret = ret;
+ qemu_bh_schedule(acb->bh);
+ return &acb->common;
+}
+
static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb)
{
BlockDriverAIOCBSync *acb = (BlockDriverAIOCBSync *)blockacb;
BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
+BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque);
void bdrv_aio_cancel(BlockDriverAIOCB *acb);
void qemu_aio_init(void);
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;
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;
return;
}
+ if (!s->bs) return; /* yikes */
+
n = s->io_buffer_size >> 9;
sector_num = ide_get_sector(s);
if (n > 0) {
return;
}
+ if (!s->bs) return; /* yikes */
+
n = s->io_buffer_size >> 9;
sector_num = ide_get_sector(s);
if (n > 0) {
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;
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;
IDEState *s = opaque;
uint64_t nb_sectors;
+ if (!s->bs) return; /* yikes */
+
/* XXX: send interrupt too */
bdrv_get_geometry(s->bs, &nb_sectors);
s->nb_sectors = nb_sectors;
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) {
break;
case WIN_FLUSH_CACHE:
case WIN_FLUSH_CACHE_EXT:
- if (s->bs) {
- ret = bdrv_flush(s->bs);
- if (ret) goto abort_cmd;
- }
- s->status = READY_STAT;
- ide_set_irq(s);
+ s->status = BUSY_STAT;
+ bdrv_aio_flush(s->bs, ide_flush_cb, s);
break;
case WIN_STANDBY:
case WIN_STANDBY2: