旅游景点网站建设规划书,邢台市网站开发公司有哪些,手机app模板,外呼系统接前一篇文章#xff1a; 上一回对于virtio_device_realize函数进行了详细解析。在第2步中virtio_device_realize函数调用了具体类的realize函数#xff0c;对于virtio balloon设备来说是virtio_balloon_realize函数。本回就来对于virtio_balloon_device_realize函数进行解析…接前一篇文章 上一回对于virtio_device_realize函数进行了详细解析。在第2步中virtio_device_realize函数调用了具体类的realize函数对于virtio balloon设备来说是virtio_balloon_realize函数。本回就来对于virtio_balloon_device_realize函数进行解析。
为了便于理解再次贴出virtio_device_realize函数源码在hw/virtio/virtio.c中如下
static void virtio_device_realize(DeviceState *dev, Error **errp)
{VirtIODevice *vdev VIRTIO_DEVICE(dev);VirtioDeviceClass *vdc VIRTIO_DEVICE_GET_CLASS(dev);Error *err NULL;/* Devices should either use vmsd or the load/save methods */assert(!vdc-vmsd || !vdc-load);if (vdc-realize ! NULL) {vdc-realize(dev, err);if (err ! NULL) {error_propagate(errp, err);return;}}virtio_bus_device_plugged(vdev, err);if (err ! NULL) {error_propagate(errp, err);vdc-unrealize(dev);return;}vdev-listener.commit virtio_memory_listener_commit;vdev-listener.name virtio;memory_listener_register(vdev-listener, vdev-dma_as);QTAILQ_INSERT_TAIL(virtio_list, vdev, next);
}
调用具体类的realize函数的代码片段如下 if (vdc-realize ! NULL) {vdc-realize(dev, err);if (err ! NULL) {error_propagate(errp, err);return;}}
virtio_balloon_device_realize函数在hw/virtio/virtio-balloon.c中代码如下
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_ID_BALLOON, virtio_balloon_config_size(s));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;}if (virtio_has_feature(s-host_features, VIRTIO_BALLOON_F_FREE_PAGE_HINT) !s-iothread) {error_setg(errp, free-page-hint requires iothread to be set);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);if (virtio_has_feature(s-host_features, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) {s-free_page_vq virtio_add_queue(vdev, VIRTQUEUE_MAX_SIZE,virtio_balloon_handle_free_page_vq);precopy_add_notifier(s-free_page_hint_notify);object_ref(OBJECT(s-iothread));s-free_page_bh aio_bh_new_guarded(iothread_get_aio_context(s-iothread),virtio_ballloon_get_free_page_hints, s,dev-mem_reentrancy_guard);}if (virtio_has_feature(s-host_features, VIRTIO_BALLOON_F_REPORTING)) {s-reporting_vq virtio_add_queue(vdev, 32,virtio_balloon_handle_report);}reset_stats(s);
}
在同文件hw/virtio/virtio-balloon.c的virtio_balloon_class_init函数中将virtio_balloon_device_realize函数地址赋给了vdc-realize。
static void virtio_balloon_class_init(ObjectClass *klass, void *data)
{DeviceClass *dc DEVICE_CLASS(klass);VirtioDeviceClass *vdc VIRTIO_DEVICE_CLASS(klass);device_class_set_props(dc, virtio_balloon_properties);dc-vmsd vmstate_virtio_balloon;set_bit(DEVICE_CATEGORY_MISC, dc-categories);vdc-realize virtio_balloon_device_realize;vdc-unrealize virtio_balloon_device_unrealize;vdc-reset virtio_balloon_device_reset;vdc-get_config virtio_balloon_get_config;vdc-set_config virtio_balloon_set_config;vdc-get_features virtio_balloon_get_features;vdc-set_status virtio_balloon_set_status;vdc-vmsd vmstate_virtio_balloon_device;
}virtio_balloon_device_realize()是virtio balloon设备的具现化函数它用于实现TYPE_VIRTIO_BALLOON_DEVICE的具现化。
1virtio_balloon_device_realize函数首先调用virtio_init函数初始化virtio设备的公共部分。代码片段如下 virtio_init(vdev, VIRTIO_ID_BALLOON, virtio_balloon_config_size(s));
virtio_init函数在hw/virtio/virtio.c中代码如下
void virtio_init(VirtIODevice *vdev, uint16_t device_id, size_t config_size)
{BusState *qbus qdev_get_parent_bus(DEVICE(vdev));VirtioBusClass *k VIRTIO_BUS_GET_CLASS(qbus);int i;int nvectors k-query_nvectors ? k-query_nvectors(qbus-parent) : 0;if (nvectors) {vdev-vector_queues g_malloc0(sizeof(*vdev-vector_queues) * nvectors);}vdev-start_on_kick false;vdev-started false;vdev-vhost_started false;vdev-device_id device_id;vdev-status 0;qatomic_set(vdev-isr, 0);vdev-queue_sel 0;vdev-config_vector VIRTIO_NO_VECTOR;vdev-vq g_new0(VirtQueue, VIRTIO_QUEUE_MAX);vdev-vm_running runstate_is_running();vdev-broken false;for (i 0; i VIRTIO_QUEUE_MAX; i) {vdev-vq[i].vector VIRTIO_NO_VECTOR;vdev-vq[i].vdev vdev;vdev-vq[i].queue_index i;vdev-vq[i].host_notifier_enabled false;}vdev-name virtio_id_to_name(device_id);vdev-config_len config_size;if (vdev-config_len) {vdev-config g_malloc0(config_size);} else {vdev-config NULL;}vdev-vmstate qdev_add_vm_change_state_handler(DEVICE(vdev),virtio_vmstate_change, vdev);vdev-device_endian virtio_default_endian();vdev-use_guest_notifier_mask true;
}
virtio_init函数的工作是初始化所有virtio设备的基类TYPE_VIRTIO_DEVICE的实例VirtIODevice结构体其对VirtIODevice的成员进行初始化。
VirtIODevice的vector_queues成员和config_vector成员与MSI中断相关device_id、status、name成员分别表示设备的id、状态和名字isr成员用来表示中断请求queue_sel成员用来在进行配置队列的时候选择队列vq成员表示的是该设备的virtio queue这里分配了VIRTIO_QUEUE_MAX个queue并且进行了初始化config_len和config分别表示该virtio设备配置空间的长度和数据存放区域use_guest_notifier_mask成员与irqfd有关。
回到virtio_balloon_device_realize函数。
2在virtio_init函数初始化了VirtIODevice之后调用virtio_add_queue函数创建了3个virtqueue。代码片段如下 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);
virtqueue是virtio设备的重要组成部分用来与虚拟机中的操作系统进行数据传输。virtio_add_queue函数在hw/virtio/virtio.c中代码如下
VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,VirtIOHandleOutput handle_output)
{int i;for (i 0; i VIRTIO_QUEUE_MAX; i) {if (vdev-vq[i].vring.num 0)break;}if (i VIRTIO_QUEUE_MAX || queue_size VIRTQUEUE_MAX_SIZE)abort();vdev-vq[i].vring.num queue_size;vdev-vq[i].vring.num_default queue_size;vdev-vq[i].vring.align VIRTIO_PCI_VRING_ALIGN;vdev-vq[i].handle_output handle_output;vdev-vq[i].used_elems g_new0(VirtQueueElement, queue_size);return vdev-vq[i];
}
virtio_add_queue函数是virtio框架中用来添加virtqueue的接口其3个参数分别表示要添加的设备VirtIODevice *vdev、virtqueue的大小int queue_size以及处理函数VirtIOHandleOutput handle_output。
virtio_add_queue函数从VirtIODevice的vq数组成员中找到还未被使用的一个queue。一个virtqueue使用VirtQueue结构表示这里对VirtQueue的成员进行初始化包括这个queue的大小以及对齐等信息。最重要的是设置VirtQueue的handle_output成员其是一个函数指针在收到虚拟机发过来的IO请求时会调用存放在handle_output中的回调函数。
VirtQueue结构的定义在hw/virtio/virtio.c中如下
struct VirtQueue
{VRing vring;VirtQueueElement *used_elems;/* Next head to pop */uint16_t last_avail_idx;bool last_avail_wrap_counter;/* Last avail_idx read from VQ. */uint16_t shadow_avail_idx;bool shadow_avail_wrap_counter;uint16_t used_idx;bool used_wrap_counter;/* Last used index value we have signalled on */uint16_t signalled_used;/* Last used index value we have signalled on */bool signalled_used_valid;/* Notification enabled? */bool notification;uint16_t queue_index;unsigned int inuse;uint16_t vector;VirtIOHandleOutput handle_output;VirtIODevice *vdev;EventNotifier guest_notifier;EventNotifier host_notifier;bool host_notifier_enabled;QLIST_ENTRY(VirtQueue) node;
}; 欲知后事如何且看下回分解。