• 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。

  • 相关阅读:
    2014 非常好用的开源 Android 测试工具
    Android 开发最佳实践
    Java_综合案例DAO设计模式(重要)
    Java_Set接口
    Java_List
    Java_类集框架简介
    Java_对象序列化
    Java_打印流
    Java_IO编程
    Java_文件操作
  • 原文地址:https://www.cnblogs.com/powerrailgun/p/13845548.html
Copyright © 2020-2023  润新知