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); }
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); }
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); } }
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. */ }
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); } }
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); }
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))); }
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)); }
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(); }
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; }
/* 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)); }
/* 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)); }
void virtio_blk_exit(VirtIODevice *vdev) { VirtIOBlock *s = to_virtio_blk(vdev); unregister_savevm(s->qdev, "virtio-blk", s); }
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); } }