virtio 块设备realize流程分析

(gdb) bt
#0  virtio_blk_device_realize (dev=0x5555579b8080, errp=0x7fffffffd5f0) at /home/user/data/qemu/hw/block/virtio-blk.c:1115
#1  0x000055555592c29c in virtio_device_realize (dev=0x5555579b8080, errp=0x7fffffffd650) at /home/user/data/qemu/hw/virtio/virtio.c:3504
#2  0x0000555555aa9a93 in device_set_realized (obj=0x5555579b8080, value=true, errp=0x7fffffffd888) at hw/core/qdev.c:876
#3  0x0000555555ccec63 in property_set_bool (obj=0x5555579b8080, v=0x5555579c3b10, name=0x555555f520fa "realized", opaque=0x5555579b96b0,
    errp=0x7fffffffd888) at qom/object.c:2080
#4  0x0000555555cccecd in object_property_set (obj=0x5555579b8080, v=0x5555579c3b10, name=0x555555f520fa "realized", errp=0x7fffffffd888)
    at qom/object.c:1272
#5  0x0000555555ccffd8 in object_property_set_qobject (obj=0x5555579b8080, value=0x5555579c3a60, name=0x555555f520fa "realized", errp=0x7fffffffd888)
    at qom/qom-qobject.c:26
#6  0x0000555555ccd1ab in object_property_set_bool (obj=0x5555579b8080, value=true, name=0x555555f520fa "realized", errp=0x7fffffffd888)
    at qom/object.c:1338
#7  0x0000555555941c9e in virtio_blk_pci_realize (vpci_dev=0x5555579aff10, errp=0x7fffffffd888)
    at /home/user/data/qemu/hw/virtio/virtio-blk-pci.c:59
#8  0x0000555555c1f9c0 in virtio_pci_realize (pci_dev=0x5555579aff10, errp=0x7fffffffd888) at hw/virtio/virtio-pci.c:1801
#9  0x0000555555b7b476 in pci_qdev_realize (qdev=0x5555579aff10, errp=0x7fffffffd940) at hw/pci/pci.c:2099
#10 0x0000555555c1fd74 in virtio_pci_dc_realize (qdev=0x5555579aff10, errp=0x7fffffffd940) at hw/virtio/virtio-pci.c:1874
#11 0x0000555555aa9a93 in device_set_realized (obj=0x5555579aff10, value=true, errp=0x7fffffffdb20) at hw/core/qdev.c:876
#12 0x0000555555ccec63 in property_set_bool (obj=0x5555579aff10, v=0x5555579bde20, name=0x555555f72c22 "realized", opaque=0x555557895900,
    errp=0x7fffffffdb20) at qom/object.c:2080
#13 0x0000555555cccecd in object_property_set (obj=0x5555579aff10, v=0x5555579bde20, name=0x555555f72c22 "realized", errp=0x7fffffffdb20)
    at qom/object.c:1272
#14 0x0000555555ccffd8 in object_property_set_qobject (obj=0x5555579aff10, value=0x5555579bbab0, name=0x555555f72c22 "realized", errp=0x7fffffffdb20)
    at qom/qom-qobject.c:26
#15 0x0000555555ccd1ab in object_property_set_bool (obj=0x5555579aff10, value=true, name=0x555555f72c22 "realized", errp=0x7fffffffdb20)
    at qom/object.c:1338
#16 0x0000555555a0f10d in qdev_device_add (opts=0x5555568f7f00, errp=0x55555687d2f0 <error_fatal>) at qdev-monitor.c:673
#17 0x0000555555a17774 in device_init_func (opaque=0x0, opts=0x5555568f7f00, errp=0x55555687d2f0 <error_fatal>) at vl.c:2210
#18 0x0000555555e34ec9 in qemu_opts_foreach (list=0x5555566c82c0 <qemu_device_opts>, func=0x555555a1774d <device_init_func>, opaque=0x0,
    errp=0x55555687d2f0 <error_fatal>) at util/qemu-option.c:1170
#19 0x0000555555a1c62a in main (argc=38, argv=0x7fffffffdf28, envp=0x7fffffffe060) at vl.c:4370

流程图:

上述流程很长,涉及到的面很多(设备QOM,QOM属性,内存管理等)。所以以这个为线索可以串起QEMU的核心知识,后续逐步完善分析。

问题1:如何从virtio_blk_pci_realize 这里调用到virtio_device_realize 这里的?
即就是上述流程图从13如何到19的?
解释:
设置realize函数都是在class_init函数里面。
注意在对象初始化函数中(这个函数是在object_new()被调用的):

77 static void virtio_blk_pci_instance_init(Object *obj)
 78 {
 79     VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
 80
 81     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
 82                                 TYPE_VIRTIO_BLK);
 83     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
 84                               "bootindex", &error_abort);
 85 }

这个函数中,调用了virtio_instance_init_common()函数,TYPE_VIRTIO_BLK是一个字符串:"virtio-blk-device",进入这个函数:

void virtio_instance_init_common(Object *proxy_obj, void *data,
                                 size_t vdev_size, const char *vdev_name)
{
    DeviceState *vdev = data;

    object_initialize_child(proxy_obj, "virtio-backend", vdev, vdev_size,
                            vdev_name, &error_abort, NULL);
    qdev_alias_all_properties(vdev, proxy_obj);
}

可以看到这里调用了object_initialize_child()函数,这个函数以vdev_name作为名字,查找该名字对应的设备Ojbect。通过上述调用关系,就可以将virtio-blk-device对象放到VirtIOBlkPCI *dev的vdev域中。
一开始的问题1就可以得到解释:

static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
{
    VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
    DeviceState *vdev = DEVICE(&dev->vdev);

    .............
    object_property_set_bool(OBJECT(vdev), true, "realized", errp);
}

通过上述流程,vdev已经得到了正确的realize函数,通过object_property_set_bool()流程就可以realize,调用的realize函数正是virtio_device_realize。
而virtio_device_realize就可以继续调用到vdc->realize,vdc就是该设备对象对应的类:TYPE_VIRTIO_BLK,其realize函数就是:virtio_blk_device_realize。

原文地址:https://www.cnblogs.com/powerrailgun/p/13845548.html