当前位置: 首页 > news >正文

一个网站 两个域名在线教学的网站开发方案

一个网站 两个域名,在线教学的网站开发方案,网站上线确认书,个人执业资格注册查询内核版本较低的nvme驱动代码不多#xff0c;而且使用的是单队列的架构#xff0c;阅读起来会轻松一点。 这个版本涉及到的nvme驱动源码文件一共就4个#xff0c;两个nvme.h文件#xff0c;分别在include/linux ,include/uapi/linux目录下#xff0c;nvme-core.c是主要源码…内核版本较低的nvme驱动代码不多而且使用的是单队列的架构阅读起来会轻松一点。 这个版本涉及到的nvme驱动源码文件一共就4个两个nvme.h文件分别在include/linux ,include/uapi/linux目录下nvme-core.c是主要源码文件还有nvme-scsi.c这个文件是scsi协议转nvme协议的。 先从模块入口函数开始吧。 static int __init nvme_init(void) {int result;nvme_thread kthread_run(nvme_kthread, NULL, nvme);//创建内核线程并开始运行if (IS_ERR(nvme_thread))return PTR_ERR(nvme_thread);result register_blkdev(nvme_major, nvme);//块设备驱动注册得到主设备号if (result 0)goto kill_kthread;else if (result 0)nvme_major result;//返回的主设备号result pci_register_driver(nvme_driver);//注册pci驱动if (result)goto unregister_blkdev;return 0; unregister_blkdev:unregister_blkdev(nvme_major, nvme); kill_kthread:kthread_stop(nvme_thread);//停止内核线程的运行return result; }static void __exit nvme_exit(void) {pci_unregister_driver(nvme_driver);unregister_blkdev(nvme_major, nvme);kthread_stop(nvme_thread);//nvme_thread内核线程停止运行 }MODULE_AUTHOR(Matthew Wilcox willylinux.intel.com); MODULE_LICENSE(GPL); MODULE_VERSION(0.8); module_init(nvme_init); module_exit(nvme_exit);模块入口函数主要干了三件事。 1创建了一个内核线程主要作用是处理不满足prp条件时队列函数提交的bio这个后面在详细说。 2注册了一个块设备驱动作用是得到了一个主设备号后面是需要这个设备号的。 3注册了pci驱动作用大家都知道的。 模块退出函数与模块入口函数做的事情刚好相反也没什么说的。 接着看probe函数 static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) {int result -ENOMEM;struct nvme_dev *dev;dev kzalloc(sizeof(*dev), GFP_KERNEL);if (!dev)return -ENOMEM;/*后续保存中断向量的信息*/dev-entry kcalloc(num_possible_cpus(), sizeof(*dev-entry), GFP_KERNEL);if (!dev-entry)goto free;//queue[0] queue[1]存放的是指针dev-queues kcalloc(num_possible_cpus() 1, sizeof(void *), GFP_KERNEL); //sizeof(void *) 8 or 4if (!dev-queues)goto free;INIT_LIST_HEAD(dev-namespaces);//初始化链表头后续将nvme的namespaces以链表的形式链接起来dev-pci_dev pdev;result nvme_set_instance(dev);//获取一个instance值,用于后面的磁盘名称命名if (result)goto free;result nvme_setup_prp_pools(dev);//prp地址的申请即prp list,后续用来保存bio转换出来的dma地址if (result)goto release;result nvme_dev_start(dev);//admin queue 和 io queu的配置if (result) {if (result -EBUSY)goto create_cdev;goto release_pools;}result nvme_dev_add(dev); //和内核块设备提供的函数操作有关if (result)goto shutdown; create_cdev://利用miscdev结构体提供一些字符设备的操作(回调函数)用户空间可以下发一些nvme的命令等scnprintf(dev-name, sizeof(dev-name), nvme%d, dev-instance);dev-miscdev.minor MISC_DYNAMIC_MINOR;dev-miscdev.parent pdev-dev;dev-miscdev.name dev-name;dev-miscdev.fops nvme_dev_fops;result misc_register(dev-miscdev);if (result)goto remove;kref_init(dev-kref);//设备引用计数初始化值为1return 0; remove:nvme_dev_remove(dev); shutdown:nvme_dev_shutdown(dev); release_pools:nvme_free_queues(dev);nvme_release_prp_pools(dev); release:nvme_release_instance(dev); free:kfree(dev-queues);kfree(dev-entry);kfree(dev);return result; }static void nvme_remove(struct pci_dev *pdev) {struct nvme_dev *dev pci_get_drvdata(pdev);misc_deregister(dev-miscdev);//引用计数为0调用nvme_free_dev函数kref_put(dev-kref, nvme_free_dev); }static DEFINE_PCI_DEVICE_TABLE(nvme_id_table) {{ PCI_DEVICE_CLASS(0x010802, 0xffffff) }, //class满足0x010802就会调用probe函数{ 0,} }; MODULE_DEVICE_TABLE(pci, nvme_id_table); static struct pci_driver nvme_driver {.name nvme,.id_table nvme_id_table,.probe nvme_probe,.remove nvme_remove, };struct nvme_dev结构体定义 struct nvme_dev {struct list_head node;struct nvme_queue **queues;u32 __iomem *dbs;struct pci_dev *pci_dev;struct dma_pool *prp_page_pool;struct dma_pool *prp_small_pool;int instance;int queue_count;int db_stride;u32 ctrl_config;struct msix_entry *entry;struct nvme_bar __iomem *bar;struct list_head namespaces;struct kref kref;struct miscdevice miscdev;char name[12];char serial[20];char model[40];char firmware_rev[8];u32 max_hw_sectors;u32 stripe_size;u16 oncs; };总结下probe函数干的事情 1struct nvme_dev *dev 申请内存这个结构体就代表一个nvme设备。 2dev-entry申请内存大小是num_possible_cpus() * sizeof(*dev-entry)后面用于保存向量的相关信息因为nvme是支持多队列的所以后面可以将队列和特定的中断向量进行绑定这个后面遇到相关代码再说。至于num_possible_cpus()的值是多少什么意思也不用研究那么多主要知道它是一个数值就行了比如是4. 3dev-queues这个是一个二级指针所以它是保存一级指针的值也就是保存的是struct nvme_queue的地址上面代码也进行了注释。 4namespaces的初始化以及dev-pci_dev pdev赋值 5nvme_set_instance函数的调用里面怎么实现的不用管主要知道调用完它以后dev-instance得到一个值就行了这个值用于磁盘的命名比如在dev目录下看到的/dev/nvmexxx就和这个值有关系。 5nvme_setup_prp_pools函数调用主要就是申请一大块内存然后用于保存prp的地址。 它的函数实现如下 static int nvme_setup_prp_pools(struct nvme_dev *dev)//放prp指针 {struct device *dmadev dev-pci_dev-dev;dev-prp_page_pool dma_pool_create(prp list page, dmadev, PAGE_SIZE, PAGE_SIZE, 0);if (!dev-prp_page_pool)return -ENOMEM;dev-prp_small_pool dma_pool_create(prp list 256, dmadev, 256, 256, 0); //Optimisation for I/Os between 4k and 128kif (!dev-prp_small_pool) {dma_pool_destroy(dev-prp_page_pool);return -ENOMEM;}return 0; }只需要知道调用结束以后dev-prp_page_pool和dev-prp_small_pool不是空就行了后面用到的时候再解释为什么这里需要两个值。 6调用nvme_dev_start 7调用nvme_dev_add 8利用miscdev做一些用户层可以用ioctl下发一些操作。 其中678是重点后面会逐一分析。 remove函数就不用多说了模块退出时资源的释放。 先聊这么多。
http://www.pierceye.com/news/689618/

相关文章:

  • 室内设计网站网站建设中请稍后再访问
  • 十堰网站开发培训编程软件手机
  • 南京网站优化推广微网站缺点
  • 大连零基础网站建设培训哪里有固安县建设局网站
  • 怎么制作网站首页培训心得体会总结简短
  • 商务网站建设 模板长春高端品牌网站建设
  • 做网站比较便宜办公资源网
  • 公司怎么做网页网站遵义网站设计公司
  • 网站建设毕业设计yy直播回放
  • 响应式网站有哪些2017淮南网络推广报价
  • 兰州公司网站建设网站建设筹备方案
  • 租房网站建设做一个跨境电商网站
  • 网站设计制作过程容桂做pc端网站
  • 宜昌市上海中学官网seo文章外包
  • 加强普法网站建设的通知制作婚恋网站
  • 北大荒建设集团有限公司网站网站添加在线qq聊天
  • 网站首页被k咋办上海市企业服务云登录
  • 长安镇网站建设公司大网站制作公司
  • 衡水做网站推广找谁廊坊百度推广排名优化
  • 网站建设毕业报告wordpress微信登录页面
  • 外包网站建设费用包括网站备份crm系统有哪些
  • 高端网站设计推广v信haotg8wordpress 付费后查看
  • cms管理手机网站长春做网站好的公司
  • 可信网站认证 技术支持单位沈阳又一烂尾项目复工
  • 南昌网站建设培训学校做幼儿网站的目标
  • 装饰网站建设的背景怎么做原创动漫视频网站
  • 电脑购物网站模板c2c商城网站建设二次开发
  • 自建站有哪些dz论坛网站源码
  • 湖南湘源建设工程有限公司网站牛商网网站做seo好么
  • 郑州网站制作建设南宁网站设计要多少钱