Beispiel #1
0
static void fvd_store_compact_cancel (FvdAIOCB * acb)
{
    if (acb->store.children) {
        int i;
        for (i = 0; i < acb->store.num_children; i++) {
            if (acb->store.children[i].hd_acb) {
                bdrv_aio_cancel (acb->store.children[i].hd_acb);
            }
        }
        my_qemu_free (acb->store.children);
    }
    if (acb->store.one_child.hd_acb) {
        bdrv_aio_cancel (acb->store.one_child.hd_acb);
    }
    if (acb->jcb.hd_acb) {
        bdrv_aio_cancel (acb->jcb.hd_acb);
        free_journal_sectors (acb->common.bs->opaque);
    }
    if (acb->jcb.iov.iov_base != NULL) {
        my_qemu_vfree (acb->jcb.iov.iov_base);
    }
    if (acb->jcb.next_wait_for_journal.le_prev) {
        QLIST_REMOVE (acb, jcb.next_wait_for_journal);
    }

    my_qemu_aio_unref (acb);
}
Beispiel #2
0
static void dma_aio_cancel(BlockDriverAIOCB *acb)
{
    DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common);

    if (dbs->acb) {
        bdrv_aio_cancel(dbs->acb);
    }
}
Beispiel #3
0
/* Cancel a pending data transfer.  */
static void scsi_cancel_io(SCSIRequest *req)
{
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);

    DPRINTF("Cancel tag=0x%x\n", req->tag);
    if (r->req.aiocb) {
        bdrv_aio_cancel(r->req.aiocb);
    }
    r->req.aiocb = NULL;
}
Beispiel #4
0
static void dma_aio_cancel(BlockDriverAIOCB *acb)
{
    DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common);

    if (dbs->acb) {
        BlockDriverAIOCB *acb = dbs->acb;
        dbs->acb = NULL;
        dbs->in_cancel = true;
        bdrv_aio_cancel(acb);
        dbs->in_cancel = false;
    }
    dbs->common.cb = NULL;
    dma_complete(dbs, 0);
}
Beispiel #5
0
/* Cancel a pending data transfer.  */
static void scsi_cancel_io(SCSIRequest *req)
{
    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);

    DPRINTF("Cancel tag=0x%x\n", req->tag);
    if (r->req.aiocb) {
        bdrv_aio_cancel(r->req.aiocb);

        /* This reference was left in by scsi_*_data.  We take ownership of
         * it independent of whether bdrv_aio_cancel completes the request
         * or not.  */
        scsi_req_unref(&r->req);
    }
    r->req.aiocb = NULL;
}
Beispiel #6
0
/* Return FALSE if the submitted request is cancelled. */
static int submit_rand_io (RandomIO * r)
{
    BlockDriverAIOCB *acb = NULL;

    QDEBUG ("TESTER %03d:  %s  test%" PRIX64 " sector_num=%" PRId64
            " nb_sectors=%d niov=%d\n", r->tester, op_type_str[r->type],
            r->uuid, r->sector_num, r->nb_sectors, r->qiov.niov);
    printf ("TESTER %03d:  %s  sector_num=%" PRId64 " nb_sectors=%d niov=%d\n",
            r->tester, op_type_str[r->type], r->sector_num, r->nb_sectors,
            r->qiov.niov);

    int ret;
    if (fail_prob <= 0) {
        ret = 0;
    } else if (random () / (double) RAND_MAX <= fail_prob) {
        ret = -EIO;
    } else {
        ret = 0;
    }

    /* This affects whether this request will fail or not. */
    sim_set_disk_io_return_code (ret);

    switch (r->type) {
    case OP_READ:
        if (!(acb = bdrv_aio_readv (bs, r->sector_num, &r->qiov, r->nb_sectors,
                             rand_io_cb, r))) {
            die ("bdrv_aio_readv\n");
        }
        break;
    case OP_WRITE:
        if (!(acb = bdrv_aio_writev (bs, r->sector_num, &r->qiov, r->nb_sectors,
                              rand_io_cb, r))) {
            die ("bdrv_aio_writev\n");
        }
        break;
    case OP_FLUSH:
        if (!(acb = bdrv_aio_flush (bs, rand_io_cb, r))) {
            die ("bdrv_aio_flush\n");
        }
        break;
    case OP_NULL:
        die ("OP_NULL");
        break;
    }

    sim_set_disk_io_return_code (0);        /* Reset to no failure state. */

    if (r->allow_cancel && cancel_prob > 0 &&
                random () / (double) RAND_MAX <= cancel_prob) {
        QDEBUG ("TESTER %03d:  cancel %s test%" PRIX64 " sector_num=%" PRId64
                " nb_sectors=%d niov=%d\n", r->tester, op_type_str[r->type],
                r->uuid, r->sector_num, r->nb_sectors, r->qiov.niov);
        printf ("TESTER %03d:  cancel %s sector_num=%" PRId64
                " nb_sectors=%d niov=%d\n", r->tester, op_type_str[r->type],
                r->sector_num, r->nb_sectors, r->qiov.niov);
        bdrv_aio_cancel (acb);
        return FALSE;
    } else {
        return TRUE;
    }
}
Beispiel #7
0
/* Store data in the compact image. The argument 'soft_write' means
 * the store was caused by copy-on-read or prefetching, which need not
 * update metadata immediately. */
static BlockDriverAIOCB *store_data_in_compact_image (FvdAIOCB * acb,
                                                      int soft_write,
                                                      FvdAIOCB * parent_acb,
                                                      BlockDriverState * bs,
                                                      int64_t sector_num,
                                                      QEMUIOVector * orig_qiov,
                                                      const int nb_sectors,
                                                      BlockDriverCompletionFunc
                                                      * cb, void *opaque)
{
    BDRVFvdState *s = bs->opaque;

    const uint32_t first_chunk = sector_num / s->chunk_size;
    const uint32_t last_chunk = (sector_num + nb_sectors - 1) / s->chunk_size;
    int table_dirty = FALSE;
    uint32_t chunk;
    int64_t start_sec;

    /* Check if storag space is allocated. */
    for (chunk = first_chunk; chunk <= last_chunk; chunk++) {
        if (IS_EMPTY (s->table[chunk])) {
            uint32_t id = allocate_chunk (bs);
            if (IS_EMPTY (id)) {
                return NULL;
            }
            id |= DIRTY_TABLE;
            WRITE_TABLE (s->table[chunk], id);

            table_dirty = TRUE;
        } else if (IS_DIRTY (s->table[chunk])) {
            /* This is possible if a previous soft-write allocated the storage
             * space but did not flush the table entry change to the journal
             * and hence did not clean the dirty bit. This is also possible
             * with two concurrent hard-writes. The first hard-write allocated
             * the storage space but has not flushed the table entry change to
             * the journal yet and hence the table entry remains dirty. In
             * this case, the second hard-write will also try to flush this
             * dirty table entry to the journal. The outcome is correct since
             * they store the same metadata change in the journal (although
             * twice). For this race condition, we prefer to have two writes
             * to the journal rather than introducing a locking mechanism,
             * because this happens rarely and those two writes to the journal
             * are likely to be merged by the kernel into a single write since
             * they are likely to update back-to-back sectors in the journal.
             * A locking mechanism would be less efficient, because the large
             * size of chunks would cause unnecessary locking due to ``false
             * sharing'' of a chunk by two writes. */
            table_dirty = TRUE;
        }
    }

    const int update_table = (!soft_write && table_dirty);
    size_t iov_left;
    uint8_t *iov_buf;
    int nb, iov_index, nqiov, niov;
    uint32_t prev;

    if (first_chunk == last_chunk) {
        goto handle_one_continuous_region;
    }

    /* Count the number of qiov and iov needed to cover the continuous regions
     * of the compact image. */
    iov_left = orig_qiov->iov[0].iov_len;
    iov_buf = orig_qiov->iov[0].iov_base;
    iov_index = 0;
    nqiov = 0;
    niov = 0;
    prev = READ_TABLE (s->table[first_chunk]);

    /* Data in the first chunk. */
    nb = s->chunk_size - (sector_num % s->chunk_size);

    for (chunk = first_chunk + 1; chunk <= last_chunk; chunk++) {
        uint32_t current = READ_TABLE (s->table[chunk]);
        int64_t data_size;
        if (chunk < last_chunk) {
            data_size = s->chunk_size;
        } else {
            data_size = (sector_num + nb_sectors) % s->chunk_size;
            if (data_size == 0) {
                data_size = s->chunk_size;
            }
        }

        if (current == prev + 1) {
            nb += data_size;        /* Continue the previous region. */
        } else {
            /* Terminate the previous region. */
            niov +=
                count_iov (orig_qiov->iov, &iov_index, &iov_buf, &iov_left,
                           nb * 512);
            nqiov++;
            nb = data_size;        /* Data in the new region. */
        }
        prev = current;
    }

    if (nqiov == 0) {
      handle_one_continuous_region:
        /* A simple case. All data can be written out in one qiov and no new
         * chunks are allocated. */
        start_sec = READ_TABLE (s->table[first_chunk]) * s->chunk_size +
                                        (sector_num % s->chunk_size);

        if (!update_table && !acb) {
            if (parent_acb) {
                QDEBUG ("STORE: acb%llu-%p  "
                        "store_directly_without_table_update\n",
                        parent_acb->uuid, parent_acb);
            }
            return bdrv_aio_writev (s->fvd_data, s->data_offset + start_sec,
                                    orig_qiov, nb_sectors, cb, opaque);
        }

        if (!acb && !(acb = init_store_acb (soft_write, orig_qiov, bs,
                            sector_num, nb_sectors, parent_acb, cb, opaque))) {
            return NULL;
        }

        QDEBUG ("STORE: acb%llu-%p  store_directly  sector_num=%" PRId64
                " nb_sectors=%d\n", acb->uuid, acb, acb->sector_num,
                acb->nb_sectors);

        acb->store.update_table = update_table;
        acb->store.num_children = 1;
        acb->store.one_child.hd_acb =
            bdrv_aio_writev (s->fvd_data, s->data_offset + start_sec, orig_qiov,
                             nb_sectors, finish_store_data_in_compact_image,
                             &acb->store.one_child);
        if (acb->store.one_child.hd_acb) {
            acb->store.one_child.acb = acb;
            return &acb->common;
        } else {
            my_qemu_aio_unref (acb);
            return NULL;
        }
    }

    /* qiov for the last continuous region. */
    niov += count_iov (orig_qiov->iov, &iov_index, &iov_buf,
                       &iov_left, nb * 512);
    nqiov++;
    ASSERT (iov_index == orig_qiov->niov - 1 && iov_left == 0);

    /* Need to submit multiple requests to the lower layer. */
    if (!acb && !(acb = init_store_acb (soft_write, orig_qiov, bs, sector_num,
                                        nb_sectors, parent_acb, cb, opaque))) {
        return NULL;
    }
    acb->store.update_table = update_table;
    acb->store.num_children = nqiov;

    if (!parent_acb) {
        QDEBUG ("STORE: acb%llu-%p  start  sector_num=%" PRId64
                " nb_sectors=%d\n", acb->uuid, acb, acb->sector_num,
                acb->nb_sectors);
    }

    /* Allocate memory and create multiple requests. */
    const size_t metadata_size = nqiov * (sizeof (CompactChildCB) +
                                          sizeof (QEMUIOVector))
                                    + niov * sizeof (struct iovec);
    acb->store.children = (CompactChildCB *) my_qemu_malloc (metadata_size);
    QEMUIOVector *q = (QEMUIOVector *) (acb->store.children + nqiov);
    struct iovec *v = (struct iovec *) (q + nqiov);

    start_sec = READ_TABLE (s->table[first_chunk]) * s->chunk_size +
                                        (sector_num % s->chunk_size);
    nqiov = 0;
    iov_index = 0;
    iov_left = orig_qiov->iov[0].iov_len;
    iov_buf = orig_qiov->iov[0].iov_base;
    prev = READ_TABLE (s->table[first_chunk]);

    /* Data in the first chunk. */
    if (first_chunk == last_chunk) {
        nb = nb_sectors;
    }
    else {
        nb = s->chunk_size - (sector_num % s->chunk_size);
    }

    for (chunk = first_chunk + 1; chunk <= last_chunk; chunk++) {
        uint32_t current = READ_TABLE (s->table[chunk]);
        int64_t data_size;
        if (chunk < last_chunk) {
            data_size = s->chunk_size;
        } else {
            data_size = (sector_num + nb_sectors) % s->chunk_size;
            if (data_size == 0) {
                data_size = s->chunk_size;
            }
        }

        if (current == prev + 1) {
            nb += data_size;        /* Continue the previous region. */
        } else {
            /* Terminate the previous continuous region. */
            niov = setup_iov (orig_qiov->iov, v, &iov_index,
                              &iov_buf, &iov_left, nb * 512);
            qemu_iovec_init_external (q, v, niov);
            QDEBUG ("STORE: acb%llu-%p  create_child %d sector_num=%" PRId64
                    " nb_sectors=%d niov=%d\n", acb->uuid, acb, nqiov,
                    start_sec, q->size / 512, q->niov);
            acb->store.children[nqiov].hd_acb =
                bdrv_aio_writev (s->fvd_data, s->data_offset + start_sec, q,
                                 q->size / 512,
                                 finish_store_data_in_compact_image,
                                 &acb->store.children[nqiov]);
            if (!acb->store.children[nqiov].hd_acb) {
                goto fail;
            }
            acb->store.children[nqiov].acb = acb;
            v += niov;
            q++;
            nqiov++;
            start_sec = current * s->chunk_size; /* Begin of the new region. */
            nb = data_size;        /* Data in the new region. */
        }
        prev = current;
    }

    /* Requst for the last chunk. */
    niov = setup_iov (orig_qiov->iov, v, &iov_index, &iov_buf,
                      &iov_left, nb * 512);
    ASSERT (iov_index == orig_qiov->niov - 1 && iov_left == 0);
    qemu_iovec_init_external (q, v, niov);

    QDEBUG ("STORE: acb%llu-%p  create_child_last %d sector_num=%" PRId64
            " nb_sectors=%d niov=%d\n", acb->uuid, acb, nqiov, start_sec,
            q->size / 512, q->niov);
    acb->store.children[nqiov].hd_acb =
        bdrv_aio_writev (s->fvd_data, s->data_offset + start_sec, q,
                         q->size / 512, finish_store_data_in_compact_image,
                         &acb->store.children[nqiov]);
    if (acb->store.children[nqiov].hd_acb) {
        acb->store.children[nqiov].acb = acb;
        return &acb->common;
    }

    int i;
  fail:
    QDEBUG ("STORE: acb%llu-%p  failed\n", acb->uuid, acb);
    for (i = 0; i < nqiov; i++) {
        bdrv_aio_cancel (acb->store.children[i].hd_acb);
    }
    my_qemu_free (acb->store.children);
    my_qemu_aio_unref (acb);
    return NULL;
}