Commit bef0fd59 authored by Stefan Hajnoczi's avatar Stefan Hajnoczi Committed by Kevin Wolf
Browse files

ide: convert ide_sector_read() to asynchronous I/O



The IDE PIO interface currently uses bdrv_read() to perform reads
synchronously.  Synchronous I/O in the vcpu thread is bad because it
prevents the guest from executing code - it makes the guest
unresponsive.

This patch converts IDE PIO to use bdrv_aio_readv().  We simply need to
use the BUSY_STAT status so the guest knows to wait while we are busy.

The only external user of ide_sector_read() is restart behavior on I/O
errors and it is not affected by this change.  We still need to restart
I/O in the same way.

Migration is also unaffected if I understand the code correctly.  We
continue to use the same transfer function and the BUSY_STAT status
should never be migrated since we flush I/O before migrating device
state.

Signed-off-by: default avatarStefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Reviewed-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Reviewed-by: default avatarZhi Yong Wu <wuzhy@linux.vnet.ibm.com>
Tested-by: default avatarRichard Davies <richard@arachsys.com>
Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
parent 592fa070
Loading
Loading
Loading
Loading
+55 −21
Original line number Diff line number Diff line
@@ -471,40 +471,68 @@ static void ide_rw_error(IDEState *s) {
    ide_set_irq(s->bus);
}

static void ide_sector_read_cb(void *opaque, int ret)
{
    IDEState *s = opaque;
    int n;

    s->pio_aiocb = NULL;
    s->status &= ~BUSY_STAT;

    bdrv_acct_done(s->bs, &s->acct);
    if (ret != 0) {
        if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY |
                                BM_STATUS_RETRY_READ)) {
            return;
        }
    }

    n = s->nsector;
    if (n > s->req_nb_sectors) {
        n = s->req_nb_sectors;
    }

    /* Allow the guest to read the io_buffer */
    ide_transfer_start(s, s->io_buffer, n * BDRV_SECTOR_SIZE, ide_sector_read);

    ide_set_irq(s->bus);

    ide_set_sector(s, ide_get_sector(s) + n);
    s->nsector -= n;
}

void ide_sector_read(IDEState *s)
{
    int64_t sector_num;
    int ret, n;
    int n;

    s->status = READY_STAT | SEEK_STAT;
    s->error = 0; /* not needed by IDE spec, but needed by Windows */
    sector_num = ide_get_sector(s);
    n = s->nsector;

    if (n == 0) {
        /* no more sector to read from disk */
        ide_transfer_stop(s);
    } else {
        return;
    }

    s->status |= BUSY_STAT;

    if (n > s->req_nb_sectors) {
        n = s->req_nb_sectors;
    }

#if defined(DEBUG_IDE)
        printf("read sector=%" PRId64 "\n", sector_num);
    printf("sector=%" PRId64 "\n", sector_num);
#endif
        if (n > s->req_nb_sectors)
            n = s->req_nb_sectors;

    s->iov.iov_base = s->io_buffer;
    s->iov.iov_len  = n * BDRV_SECTOR_SIZE;
    qemu_iovec_init_external(&s->qiov, &s->iov, 1);

    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);
        if (ret != 0) {
            if (ide_handle_rw_error(s, -ret,
                BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ))
            {
                return;
            }
        }
        ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read);
        ide_set_irq(s->bus);
        ide_set_sector(s, sector_num + n);
        s->nsector -= n;
    }
    s->pio_aiocb = bdrv_aio_readv(s->bs, sector_num, &s->qiov, n,
                                  ide_sector_read_cb, s);
}

static void dma_buf_commit(IDEState *s)
@@ -1765,6 +1793,12 @@ static void ide_reset(IDEState *s)
#ifdef DEBUG_IDE
    printf("ide: reset\n");
#endif

    if (s->pio_aiocb) {
        bdrv_aio_cancel(s->pio_aiocb);
        s->pio_aiocb = NULL;
    }

    if (s->drive_kind == IDE_CFATA)
        s->mult_sectors = 0;
    else
+3 −0
Original line number Diff line number Diff line
@@ -385,6 +385,9 @@ struct IDEState {
    int cd_sector_size;
    int atapi_dma; /* true if dma is requested for the packet cmd */
    BlockAcctCookie acct;
    BlockDriverAIOCB *pio_aiocb;
    struct iovec iov;
    QEMUIOVector qiov;
    /* ATA DMA state */
    int io_buffer_size;
    QEMUSGList sg;