static bool virtio_balloon_free_page_support(void *opaque) { VirtIOBalloon *s = opaque; VirtIODevice *vdev = VIRTIO_DEVICE(s); return virtio_vdev_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT); }
static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) { VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev); DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *proxy = DEVICE(vpci_dev); char *bus_name; if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER && vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */ vpci_dev->class_code != PCI_CLASS_OTHERS) { /* qemu-kvm */ vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER; } /* backwards-compatibility with machines that were created with DEV_NVECTORS_UNSPECIFIED */ if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1; } /* * For command line compatibility, this sets the virtio-serial-device bus * name as before. */ if (proxy->id) { bus_name = g_strdup_printf("%s.0", proxy->id); virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name); g_free(bus_name); } qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); object_property_set_bool(OBJECT(vdev), true, "realized", errp); }
static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb) { BlockRequest *blkreq; uint64_t sector; sector = virtio_ldq_p(VIRTIO_DEVICE(req->dev), &req->out.sector); bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_WRITE); trace_virtio_blk_handle_write(req, sector, req->qiov.size / 512); if (sector & req->dev->sector_mask) { virtio_blk_rw_complete(req, -EIO); return; } if (req->qiov.size % req->dev->conf->logical_block_size) { virtio_blk_rw_complete(req, -EIO); return; } if (mrb->num_writes == 32) { virtio_submit_multiwrite(req->dev->bs, mrb); } blkreq = &mrb->blkreq[mrb->num_writes]; blkreq->sector = sector; blkreq->nb_sectors = req->qiov.size / BDRV_SECTOR_SIZE; blkreq->qiov = &req->qiov; blkreq->cb = virtio_blk_rw_complete; blkreq->opaque = req; blkreq->error = 0; mrb->num_writes++; }
static void virtio_blk_rw_complete(void *opaque, int ret) { VirtIOBlockReq *next = opaque; while (next) { VirtIOBlockReq *req = next; next = req->mr_next; trace_virtio_blk_rw_complete(req, ret); if (req->qiov.nalloc != -1) { /* If nalloc is != 1 req->qiov is a local copy of the original * external iovec. It was allocated in submit_merged_requests * to be able to merge requests. */ qemu_iovec_destroy(&req->qiov); } if (ret) { int p = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type); bool is_read = !(p & VIRTIO_BLK_T_OUT); if (virtio_blk_handle_rw_error(req, -ret, is_read)) { continue; } } virtio_blk_req_complete(req, VIRTIO_BLK_S_OK); block_acct_done(blk_get_stats(req->dev->blk), &req->acct); virtio_blk_free_request(req); } }
static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id) { VirtIOBlock *s = opaque; VirtIODevice *vdev = VIRTIO_DEVICE(s); int ret; if (version_id != 2) return -EINVAL; ret = virtio_load(vdev, f); if (ret) { return ret; } while (qemu_get_sbyte(f)) { VirtIOBlockReq *req = virtio_blk_alloc_request(s); qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem)); req->next = s->rq; s->rq = req; virtqueue_map_sg(req->elem.in_sg, req->elem.in_addr, req->elem.in_num, 1); virtqueue_map_sg(req->elem.out_sg, req->elem.out_addr, req->elem.out_num, 0); } return 0; }
static void virtio_crypto_dataq_bh(void *opaque) { VirtIOCryptoQueue *q = opaque; VirtIOCrypto *vcrypto = q->vcrypto; VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); /* This happens when device was stopped but BH wasn't. */ if (!vdev->vm_running) { return; } /* Just in case the driver is not ready on more */ if (unlikely(!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK))) { return; } for (;;) { virtio_crypto_handle_dataq(vdev, q->dataq); virtio_queue_set_notification(q->dataq, 1); /* Are we done or did the guest add more buffers? */ if (virtio_queue_empty(q->dataq)) { break; } virtio_queue_set_notification(q->dataq, 0); } }
static int vhost_vsock_load(QEMUFile *f, void *opaque, size_t size) { VHostVSock *vsock = opaque; VirtIODevice *vdev = VIRTIO_DEVICE(vsock); int ret; ret = virtio_load(vdev, f, VHOST_VSOCK_SAVEVM_VERSION); if (ret) { return ret; } if (virtio_queue_get_addr(vdev, 2)) { /* Defer transport reset event to a vm clock timer so that virtqueue * changes happen after migration has completed. */ assert(!vsock->post_load_timer); vsock->post_load_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, vhost_vsock_post_load_timer_cb, vsock); timer_mod(vsock->post_load_timer, 1); } return 0; }
static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id) { if (version_id != 1) return -EINVAL; return virtio_load(VIRTIO_DEVICE(opaque), f, version_id); }
static void vhost_vsock_send_transport_reset(VHostVSock *vsock) { VirtQueueElement *elem; VirtQueue *vq = vsock->event_vq; struct virtio_vsock_event event = { .id = cpu_to_le32(VIRTIO_VSOCK_EVENT_TRANSPORT_RESET), }; elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); if (!elem) { error_report("vhost-vsock missed transport reset event"); return; } if (elem->out_num) { error_report("invalid vhost-vsock event virtqueue element with " "out buffers"); goto out; } if (iov_from_buf(elem->in_sg, elem->in_num, 0, &event, sizeof(event)) != sizeof(event)) { error_report("vhost-vsock event virtqueue element is too short"); goto out; } virtqueue_push(vq, elem, sizeof(event)); virtio_notify(VIRTIO_DEVICE(vsock), vq); out: g_free(elem); }
/* Disable dataplane thread during live migration since it does not * update the dirty memory bitmap yet. */ static void virtio_blk_migration_state_changed(Notifier *notifier, void *data) { VirtIOBlock *s = container_of(notifier, VirtIOBlock, migration_state_notifier); MigrationState *mig = data; Error *err = NULL; if (migration_in_setup(mig)) { if (!s->dataplane) { return; } virtio_blk_data_plane_destroy(s->dataplane); s->dataplane = NULL; } else if (migration_has_finished(mig) || migration_has_failed(mig)) { if (s->dataplane) { return; } bdrv_drain_all(); /* complete in-flight non-dataplane requests */ virtio_blk_data_plane_create(VIRTIO_DEVICE(s), &s->blk, &s->dataplane, &err); if (err != NULL) { error_report("%s", error_get_pretty(err)); error_free(err); } } }
static void virtio_balloon_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOBalloon *s = VIRTIO_BALLOON(dev); int ret; virtio_init(vdev, "virtio-balloon", VIRTIO_ID_BALLOON, sizeof(struct virtio_balloon_config)); ret = qemu_add_balloon_handler(virtio_balloon_to_target, virtio_balloon_stat, s); if (ret < 0) { error_setg(errp, "Only one balloon device is supported"); virtio_cleanup(vdev); return; } s->ivq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output); s->dvq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output); s->svq = virtio_add_queue(vdev, 128, virtio_balloon_receive_stats); reset_stats(s); register_savevm(dev, "virtio-balloon", -1, 1, virtio_balloon_save, virtio_balloon_load, s); }
static void virtio_balloon_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOBalloon *s = VIRTIO_BALLOON(dev); int ret; virtio_init(vdev, "virtio-balloon", VIRTIO_ID_BALLOON, sizeof(struct virtio_balloon_config)); ret = qemu_add_balloon_handler(virtio_balloon_to_target, virtio_balloon_stat, s); if (ret < 0) { error_setg(errp, "Adding balloon handler failed"); virtio_cleanup(vdev); return; } s->ivq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output); s->dvq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output); s->svq = virtio_add_queue(vdev, 128, virtio_balloon_receive_stats); register_savevm(dev, "virtio-balloon", -1, 1, virtio_balloon_save, virtio_balloon_load, s); object_property_add(OBJECT(dev), "guest-stats", "guest statistics", balloon_stats_get_all, NULL, NULL, s, NULL); object_property_add(OBJECT(dev), "guest-stats-polling-interval", "int", balloon_stats_get_poll_interval, balloon_stats_set_poll_interval, NULL, s, NULL); }
static void virtio_cuda_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); virtio_init(vdev, "virtio-cuda", 13, 0); virtio_add_queue(vdev, 1024, vq_handle_output); }
static int virtio_balloon_device_init(VirtIODevice *vdev) { DeviceState *qdev = DEVICE(vdev); VirtIOBalloon *s = VIRTIO_BALLOON(vdev); int ret; virtio_init(vdev, "virtio-balloon", VIRTIO_ID_BALLOON, 8); ret = qemu_add_balloon_handler(virtio_balloon_to_target, virtio_balloon_stat, s); if (ret < 0) { virtio_cleanup(VIRTIO_DEVICE(s)); return -1; } s->ivq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output); s->dvq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output); s->svq = virtio_add_queue(vdev, 128, virtio_balloon_receive_stats); register_savevm(qdev, "virtio-balloon", -1, 1, virtio_balloon_save, virtio_balloon_load, s); object_property_add(OBJECT(qdev), "guest-stats", "guest statistics", balloon_stats_get_all, NULL, NULL, s, NULL); object_property_add(OBJECT(qdev), "guest-stats-polling-interval", "int", balloon_stats_get_poll_interval, balloon_stats_set_poll_interval, NULL, s, NULL); return 0; }
static void virtio_balloon_free_page_done(VirtIOBalloon *s) { VirtIODevice *vdev = VIRTIO_DEVICE(s); s->free_page_report_status = FREE_PAGE_REPORT_S_DONE; virtio_notify_config(vdev); }
static void virtio_rng_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIORNG *vrng = VIRTIO_RNG(dev); Error *local_err = NULL; if (vrng->conf.period_ms <= 0) { error_setg(errp, "'period' parameter expects a positive integer"); return; } /* Workaround: Property parsing does not enforce unsigned integers, * So this is a hack to reject such numbers. */ if (vrng->conf.max_bytes > INT64_MAX) { error_setg(errp, "'max-bytes' parameter must be non-negative, " "and less than 2^63"); return; } if (vrng->conf.rng == NULL) { vrng->conf.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM)); user_creatable_complete(OBJECT(vrng->conf.default_backend), &local_err); if (local_err) { error_propagate(errp, local_err); object_unref(OBJECT(vrng->conf.default_backend)); return; } object_property_add_child(OBJECT(dev), "default-backend", OBJECT(vrng->conf.default_backend), NULL); /* The child property took a reference, we can safely drop ours now */ object_unref(OBJECT(vrng->conf.default_backend)); object_property_set_link(OBJECT(dev), OBJECT(vrng->conf.default_backend), "rng", NULL); } vrng->rng = vrng->conf.rng; if (vrng->rng == NULL) { error_setg(errp, "'rng' parameter expects a valid object"); return; } virtio_init(vdev, "virtio-rng", VIRTIO_ID_RNG, 0); vrng->vq = virtio_add_queue(vdev, 8, handle_input); vrng->quota_remaining = vrng->conf.max_bytes; vrng->rate_limit_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, check_rate_limit, vrng); vrng->activate_timer = true; register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save, virtio_rng_load, vrng); }
static void virtio_balloon_device_unrealize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOBalloon *s = VIRTIO_BALLOON(dev); balloon_stats_destroy_timer(s); qemu_remove_balloon_handler(s); virtio_cleanup(vdev); }
static void virtio_blk_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOBlock *s = VIRTIO_BLK(dev); VirtIOBlkConf *blk = &(s->blk); #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE Error *err = NULL; #endif static int virtio_blk_id; if (!blk->conf.bs) { error_setg(errp, "drive property not set"); return; } if (!bdrv_is_inserted(blk->conf.bs)) { error_setg(errp, "Device needs media, but drive is empty"); return; } blkconf_serial(&blk->conf, &blk->serial); s->original_wce = bdrv_enable_write_cache(blk->conf.bs); if (blkconf_geometry(&blk->conf, NULL, 65535, 255, 255) < 0) { error_setg(errp, "Error setting geometry"); return; } virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, sizeof(struct virtio_blk_config)); s->bs = blk->conf.bs; s->conf = &blk->conf; s->rq = NULL; s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1; s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output); s->complete_request = virtio_blk_complete_request; #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE virtio_blk_data_plane_create(vdev, blk, &s->dataplane, &err); if (err != NULL) { error_propagate(errp, err); virtio_cleanup(vdev); return; } s->migration_state_notifier.notify = virtio_blk_migration_state_changed; add_migration_state_change_notifier(&s->migration_state_notifier); #endif s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); register_savevm(dev, "virtio-blk", virtio_blk_id++, 2, virtio_blk_save, virtio_blk_load, s); bdrv_set_dev_ops(s->bs, &virtio_block_ops, s); bdrv_set_guest_block_size(s->bs, s->conf->logical_block_size); bdrv_iostatus_enable(s->bs); add_boot_device_path(s->conf->bootindex, dev, "/disk@0,0"); }
static void virtio_9p_device_unrealize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); V9fsVirtioState *v = VIRTIO_9P(dev); V9fsState *s = &v->state; virtio_cleanup(vdev); v9fs_device_unrealize_common(s, errp); }
static void vhost_vsock_save(QEMUFile *f, void *opaque, size_t size) { VHostVSock *vsock = opaque; VirtIODevice *vdev = VIRTIO_DEVICE(vsock); /* At this point, backend must be stopped, otherwise * it might keep writing to memory. */ assert(!vsock->vhost_dev.started); virtio_save(vdev, f); }
static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id) { VirtIOBlock *s = opaque; VirtIODevice *vdev = VIRTIO_DEVICE(s); if (version_id != 2) return -EINVAL; return virtio_load(vdev, f, version_id); }
static void virtio_rng_device_unrealize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIORNG *vrng = VIRTIO_RNG(dev); timer_del(vrng->rate_limit_timer); timer_free(vrng->rate_limit_timer); unregister_savevm(dev, "virtio-rng", vrng); virtio_cleanup(vdev); }
static void virtio_balloon_save(QEMUFile *f, void *opaque) { VirtIOBalloon *s = VIRTIO_BALLOON(opaque); VirtIODevice *vdev = VIRTIO_DEVICE(s); virtio_save(vdev, f); qemu_put_be32(f, s->num_pages); qemu_put_be32(f, s->actual); }
static bool is_guest_ready(VirtIORNG *vrng) { VirtIODevice *vdev = VIRTIO_DEVICE(vrng); if (virtio_queue_ready(vrng->vq) && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) { return true; } trace_virtio_rng_guest_not_ready(vrng); return false; }
static void virtio_blk_req_complete(VirtIOBlockReq *req, int status) { VirtIOBlock *s = req->dev; VirtIODevice *vdev = VIRTIO_DEVICE(s); trace_virtio_blk_req_complete(req, status); stb_p(&req->in->status, status); virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in)); virtio_notify(vdev, s->vq); }
static int virtio_balloon_device_exit(DeviceState *qdev) { VirtIOBalloon *s = VIRTIO_BALLOON(qdev); VirtIODevice *vdev = VIRTIO_DEVICE(qdev); balloon_stats_destroy_timer(s); qemu_remove_balloon_handler(s); unregister_savevm(qdev, "virtio-balloon", s); virtio_common_cleanup(vdev); return 0; }
static void virtio_blk_rw_complete(void *opaque, int ret) { VirtIOBlockReq *next = opaque; VirtIOBlock *s = next->dev; VirtIODevice *vdev = VIRTIO_DEVICE(s); aio_context_acquire(blk_get_aio_context(s->conf.conf.blk)); while (next) { VirtIOBlockReq *req = next; next = req->mr_next; trace_virtio_blk_rw_complete(vdev, req, ret); if (req->qiov.nalloc != -1) { /* If nalloc is != 1 req->qiov is a local copy of the original * external iovec. It was allocated in submit_merged_requests * to be able to merge requests. */ qemu_iovec_destroy(&req->qiov); } if (ret) { int p = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type); bool is_read = !(p & VIRTIO_BLK_T_OUT); /* Note that memory may be dirtied on read failure. If the * virtio request is not completed here, as is the case for * BLOCK_ERROR_ACTION_STOP, the memory may not be copied * correctly during live migration. While this is ugly, * it is acceptable because the device is free to write to * the memory until the request is completed (which will * happen on the other side of the migration). */ if (virtio_blk_handle_rw_error(req, -ret, is_read)) { continue; } } virtio_blk_req_complete(req, VIRTIO_BLK_S_OK); block_acct_done(blk_get_stats(req->dev->blk), &req->acct); virtio_blk_free_request(req); } aio_context_release(blk_get_aio_context(s->conf.conf.blk)); }
static int virtio_ccw_blk_init(VirtioCcwDevice *ccw_dev) { VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); virtio_blk_set_conf(vdev, &(dev->blk)); qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); if (qdev_init(vdev) < 0) { return -1; } return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev)); }
static int virtio_ccw_scsi_init(VirtioCcwDevice *ccw_dev) { VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); if (qdev_init(vdev) < 0) { return -1; } return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev)); }
static void virtio_blk_complete_request(VirtIOBlockReq *req, unsigned char status) { VirtIOBlock *s = req->dev; VirtIODevice *vdev = VIRTIO_DEVICE(s); trace_virtio_blk_req_complete(req, status); stb_p(&req->in->status, status); virtqueue_push(s->vq, &req->elem, req->in_len); virtio_notify(vdev, s->vq); }