QEMU源码全解析 —— virtio(5)

88 篇文章 19 订阅
本文详细解析QEMU中virtio balloon设备的初始化过程,通过virtio balloon PCI设备和virtual balloon设备的代码分析,展示了从实例化到调用virtio_instance_init_common函数的步骤,阐述了对象初始化的过程及其在设备具现化中的作用。
摘要由CSDN通过智能技术生成

接前一篇文章:

本文内容参考:

《趣谈 Linux操作系统 》 —— 刘超, 极客时间

QEMU /KVM》源码解析与应用 —— 李强,机械工业出版社

特此致谢!

上一回以virtio balloon设备为例概述了具体的virtio设备、virtio PCI代理设备、virtio公共设备的关系,如下图所示:

本回讲解代码细节。

仍以virtio balloon设备为例分析virtio设备的初始化过程。再次贴出之前的相关代码:

  • virtio balloon PCI设备

virtio balloon PCI设备的定义在hw/virtio/virtio-balloon-pci.c中,代码如下:

  1. static const VirtioPCIDeviceTypeInfo virtio_balloon_pci_info = {
  2. .base_name = TYPE_VIRTIO_BALLOON_PCI,
  3. .generic_name = "virtio-balloon-pci",
  4. .transitional_name = "virtio-balloon-pci-transitional",
  5. .non_transitional_name = "virtio-balloon-pci-non-transitional",
  6. .instance_size = sizeof(VirtIOBalloonPCI),
  7. .instance_init = virtio_balloon_pci_instance_init,
  8. .class_init = virtio_balloon_pci_class_init,
  9. };
  10. static void virtio_balloon_pci_register(void)
  11. {
  12. virtio_pci_types_register(&virtio_balloon_pci_info);
  13. }
  14. type_init(virtio_balloon_pci_register)
  • virtual balloon设备

virtual balloon设备的定义在hw/virtio/virtio-balloon.c中,代码如下:

  1. static const TypeInfo virtio_balloon_info = {
  2. .name = TYPE_VIRTIO_BALLOON,
  3. .parent = TYPE_VIRTIO_DEVICE,
  4. .instance_size = sizeof(VirtIOBalloon),
  5. .instance_init = virtio_balloon_instance_init,
  6. .class_init = virtio_balloon_class_init,
  7. };
  8. static void virtio_register_types(void)
  9. {
  10. type_register_static(&virtio_balloon_info);
  11. }
  12. type_init(virtio_register_types)

创建virtio balloon设备时只需要创建其PCI代理设备(即TYPE_VIRTIO_BALOON_PCI)即可,在命令行指定“-device virtio-balloon-pci”。先来看实例化函数virtio_balloon_pci_instance_init,其在hw/virtio/virtio-balloon-pci.c中(就在virtio_balloon_pci_info的定义上边),代码如下:

  1. static void virtio_balloon_pci_instance_init(Object *obj)
  2. {
  3. VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
  4. virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
  5. TYPE_VIRTIO_BALLOON);
  6. object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev),
  7. "guest-stats");
  8. object_property_add_alias(obj, "guest-stats-polling-interval",
  9. OBJECT(&dev->vdev),
  10. "guest-stats-polling-interval");
  11. }

TYPE_VIRTIO_BALLOON_PCI的实例化函数是virtio_balloon_pci_instance_init,在该函数中会调用virtio_instance_init_common,并将VirtIOBalloonPCI结构体的vdev成员地址以及TYPE_VIRTIO_BALLOON作为参数传递给该函数。

virtio_instance_init_common函数在hw/virtio/virtio.c中,代码如下:

  1. void virtio_instance_init_common(Object *proxy_obj, void *data,
  2. size_t vdev_size, const char *vdev_name)
  3. {
  4. DeviceState *vdev = data;
  5. object_initialize_child_with_props(proxy_obj, "virtio-backend", vdev,
  6. vdev_size, vdev_name, &error_abort,
  7. NULL);
  8. qdev_alias_all_properties(vdev, proxy_obj);
  9. }

object_initialize_child_with_props函数在qom/object.c中,代码如下:

  1. bool object_initialize_child_with_props(Object *parentobj,
  2. const char *propname,
  3. void *childobj, size_t size,
  4. const char *type,
  5. Error **errp, ...)
  6. {
  7. va_list vargs;
  8. bool ok;
  9. va_start(vargs, errp);
  10. ok = object_initialize_child_with_propsv(parentobj, propname,
  11. childobj, size, type, errp,
  12. vargs);
  13. va_end(vargs);
  14. return ok;
  15. }

object_initialize_child_with_propsv函数在同文件中(就在下边),代码如下:

  1. bool object_initialize_child_with_propsv(Object *parentobj,
  2. const char *propname,
  3. void *childobj, size_t size,
  4. const char *type,
  5. Error **errp, va_list vargs)
  6. {
  7. bool ok = false;
  8. Object *obj;
  9. UserCreatable *uc;
  10. object_initialize(childobj, size, type);
  11. obj = OBJECT(childobj);
  12. if (!object_set_propv(obj, errp, vargs)) {
  13. goto out;
  14. }
  15. object_property_add_child(parentobj, propname, obj);
  16. uc = (UserCreatable *)object_dynamic_cast(obj, TYPE_USER_CREATABLE);
  17. if (uc) {
  18. if (!user_creatable_complete(uc, errp)) {
  19. object_unparent(obj);
  20. goto out;
  21. }
  22. }
  23. ok = true;
  24. out:
  25. /*
  26. * We want @obj's reference to be 1 on success, 0 on failure.
  27. * On success, it's 2: one taken by object_initialize(), and one
  28. * by object_property_add_child().
  29. * On failure in object_initialize() or earlier, it's 1.
  30. * On failure afterwards, it's also 1: object_unparent() releases
  31. * the reference taken by object_property_add_child().
  32. */
  33. object_unref(obj);
  34. return ok;
  35. }

由代码可知,virtio_instance_init_common函数经过virtio_instance_init_common() -> object_initialize_child_with_props() -> object_initialize_child_with_propsv(),最终会调用object_initialize函数初始化TYPE_VIRTIO_BALLOON的实例对象VirtIOBalloon,并添加一些属性。由此可见,virtio设备在实例创建过程中并没有做很多事情,大部分的工作是在设备的具现化过程中做的。

在本回结束前,仍然要重点看一下object_initialize_child_with_props函数的说明,在include/qom/object.h中,如下:

  1. /**
  2. * object_initialize_child_with_props:
  3. * @parentobj: The parent object to add a property to
  4. * @propname: The name of the property
  5. * @childobj: A pointer to the memory to be used for the object.
  6. * @size: The maximum size available at @childobj for the object.
  7. * @type: The name of the type of the object to instantiate.
  8. * @errp: If an error occurs, a pointer to an area to store the error
  9. * @...: list of property names and values
  10. *
  11. * This function will initialize an object. The memory for the object should
  12. * have already been allocated. The object will then be added as child property
  13. * to a parent with object_property_add_child() function. The returned object
  14. * has a reference count of 1 (for the "child<...>" property from the parent),
  15. * so the object will be finalized automatically when the parent gets removed.
  16. *
  17. * The variadic parameters are a list of pairs of (propname, propvalue)
  18. * strings. The propname of %NULL indicates the end of the property list.
  19. * If the object implements the user creatable interface, the object will
  20. * be marked complete once all the properties have been processed.
  21. *
  22. * Returns: %true on success, %false on failure.
  23. */
  24. bool object_initialize_child_with_props(Object *parentobj,
  25. const char *propname,
  26. void *childobj, size_t size, const char *type,
  27. Error **errp, ...) G_GNUC_NULL_TERMINATED;

object_initialize_child_with_props:

参数:

parentobj:要向其中添加属性的父对象。

propname:属性名称。

childobj:指向要用于对象的内存的指针。

size:childobj参数可用于对象的最大大小。

type:要实例化的对象的类型的名称。

errp:如果发生错误,则是一个指向存储错误的区域的指针。

...:属性名称和值得列表。

此函数将初始化一个对象。应该已经为对象分配了内存。然后,该对象将作为子属性添加到具有object_property_add_child()函数的父对象中。返回的对象的引用计数为1(对于父对象的“child<…>”属性),因此,当父对象被移除时,该对象将自动完成。

可变参数是一对(propname,propvalue)字符串的列表。属性名为NULL则表示属性列表的末尾。如果该对象实现了用户可创建的接口,则在处理完所有属性后,该对象将被标记为完成。

返回值:

成功时为true,失败时为false。

预知后事如何,且看下回分解。

举报

选择你想要举报的内容(必选)
  • 内容涉黄
  • 政治相关
  • 内容抄袭
  • 涉嫌广告
  • 内容侵权
  • 侮辱谩骂
  • 样式问题
  • 其他