ia64/xen-unstable

changeset 17345:50efc4b3ffdb

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>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Mar 28 09:50:50 2008 +0000 (2008-03-28)
parents 7a3702ff0e8c
children abae878a65f4
files tools/ioemu/block-qcow.c tools/ioemu/block-qcow2.c tools/ioemu/block-raw.c tools/ioemu/block.c tools/ioemu/block_int.h tools/ioemu/hw/ide.c tools/ioemu/vl.h
line diff
     1.1 --- a/tools/ioemu/block-qcow.c	Fri Mar 28 07:34:47 2008 +0000
     1.2 +++ b/tools/ioemu/block-qcow.c	Fri Mar 28 09:50:50 2008 +0000
     1.3 @@ -783,6 +783,13 @@ static void qcow_aio_cancel(BlockDriverA
     1.4      qemu_aio_release(acb);
     1.5  }
     1.6  
     1.7 +static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,
     1.8 +        BlockDriverCompletionFunc *cb, void *opaque)
     1.9 +{
    1.10 +    BDRVQcowState *s = bs->opaque;
    1.11 +    return bdrv_aio_flush(s->hd, cb, opaque);
    1.12 +}
    1.13 +
    1.14  static void qcow_close(BlockDriverState *bs)
    1.15  {
    1.16      BDRVQcowState *s = bs->opaque;
    1.17 @@ -957,6 +964,7 @@ BlockDriver bdrv_qcow = {
    1.18      .bdrv_aio_read = qcow_aio_read,
    1.19      .bdrv_aio_write = qcow_aio_write,
    1.20      .bdrv_aio_cancel = qcow_aio_cancel,
    1.21 +    .bdrv_aio_flush = qcow_aio_flush,
    1.22      .aiocb_size = sizeof(QCowAIOCB),
    1.23      .bdrv_write_compressed = qcow_write_compressed,
    1.24      .bdrv_get_info = qcow_get_info,
     2.1 --- a/tools/ioemu/block-qcow2.c	Fri Mar 28 07:34:47 2008 +0000
     2.2 +++ b/tools/ioemu/block-qcow2.c	Fri Mar 28 09:50:50 2008 +0000
     2.3 @@ -1007,6 +1007,13 @@ static void qcow_aio_cancel(BlockDriverA
     2.4      qemu_aio_release(acb);
     2.5  }
     2.6  
     2.7 +static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs,
     2.8 +        BlockDriverCompletionFunc *cb, void *opaque)
     2.9 +{
    2.10 +    BDRVQcowState *s = bs->opaque;
    2.11 +    return bdrv_aio_flush(s->hd, cb, opaque);
    2.12 +}
    2.13 +
    2.14  static void qcow_close(BlockDriverState *bs)
    2.15  {
    2.16      BDRVQcowState *s = bs->opaque;
    2.17 @@ -2241,6 +2248,7 @@ BlockDriver bdrv_qcow2 = {
    2.18      .bdrv_aio_read = qcow_aio_read,
    2.19      .bdrv_aio_write = qcow_aio_write,
    2.20      .bdrv_aio_cancel = qcow_aio_cancel,
    2.21 +    .bdrv_aio_flush = qcow_aio_flush,
    2.22      .aiocb_size = sizeof(QCowAIOCB),
    2.23      .bdrv_write_compressed = qcow_write_compressed,
    2.24  
     3.1 --- a/tools/ioemu/block-raw.c	Fri Mar 28 07:34:47 2008 +0000
     3.2 +++ b/tools/ioemu/block-raw.c	Fri Mar 28 09:50:50 2008 +0000
     3.3 @@ -496,6 +496,21 @@ static void raw_aio_cancel(BlockDriverAI
     3.4          pacb = &acb->next;
     3.5      }
     3.6  }
     3.7 +
     3.8 +static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
     3.9 +        BlockDriverCompletionFunc *cb, void *opaque)
    3.10 +{
    3.11 +    RawAIOCB *acb;
    3.12 +
    3.13 +    acb = raw_aio_setup(bs, 0, NULL, 0, cb, opaque);
    3.14 +    if (!acb)
    3.15 +        return NULL;
    3.16 +    if (aio_fsync(O_SYNC, &acb->aiocb) < 0) {
    3.17 +        qemu_aio_release(acb);
    3.18 +        return NULL;
    3.19 +    }
    3.20 +    return &acb->common;
    3.21 +}
    3.22  #endif
    3.23  
    3.24  static void raw_close(BlockDriverState *bs)
    3.25 @@ -621,6 +636,7 @@ BlockDriver bdrv_raw = {
    3.26      .bdrv_aio_read = raw_aio_read,
    3.27      .bdrv_aio_write = raw_aio_write,
    3.28      .bdrv_aio_cancel = raw_aio_cancel,
    3.29 +    .bdrv_aio_flush = raw_aio_flush,
    3.30      .aiocb_size = sizeof(RawAIOCB),
    3.31  #endif
    3.32      .protocol_name = "file",
    3.33 @@ -959,6 +975,7 @@ BlockDriver bdrv_host_device = {
    3.34      .bdrv_aio_read = raw_aio_read,
    3.35      .bdrv_aio_write = raw_aio_write,
    3.36      .bdrv_aio_cancel = raw_aio_cancel,
    3.37 +    .bdrv_aio_flush = raw_aio_flush,
    3.38      .aiocb_size = sizeof(RawAIOCB),
    3.39  #endif
    3.40      .bdrv_pread = raw_pread,
     4.1 --- a/tools/ioemu/block.c	Fri Mar 28 07:34:47 2008 +0000
     4.2 +++ b/tools/ioemu/block.c	Fri Mar 28 09:50:50 2008 +0000
     4.3 @@ -48,6 +48,8 @@ static BlockDriverAIOCB *bdrv_aio_write_
     4.4          int64_t sector_num, const uint8_t *buf, int nb_sectors,
     4.5          BlockDriverCompletionFunc *cb, void *opaque);
     4.6  static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb);
     4.7 +static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
     4.8 +        BlockDriverCompletionFunc *cb, void *opaque);
     4.9  static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, 
    4.10                          uint8_t *buf, int nb_sectors);
    4.11  static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
    4.12 @@ -155,6 +157,8 @@ void bdrv_register(BlockDriver *bdrv)
    4.13          bdrv->bdrv_read = bdrv_read_em;
    4.14          bdrv->bdrv_write = bdrv_write_em;
    4.15      }
    4.16 +    if (!bdrv->bdrv_aio_flush)
    4.17 +        bdrv->bdrv_aio_flush = bdrv_aio_flush_em;
    4.18      bdrv->next = first_drv;
    4.19      first_drv = bdrv;
    4.20  }
    4.21 @@ -1138,6 +1142,17 @@ void bdrv_aio_cancel(BlockDriverAIOCB *a
    4.22      drv->bdrv_aio_cancel(acb);
    4.23  }
    4.24  
    4.25 +BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs, 
    4.26 +                                 BlockDriverCompletionFunc *cb, void *opaque)
    4.27 +{
    4.28 +    BlockDriver *drv = bs->drv;
    4.29 +
    4.30 +    if (!drv)
    4.31 +        return NULL;
    4.32 +
    4.33 +    return drv->bdrv_aio_flush(bs, cb, opaque);
    4.34 +}
    4.35 +
    4.36  
    4.37  /**************************************************************/
    4.38  /* async block device emulation */
    4.39 @@ -1214,6 +1229,14 @@ static void bdrv_aio_cancel_em(BlockDriv
    4.40  }
    4.41  #endif /* !QEMU_TOOL */
    4.42  
    4.43 +static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
    4.44 +        BlockDriverCompletionFunc *cb, void *opaque)
    4.45 +{
    4.46 +    bdrv_flush(bs);
    4.47 +    cb(opaque, 0);
    4.48 +    return NULL;
    4.49 +}
    4.50 +
    4.51  /**************************************************************/
    4.52  /* sync block device emulation */
    4.53  
     5.1 --- a/tools/ioemu/block_int.h	Fri Mar 28 07:34:47 2008 +0000
     5.2 +++ b/tools/ioemu/block_int.h	Fri Mar 28 09:50:50 2008 +0000
     5.3 @@ -49,6 +49,8 @@ struct BlockDriver {
     5.4          int64_t sector_num, const uint8_t *buf, int nb_sectors,
     5.5          BlockDriverCompletionFunc *cb, void *opaque);
     5.6      void (*bdrv_aio_cancel)(BlockDriverAIOCB *acb);
     5.7 +    BlockDriverAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs,
     5.8 +        BlockDriverCompletionFunc *cb, void *opaque);
     5.9      int aiocb_size;
    5.10  
    5.11      const char *protocol_name;
     6.1 --- a/tools/ioemu/hw/ide.c	Fri Mar 28 07:34:47 2008 +0000
     6.2 +++ b/tools/ioemu/hw/ide.c	Fri Mar 28 09:50:50 2008 +0000
     6.3 @@ -751,6 +751,7 @@ static inline void ide_abort_command(IDE
     6.4  static inline void ide_set_irq(IDEState *s)
     6.5  {
     6.6      BMDMAState *bm = s->bmdma;
     6.7 +    if (!s->bs) return; /* yikes */
     6.8      if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) {
     6.9          if (bm) {
    6.10              bm->status |= BM_STATUS_INT;
    6.11 @@ -916,6 +917,8 @@ static void ide_read_dma_cb(void *opaque
    6.12      int n;
    6.13      int64_t sector_num;
    6.14  
    6.15 +    if (!s->bs) return; /* yikes */
    6.16 +
    6.17      n = s->io_buffer_size >> 9;
    6.18      sector_num = ide_get_sector(s);
    6.19      if (n > 0) {
    6.20 @@ -1024,6 +1027,8 @@ static void ide_write_dma_cb(void *opaqu
    6.21      int n;
    6.22      int64_t sector_num;
    6.23  
    6.24 +    if (!s->bs) return; /* yikes */
    6.25 +
    6.26      n = s->io_buffer_size >> 9;
    6.27      sector_num = ide_get_sector(s);
    6.28      if (n > 0) {
    6.29 @@ -1072,6 +1077,39 @@ static void ide_sector_write_dma(IDEStat
    6.30      ide_dma_start(s, ide_write_dma_cb);
    6.31  }
    6.32  
    6.33 +static void ide_device_utterly_broken(IDEState *s) {
    6.34 +    s->status |= BUSY_STAT;
    6.35 +    s->bs = NULL;
    6.36 +    /* This prevents all future commands from working.  All of the
    6.37 +     * asynchronous callbacks (and ide_set_irq, as a safety measure)
    6.38 +     * check to see whether this has happened and bail if so.
    6.39 +     */
    6.40 +}
    6.41 +
    6.42 +static void ide_flush_cb(void *opaque, int ret)
    6.43 +{
    6.44 +    IDEState *s = opaque;
    6.45 +
    6.46 +    if (!s->bs) return; /* yikes */
    6.47 +
    6.48 +    if (ret) {
    6.49 +        /* We are completely doomed.  The IDE spec does not permit us
    6.50 +	 * to return an error from a flush except via a protocol which
    6.51 +	 * requires us to say where the error is and which
    6.52 +	 * contemplates the guest repeating the flush attempt to
    6.53 +	 * attempt flush the remaining data.  We can't support that
    6.54 +	 * because f(data)sync (which is what the block drivers use
    6.55 +	 * eventually) doesn't report the necessary information or
    6.56 +	 * give us the necessary control.  So we make the disk vanish.
    6.57 +	 */
    6.58 +	ide_device_utterly_broken(s);
    6.59 +	return;
    6.60 +    }
    6.61 +    else
    6.62 +        s->status = READY_STAT;
    6.63 +    ide_set_irq(s);
    6.64 +}
    6.65 +
    6.66  static void ide_atapi_cmd_ok(IDEState *s)
    6.67  {
    6.68      s->error = 0;
    6.69 @@ -1298,6 +1336,8 @@ static void ide_atapi_cmd_read_dma_cb(vo
    6.70      IDEState *s = bm->ide_if;
    6.71      int data_offset, n;
    6.72  
    6.73 +    if (!s->bs) return; /* yikes */
    6.74 +
    6.75      if (ret < 0) {
    6.76          ide_atapi_io_error(s, ret);
    6.77          goto eot;
    6.78 @@ -1703,6 +1743,8 @@ static void cdrom_change_cb(void *opaque
    6.79      IDEState *s = opaque;
    6.80      int64_t nb_sectors;
    6.81  
    6.82 +    if (!s->bs) return; /* yikes */
    6.83 +
    6.84      /* XXX: send interrupt too */
    6.85      bdrv_get_geometry(s->bs, &nb_sectors);
    6.86      s->nb_sectors = nb_sectors;
    6.87 @@ -1806,8 +1848,8 @@ static void ide_ioport_write(void *opaqu
    6.88          printf("ide: CMD=%02x\n", val);
    6.89  #endif
    6.90          s = ide_if->cur_drive;
    6.91 -        /* ignore commands to non existant slave */
    6.92 -        if (s != ide_if && !s->bs) 
    6.93 +        /* ignore commands to non existant device */
    6.94 +        if (!s->bs) 
    6.95              break;
    6.96  
    6.97          switch(val) {
    6.98 @@ -1976,10 +2018,8 @@ static void ide_ioport_write(void *opaqu
    6.99              break;
   6.100          case WIN_FLUSH_CACHE:
   6.101          case WIN_FLUSH_CACHE_EXT:
   6.102 -            if (s->bs)
   6.103 -                bdrv_flush(s->bs);
   6.104 -	    s->status = READY_STAT;
   6.105 -            ide_set_irq(s);
   6.106 +            s->status = BUSY_STAT;
   6.107 +            bdrv_aio_flush(s->bs, ide_flush_cb, s);
   6.108              break;
   6.109          case WIN_IDLEIMMEDIATE:
   6.110          case WIN_STANDBY:
     7.1 --- a/tools/ioemu/vl.h	Fri Mar 28 07:34:47 2008 +0000
     7.2 +++ b/tools/ioemu/vl.h	Fri Mar 28 09:50:50 2008 +0000
     7.3 @@ -653,6 +653,8 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDr
     7.4                                   const uint8_t *buf, int nb_sectors,
     7.5                                   BlockDriverCompletionFunc *cb, void *opaque);
     7.6  void bdrv_aio_cancel(BlockDriverAIOCB *acb);
     7.7 +BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs, 
     7.8 +                                 BlockDriverCompletionFunc *cb, void *opaque);
     7.9  
    7.10  void qemu_aio_init(void);
    7.11  void qemu_aio_poll(void);