• SPDK/NVMe存储技术分析之SSD设备的发现(二)


    接下来重点看看L647对应的函数spck_pci_nvme_enumerate()就好,因为我们的目标是看明白是如何利用Class Code发现SSD设备的。

    647         return spdk_pci_nvme_enumerate(pcie_nvme_enum_cb, &enum_ctx);
    1. /* src/spdk-17.07.1/lib/env_dpdk/pci_nvme.c */
    2. 81 int
    3. 82 spdk_pci_nvme_enumerate(spdk_pci_enum_cb enum_cb, void *enum_ctx)
    4. 83 {
    5. 84 return spdk_pci_enumerate(&g_nvme_pci_drv, enum_cb, enum_ctx);
    6. 85 }

    注意: L84第一个参数为一个全局变量g_nvme_pci_drv的地址

    1. /* src/spdk-17.07.1/lib/env_dpdk/pci_nvme.c */
    2. 38 static struct rte_pci_id nvme_pci_driver_id[] = {
    3. 39 #if RTE_VERSION >= RTE_VERSION_NUM(16, 7, 0, 1)
    4. 40 {
    5. 41 .class_id = SPDK_PCI_CLASS_NVME,
    6. 42 .vendor_id = PCI_ANY_ID,
    7. 43 .device_id = PCI_ANY_ID,
    8. 44 .subsystem_vendor_id = PCI_ANY_ID,
    9. 45 .subsystem_device_id = PCI_ANY_ID,
    10. 46 },
    11. 47 #else
    12. 48 {RTE_PCI_DEVICE(0x8086, 0x0953)},
    13. 49 #endif
    14. 50 { .vendor_id = 0, /* sentinel */ },
    15. 51 };
    16. ..
    17. 53 static struct spdk_pci_enum_ctx g_nvme_pci_drv = {
    18. 54 .driver = {
    19. 55 .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
    20. 56 .id_table = nvme_pci_driver_id,
    21. ..
    22. 66 },
    23. 67
    24. 68 .cb_fn = NULL,
    25. 69 .cb_arg = NULL,
    26. 70 .mtx = PTHREAD_MUTEX_INITIALIZER,
    27. 71 .is_registered = false,
    28. 72 };

    终于跟Class Code (SPDK_PCI_CLASS_NVME=0x010802)扯上了关系。 全局变量g_nvme_pci_drv就是在L53行定义的,而g_nvme_pci_drv.driver.id_table则是在L38行定义的。

    1. 38 static struct rte_pci_id nvme_pci_driver_id[] = {
    2. ..
    3. 41 .class_id = SPDK_PCI_CLASS_NVME,
    4. ..
    5. 53 static struct spdk_pci_enum_ctx g_nvme_pci_drv = {
    6. 54 .driver = {
    7. ..
    8. 56 .id_table = nvme_pci_driver_id,
    9. ..

    那么,我们只需要进一步深挖spdk_pci_enumerate()就可以找到SSD设备是如何被发现的了...

    1. /* src/spdk-17.07.1/lib/env_dpdk/pci.c#150 */
    2. 149 int
    3. 150 spdk_pci_enumerate(struct spdk_pci_enum_ctx *ctx,
    4. 151 spdk_pci_enum_cb enum_cb,
    5. 152 void *enum_ctx)
    6. 153 {
    7. ...
    8. 168
    9. 169 #if RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 4)
    10. 170 if (rte_pci_probe() != 0) {
    11. 171 #else
    12. 172 if (rte_eal_pci_probe() != 0) {
    13. 173 #endif
    14. ...
    15. 184 return 0;
    16. 185 }

    省略了一些代码,我们接下来重点关注L170,

    170     if (rte_pci_probe() != 0) {
      

    从rte_pci_probe()函数的实现开始,我们就深入到DPDK的内部了,代码如下,

    1. /* src/dpdk-17.08/lib/librte_eal/common/eal_common_pci.c#413 */
    2. 407 /*
    3. 408 * Scan the content of the PCI bus, and call the probe() function for
    4. 409 * all registered drivers that have a matching entry in its id_table
    5. 410 * for discovered devices.
    6. 411 */
    7. 412 int
    8. 413 rte_pci_probe(void)
    9. 414 {
    10. 415 struct rte_pci_device *dev = NULL;
    11. 416 size_t probed = 0, failed = 0;
    12. 41
  • 相关阅读:
    中国石油大学《高等数学二》第三次在线作业
    从JDK8到JDK17的新特性
    数据传输功能单元——DID参数定义
    dnslog注入_dnslog盲注
    内存优化:Boxing
    代码随想录 贪心算法-简单题目
    SQLAlchemy删除所有重复的用户|Counter类运用
    Golang 开源库分享:anko - 给 Go 加点“脚本魔法”
    2022年7月国产数据库大事记-墨天轮
    对象 和 json 互转 四种方式 json-lib、Gson、FastJson、Jackson
  • 原文地址:https://blog.csdn.net/lingshengxiyou/article/details/126440966