首页 > 其他分享 >chrdev_open --- 通过文件路径,执行驱动设置的open()流程

chrdev_open --- 通过文件路径,执行驱动设置的open()流程

时间:2023-04-01 16:46:49浏览次数:48  
标签:chrdev fops struct -- inode --- cdev open

open一个字符设备的流程大概是:文件路径 => inode => chrdev_open() => (kobj_lookup=>) inode.i_cdev => cdev.fops.my_chr_open()。所以只要通过VFS找到了inode,就可以找到chrdev_open(),这里我们就来关注一个chrdev_open()是怎么从内核的数据结构中找到我们的cdev并执行其中的my_chr_open()的。虽然我们有了字符设备的设备文件,inode也被构造并初始化了, 但是在第一次调用chrdev_open()之前,这个inode和具体的chr_dev对象并没有直接关系,而只是通过设备号建立的"间接"关系。在第一次调用chrdev_open()之后, inode->i_cdev才根据设备号找到的cdev对象被赋值,此后inode才和具体的cdev对象直接联系在了一起。

 1 static int chrdev_open(struct inode *inode, struct file *filp)
 2 {
 3     const struct file_operations *fops;
 4     struct cdev *p;
 5     struct cdev *new = NULL;
 6     int ret = 0;
 7 
 8     spin_lock(&cdev_lock);
 9     p = inode->i_cdev;
10     if (!p) {
11         struct kobject *kobj;
12         int idx;
13         spin_unlock(&cdev_lock);
14         kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);
15         if (!kobj)
16             return -ENXIO;
17         new = container_of(kobj, struct cdev, kobj);
18         spin_lock(&cdev_lock);
19         /* Check i_cdev again in case somebody beat us to it while
20            we dropped the lock. */
21         p = inode->i_cdev;
22         if (!p) {
23             inode->i_cdev = p = new;
24             list_add(&inode->i_devices, &p->list);
25             new = NULL;
26         } else if (!cdev_get(p))
27             ret = -ENXIO;
28     } else if (!cdev_get(p))
29         ret = -ENXIO;
30     spin_unlock(&cdev_lock);
31     cdev_put(new);
32     if (ret)
33         return ret;
34 
35     ret = -ENXIO;
36     fops = fops_get(p->ops);
37     if (!fops)
38         goto out_cdev_put;
39 
40     replace_fops(filp, fops);
41     if (filp->f_op->open) {
42         ret = filp->f_op->open(inode, filp);
43         if (ret)
44             goto out_cdev_put;
45     }
46 
47     return 0;
48 
49  out_cdev_put:
50     cdev_put(p);
51     return ret;
52 }

--  9-->将inode->i_cdev(一个cdev结构指针)保存在局部变量p中,
--10-->如果p为空,即inode->i_cdev为空,
--14-->根据inode->i_rdev(设备号)通过kobj_lookup()搜索cdev_map,并返回与之对应kobj
--23-->由于kobject是cdev的父类,我们根据container_of很容易找到相应的cdev结构并将其保存在inode->i_cdev中,
--24-->将inode->i_devices挂接到inode->i_cdev的管理链表中
--40-->找到了cdev结构,其中的操作方法集inode->i_cdev->ops传递给filp->f_ops
--42-->回调我们的设备打开函数my_chr_open(),如果我们没有实现自己的open接口,就什么都不做,也不是错

 1 void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
 2 {
 3     inode->i_mode = mode;
 4     if (S_ISCHR(mode)) {
 5         inode->i_fop = &def_chr_fops;
 6         inode->i_rdev = rdev;
 7     } else if (S_ISBLK(mode)) {
 8         inode->i_fop = &def_blk_fops;
 9         inode->i_rdev = rdev;
10     } else if (S_ISFIFO(mode))
11         inode->i_fop = &pipefifo_fops;
12     else if (S_ISSOCK(mode))
13         ;    /* leave it no_open_fops */
14     else
15         printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"
16                   " inode %s:%lu\n", mode, inode->i_sb->s_id,
17                   inode->i_ino);
18 }

 

1 const struct file_operations def_chr_fops = {
2     .open = chrdev_open,
3     .llseek = noop_llseek,
4 };

 Linux中几乎所有的"设备"都是"device"的子类,无论是平台设备还是i2c设备还是网络设备,但唯独字符设备不是,注册一个cdev对象到内核其实只是将它放到cdev_map中,当下cdev更合适的一种理解是一种接口,而不是而一个具体的设备,和platform_device,i2c_device有着本质的区别。

 

标签:chrdev,fops,struct,--,inode,---,cdev,open
From: https://www.cnblogs.com/god-of-death/p/17278831.html

相关文章

  • Ceres 自动求导解析-从原理到实践
    Ceres自动求导解析-从原理到实践目录Ceres自动求导解析-从原理到实践1.0前言2.0Ceres求导简介3.0Ceres自动求导原理3.1官方解释3.2自我理解4.0实践4.1Jet的实现4.2多项式函数自动求导4.3BA问题中的自动求导Reference1.0前言Ceres有一个自动求导功能,只要你按照C......
  • openfeign开启日志
    openfeign的日志级别有:NONE:默认,不开启日志BASIC:只记录请求方法和URL以及响应状态代码和执行时间HEADERS:记录基本信息以及请求和响应标头。FULL:记录请求和响应的标题、正文和元数据。  全局日志加入Logger.LevelBean:@ConfigurationpublicclassMyConfigration{......
  • 代码随想录Day17-Leetcode110.平衡二叉树,257. 二叉树的所有路径,404.左叶子之和
    110.平衡二叉树题目链接:https://leetcode.cn/problems/balanced-binary-tree/一个显然但似乎不太高效的方法是:通过递归获取左右子树高度,判断差;然后递归判断左右结点;那么一个显然的改进就是后序遍历/***Definitionforabinarytreenode.*functionTreeNode(val......
  • 例题3-1 TeX中的引号(Tex Quotes, UVa 272)
    题目在TeX中,左双引号是“``”,右双引号是“''”。输入一篇包含双引号的文章,你的任务是把它转换成TeX的格式。样例输入"Tobeornottobe,"quoththeBard,"thatisthequestion".样例输出``Tobeornottobe,''quoththeBard,``thatisthequestion''.思路依......
  • Qt学习笔记9——P30-33. 自定义控件封装,鼠标事件,定时器
    P30.自定义控件封装P31.Qt中的鼠标事件P32.定时器1P33.定时器2P30.自定义控件封装(创建了新项目) 添加新的界面和类:右键项目的文件夹(顶层的文件)->Qt——Qt设计师界面类->“选择界面模板”选"Widget"->在"Classname"中取个类名(此案例中改成了SmallWidget)->别的没......
  • JAVA-方法
    1.1方法的定义[修饰符列表] 返回值类型方法名(第一个首字母小写,后边单词大写)(形参列表){方法体};ps:方法遵循自上而下运行1.2方法调用类名.方法名(实参列表)方法调用时,压栈!结束时弹栈!先进后出!   1.2方法重载1.2.1定义......
  • linux操作系统实验四-以time/gettimeofday系统调用为例分析ARM64 Linux 5.4.34
    一、搭配环境(1)安装编译工具sudoapt-getinstallgcc-aarch64-linux-gnusudoapt-getinstalllibncurses5-dev build-essentialgitbisonflexlibssl-dev(2)制作根文件系统wget https://busybox.net/downloads/busybox-1.33.1.tar.bz2tar-xjfbusybox-1.33.1.tar.bz2......
  • dotnet-sharp 笔记(二)
    C#新特性泛型属性创建属性时可直接使用泛型//声明一个泛型属性publicclassGenericAttribute<T>:Attribute{}//使用[GenericAttribute<string>()]publicstringMethod()=>default;字符串内可插入换行符$"{\r\n}"原始字符串三个双引号开头并结尾,可以包含任......
  • XXL-Job与Elastic-Job详细对比
    1.失败处理策略失败处理策略XXL-JobElastic-Job失败重试支持,最多重试三次。重试时间间隔可配置。支持,最多重试十次。重试时间间隔可配置。失败告警支持,可配置告警接收人和方式。可通过邮件、短信等方式发送告警信息。支持,可配置告警接收人和方式。可通过邮件、......
  • npm install --legacy-peer-deps
    --legacy-peer-deps标志是在v7中引入的,目的是绕过peerDependency自动安装;它告诉NPM忽略项目中引入的各个modules之间的相同modules但不同版本的问题并继续安装,保证各个引入的依赖之间对自身所使用的不同版本modules共存。......