NVME源码流程解析(一)

2022-12-15 0 271

1、源代码产品目录

源代码在drivers/nvme上面,有三个实用性文件,当中targets 实用性文件用作将nvme 电子设备做为

硬盘求出供内部采用,host实用性文件同时实现将nvme 电子设备八版控制系统采用。若实用性NVME target 还

须要辅助工具nvmetcli辅助工具。

2、/drivers/nvme/host/Makefile

组件校对的四个实用性模块:

NVME_CORE:nvme的核心理念此基础

BLK_DEV_NVME:用作将ssd镜像到pcie上

CONFIG_NVME_FABRICS:全力支持FC协定

CONFIG_NVME_RDMA:使 NVMe over Fabric 能透过 RDMA 数据传输

CONFIG_NVME_FC:使NVMe over Fabric能在FC 数据传输

3、/drivers/nvme/host/pci.c

nvme驱动力的注册登记和已过期——总体表达式业务流程如下表右图斑蛛属右图:

NVME源码流程解析(一)

当中nvme_init表达式最后会初始化到nvme_probe,其内部结构如下表右图:

NVME源码流程解析(一)

图片能放大来看!主要记录了关键表达式之间的初始化关系!

(1)驱动力的注册登记和已过期:

module_init(nvme_init); module_exit(nvme_exit);

(2)初始化 pci_register_driver()注册登记时,其模块为 struct pci_driver.

static structpci_driver nvme_driver = { .name =“nvme”, .id_table = nvme_id_table, .probe = nvme_probe, .remove= nvme_remove, .shutdown = nvme_shutdown,#ifdef CONFIG_PM_SLEEP .driver = { .pm = &nvme_dev_pm_ops, }, #endif.sriov_configure = pci_sriov_configure_simple, .err_handler = &nvme_err_handler, };

(3) /drivers/pci/pci-driver.c

/** * __pci_register_driver – register a new pci driver * @drv: the driver structure to register * @owner: owner module of drv * @mod_name: module name string * * Adds the driver structure to the list of registered drivers. * Returns a negative value on error, otherwise 0. * If no error occurred, the driver remains registered even if * no device was claimed during registration. */int __pci_register_driver(struct pci_driver *drv, struct module *owner, const char *mod_name) { /* initialize common driver fields */ drv->driver.name = drv->name; drv->driver.bus = &pci_bus_type; //pci_bus_type是个结构体————struct bus_type pci_bus_typedrv->driver.owner = owner; drv->driver.mod_name = mod_name; drv->driver.groups = drv->groups; spin_lock_init(&drv->dynids.lock); INIT_LIST_HEAD(&drv->dynids.list);//初始化电子设备中的节点 /* register with core */ return driver_register(&drv->driver); }

(4)接下来看看driver_register(&drv->driver)表达式 —— /drivers/base/driver.c

/** * driver_register – register driver with bus * @drv: driver to register * * We pass off most of the work to the bus_add_driver() call, * since most of the things we have to do deal with the bus * structures. */ int driver_register(struct device_driver *drv) { int ret; struct device_driver*other;if (!drv->bus->p) { pr_err(“Driver %s was unable to register with bus_type %s because the bus was not initialized.\n”, drv->name, drv->bus->name); return -EINVAL; } if((drv->bus->probe && drv->probe) || (drv->bus->remove && drv->remove) || (drv->bus->shutdown && drv->shutdown)) printk(KERN_WARNING“Driver %s needs updating – please use “ “bus_type methods\n”, drv->name); other = driver_find(drv->name, drv->bus);//寻找是否已注册登记同名驱动力 if (other) { printk(KERN_ERR “Error: Driver %s is already registered, “ “aborting…\n”, drv->name); return-EBUSY; } ret = bus_add_driver(drv);//真正将驱动力电子设备添加到总线中的地方 if (ret) return ret; ret = driver_add_groups(drv, drv->groups); //透过sysfs_create_groups表达式创建NVME驱动力的属性组 if (ret) { bus_remove_driver(drv); returnret; } kobject_uevent(&drv->p->kobj, KOBJ_ADD);//通知用户驱动力加载成功 return ret; }

(5) 真正加载驱动力的表达式是bus_add_driver(drv) —— /drivers/base/bus.c

/** * bus_add_driver – Add a driver to the bus. * @drv: driver. */int bus_add_driver(struct device_driver *drv) { struct bus_type *bus; struct driver_private *priv; int error =0; bus = bus_get(drv->bus); if (!bus) return -EINVAL; pr_debug(“bus: %s: add driver %s\n”, bus->name, drv->name); priv = kzalloc(sizeof(*priv), GFP_KERNEL); //分配空间 if (!priv) { error = -ENOMEM; goto out_put_bus; } klist_init(&priv->klist_devices, NULL, NULL); //初始化列表 priv->driver = drv; drv->p = priv; priv->kobj.kset = bus->p->drivers_kset; error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, “%s”, drv->name); //初始化一个kobject结构体,并加入到kobject架构中 if(error) goto out_unregister; klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); //将priv->knode_bus添加到总线的subsys_private->klist_drivers链表中 if(drv->bus->p->drivers_autoprobe) { error = driver_attach(drv);//初始化bus_for_each_dev负责在总线上遍历电子设备,并将电子设备传递给表达式,会初始化__driver_attach进行电子设备和驱动力的匹配 if(error) goto out_unregister; } module_add_driver(drv->owner, drv); /* 该表达式主要同时实现是sysfs_create_link 在sysfs文件控制系统中创建相关文件。 sysfs_create_link(&drv->p->kobj, &mk->kobj,“module”); sysfs_create_link(mk->drivers_dir, &drv->p->kobj, driver_name); 第一个 sysfs_create_link 初始化在/sys/bus/pci/drivers/nvme 中创建 module 指向 /sys/module/nvme,第二个 sysfs_create_link 在产品目录/sys/module/nvme/drivers 中创建 pci:nvme 镜像,指向/sys/bus/pci/drivers/nvme 驱动力。 */ error = driver_create_file(drv, &driver_attr_uevent);//过 sysfs_create_file 表达式,sysfs_create_file(&drv->p->kobj,&attr->attr),在/sys/bus/pci/drivers/nvme中创建驱动力的属性文件 if (error) { printk(KERN_ERR “%s: uevent attr (%s) failed\n”, __func__, drv->name); } error = driver_add_groups(drv, bus->drv_groups);//透过sysfs_create_groups表达式创建总线中驱动力的属性组 if(error) {/* How the hell do we get out of this pickle? Give up */ printk(KERN_ERR “%s: driver_create_groups(%s) failed\n”, __func__, drv->name); } if(!drv->suppress_bind_attrs) { error = add_bind_files(drv);//创建绑定的属性文件 if (error) { /* Ditto */ printk(KERN_ERR “%s: add_bind_files(%s) failed\n”, __func__, drv->name); } }return 0; out_unregister: kobject_put(&priv->kobj); /* drv->p is freed in driver_release() */ drv->p = NULL; out_put_bus: bus_put(bus); return error; }

当中最重要的表达式是driver_attach(drv),其会负责进行电子设备和驱动力的匹配,该表达式留到下一小节来讲!

原文镜像:

https://blog.csdn.net/weixin_38

更多DPDK/SPDK LinuxC++后台开发 面试题、学习资料、教学视频和学习路线图

免费分享 有须要的能后台私信我 输入数字 0 即可 !

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务