Example #1
0
void virtio_blk_exit(VirtIODevice *vdev)
{
    VirtIOBlock *s = to_virtio_blk(vdev);
    unregister_savevm(s->qdev, "virtio-blk", s);
    blockdev_mark_auto_del(s->bs);
    virtio_cleanup(vdev);
}
Example #2
0
static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
{
    VirtIOBlock *s = to_virtio_blk(vdev);
    struct virtio_blk_config blkcfg;

    memcpy(&blkcfg, config, sizeof(blkcfg));
    bdrv_set_enable_write_cache(s->bs, blkcfg.wce != 0);
}
Example #3
0
static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
{
    VirtIOBlock *s = to_virtio_blk(vdev);

    if (s->dataplane && !(status & (VIRTIO_CONFIG_S_DRIVER |
                                    VIRTIO_CONFIG_S_DRIVER_OK))) {
        virtio_blk_data_plane_stop(s->dataplane);
    }
}
Example #4
0
static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
    VirtIOBlock *s = to_virtio_blk(vdev);
    VirtIOBlockReq *req;

    while ((req = virtio_blk_get_request(s))) {
        int i;

        if (req->elem.out_num < 1 || req->elem.in_num < 1) {
            fprintf(stderr, "virtio-blk missing headers\n");
            exit(1);
        }

        if (req->elem.out_sg[0].iov_len < sizeof(*req->out) ||
            req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) {
            fprintf(stderr, "virtio-blk header not in correct element\n");
            exit(1);
        }

        req->out = (void *)req->elem.out_sg[0].iov_base;
        req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;

        if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) {
            unsigned int len = sizeof(*req->in);

            req->in->status = VIRTIO_BLK_S_UNSUPP;
            virtqueue_push(vq, &req->elem, len);
            virtio_notify(vdev, vq);
            qemu_free(req);
        } else if (req->out->type & VIRTIO_BLK_T_OUT) {
            if (virtio_blk_handle_write(req) < 0)
                break;
        } else {
            for (i = 0; i < req->elem.in_num - 1; i++)
                req->size += req->elem.in_sg[i].iov_len;

            req->buffer = qemu_memalign(512, req->size);
            if (req->buffer == NULL) {
                qemu_free(req);
                break;
            }

            bdrv_aio_read(s->bs, req->out->sector,
                          req->buffer,
                          req->size / 512,
                          virtio_blk_rw_complete,
                          req);
        }
    }
    /*
     * FIXME: Want to check for completions before returning to guest mode,
     * so cached reads and writes are reported as quickly as possible. But
     * that should be done in the generic block layer.
     */
}
Example #5
0
static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
    VirtIOBlock *s = to_virtio_blk(vdev);
    VirtIOBlockReq *req;
    MultiReqBuffer mrb = {
        .num_writes = 0,
    };

    while ((req = virtio_blk_get_request(s))) {
        virtio_blk_handle_request(req, &mrb);
    }

    virtio_submit_multiwrite(s->bs, &mrb);

    /*
     * FIXME: Want to check for completions before returning to guest mode,
     * so cached reads and writes are reported as quickly as possible. But
     * that should be done in the generic block layer.
     */
}

static void virtio_blk_dma_restart_bh(void *opaque)
{
    VirtIOBlock *s = opaque;
    VirtIOBlockReq *req = s->rq;
    MultiReqBuffer mrb = {
        .num_writes = 0,
    };

    qemu_bh_delete(s->bh);
    s->bh = NULL;

    s->rq = NULL;

    while (req) {
        virtio_blk_handle_request(req, &mrb);
        req = req->next;
    }

    virtio_submit_multiwrite(s->bs, &mrb);
}

static void virtio_blk_dma_restart_cb(void *opaque, int running,
                                      RunState state)
{
    VirtIOBlock *s = opaque;

    if (!running)
        return;

    if (!s->bh) {
        s->bh = qemu_bh_new(virtio_blk_dma_restart_bh, s);
        qemu_bh_schedule(s->bh);
    }
}
Example #6
0
void virtio_blk_exit(VirtIODevice *vdev)
{
    VirtIOBlock *s = to_virtio_blk(vdev);

#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
    virtio_blk_data_plane_destroy(s->dataplane);
    s->dataplane = NULL;
#endif
    qemu_del_vm_change_state_handler(s->change);
    unregister_savevm(s->qdev, "virtio-blk", s);
    virtio_cleanup(vdev);
}
Example #7
0
static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
{
    VirtIOBlock *s = to_virtio_blk(vdev);
    uint32_t features;

    if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
        return;
    }

    features = vdev->guest_features;
    bdrv_set_enable_write_cache(s->bs, !!(features & (1 << VIRTIO_BLK_F_WCE)));
}
Example #8
0
static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
{
    VirtIOBlock *s = to_virtio_blk(vdev);
    struct virtio_blk_config blkcfg;
    uint64_t capacity;
    int cylinders, heads, secs;

    bdrv_get_geometry(s->bs, &capacity);
    bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs);
    stq_raw(&blkcfg.capacity, capacity);
    stl_raw(&blkcfg.seg_max, 128 - 2);
    stw_raw(&blkcfg.cylinders, cylinders);
    blkcfg.heads = heads;
    blkcfg.sectors = secs;
    memcpy(config, &blkcfg, sizeof(blkcfg));
}
Example #9
0
static void virtio_blk_reset(VirtIODevice *vdev)
{
#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
    VirtIOBlock *s = to_virtio_blk(vdev);

    if (s->dataplane) {
        virtio_blk_data_plane_stop(s->dataplane);
    }
#endif

    /*
     * This should cancel pending requests, but can't do nicely until there
     * are per-device request lists.
     */
    bdrv_drain_all();
}
Example #10
0
static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
{
    VirtIOBlock *s = to_virtio_blk(vdev);

    features |= (1 << VIRTIO_BLK_F_SEG_MAX);
    features |= (1 << VIRTIO_BLK_F_GEOMETRY);
    features |= (1 << VIRTIO_BLK_F_TOPOLOGY);
    features |= (1 << VIRTIO_BLK_F_BLK_SIZE);

    if (bdrv_enable_write_cache(s->bs))
        features |= (1 << VIRTIO_BLK_F_WCACHE);
    
    if (bdrv_is_read_only(s->bs))
        features |= 1 << VIRTIO_BLK_F_RO;

    return features;
}
Example #11
0
/* coalesce internal state, copy to pci i/o region 0
 */
static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
{
    VirtIOBlock *s = to_virtio_blk(vdev);
    struct virtio_blk_config blkcfg;
    uint64_t capacity;
    int blk_size = s->conf->logical_block_size;

    bdrv_get_geometry(s->bs, &capacity);
    memset(&blkcfg, 0, sizeof(blkcfg));
    stq_raw(&blkcfg.capacity, capacity);
    stl_raw(&blkcfg.seg_max, 128 - 2);
    stw_raw(&blkcfg.cylinders, s->conf->cyls);
    stl_raw(&blkcfg.blk_size, blk_size);
    stw_raw(&blkcfg.min_io_size, s->conf->min_io_size / blk_size);
    stw_raw(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size);
    blkcfg.heads = s->conf->heads;
    /*
     * We must ensure that the block device capacity is a multiple of
     * the logical block size. If that is not the case, lets use
     * sector_mask to adopt the geometry to have a correct picture.
     * For those devices where the capacity is ok for the given geometry
     * we dont touch the sector value of the geometry, since some devices
     * (like s390 dasd) need a specific value. Here the capacity is already
     * cyls*heads*secs*blk_size and the sector value is not block size
     * divided by 512 - instead it is the amount of blk_size blocks
     * per track (cylinder).
     */
    if (bdrv_getlength(s->bs) /  s->conf->heads / s->conf->secs % blk_size) {
        blkcfg.sectors = s->conf->secs & ~s->sector_mask;
    } else {
        blkcfg.sectors = s->conf->secs;
    }
    blkcfg.size_max = 0;
    blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
    blkcfg.alignment_offset = 0;
    blkcfg.wce = bdrv_enable_write_cache(s->bs);
    memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
}
Example #12
0
/* coalesce internal state, copy to pci i/o region 0
 */
static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
{
    VirtIOBlock *s = to_virtio_blk(vdev);
    struct virtio_blk_config blkcfg;
    uint64_t capacity;
    int cylinders, heads, secs;

    bdrv_get_geometry(s->bs, &capacity);
    bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs);
    memset(&blkcfg, 0, sizeof(blkcfg));
    stq_raw(&blkcfg.capacity, capacity);
    stl_raw(&blkcfg.seg_max, 128 - 2);
    stw_raw(&blkcfg.cylinders, cylinders);
    blkcfg.heads = heads;
    blkcfg.sectors = secs & ~s->sector_mask;
    blkcfg.blk_size = s->conf->logical_block_size;
    blkcfg.size_max = 0;
    blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
    blkcfg.alignment_offset = 0;
    blkcfg.min_io_size = s->conf->min_io_size / blkcfg.blk_size;
    blkcfg.opt_io_size = s->conf->opt_io_size / blkcfg.blk_size;
    memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
}
Example #13
0
void virtio_blk_exit(VirtIODevice *vdev)
{
    VirtIOBlock *s = to_virtio_blk(vdev);
    unregister_savevm(s->qdev, "virtio-blk", s);
}
Example #14
0
static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
    VirtIOBlock *s = to_virtio_blk(vdev);
    VirtIOBlockReq *req;
    MultiReqBuffer mrb = {
        .num_writes = 0,
        .old_bs = NULL,
    };

#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
    /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start
     * dataplane here instead of waiting for .set_status().
     */
    if (s->dataplane) {
        virtio_blk_data_plane_start(s->dataplane);
        return;
    }
#endif

    while ((req = virtio_blk_get_request(s))) {
        virtio_blk_handle_request(req, &mrb);
    }

    if (mrb.num_writes > 0) {
        do_multiwrite(mrb.old_bs, mrb.blkreq, mrb.num_writes);
    }

    /*
     * FIXME: Want to check for completions before returning to guest mode,
     * so cached reads and writes are reported as quickly as possible. But
     * that should be done in the generic block layer.
     */
}

static void virtio_blk_dma_restart_bh(void *opaque)
{
    VirtIOBlock *s = opaque;
    VirtIOBlockReq *req = s->rq;
    MultiReqBuffer mrb = {
        .num_writes = 0,
        .old_bs = NULL,
    };

    qemu_bh_delete(s->bh);
    s->bh = NULL;

    s->rq = NULL;

    while (req) {
        virtio_blk_handle_request(req, &mrb);
        req = req->next;
    }

    if (mrb.num_writes > 0) {
        do_multiwrite(mrb.old_bs, mrb.blkreq, mrb.num_writes);
    }
}

static void virtio_blk_dma_restart_cb(void *opaque, int running, RunState state)
{
    VirtIOBlock *s = opaque;

    if (!running)
        return;

    if (!s->bh) {
        s->bh = qemu_bh_new(virtio_blk_dma_restart_bh, s);
        qemu_bh_schedule(s->bh);
    }
}