open 函数到底做了什么

使用设备之前我们通常都需要调用 open 函数,这个函数一般用于设备专有数据的初始化,申请相关资源及进行设备的初始化等工作,对于简单的设备而言,open 函数可以不做具体的工作,你在应用层通过系统调用 open 打开设备时,如果打开正常,就会得到该设备的文件描述符,之后,我们就可以通过该描述符对设备进行 read write 等操作; open 函数到底做了些什么工作?下图中列出了 open 函数执行的大致过程。
户空间使用 open() 系统调用函数打开一个字符设备时 (int fd = open( dev/xxx , O_RDWR)) 大致
有以下过程:
在虚拟文件系统 VFS 中的查找对应与字符设备对应 struct inode 节点
遍历散列表 cdev_map ,根据 inod 节点中的 cdev_t 设备号找到 cdev 对象
创建 struct file 对象(系统采用一个数组来管理一个进程中的多个被打开的设备,每个文件
秒速符作为数组下标标识了一个设备对象)
初始化 struct file 对象,将 struct file 对象中的 file_operations 成员指向 struct cdev 对象中的 file_operations 成员( file->fops = cdev->fops
回调 file->fops->open 函数
我们使用的 open 函数在内核中对应的是 sys_open 函数, sys_open 函数又会调用 do_sys_open 函 数。在 do_sys_open 函数中,首先调用函数 get_unused_fd_flags 来获取一个未被使用的文件描述符 fd,该文件描述符就是我们最终通过 open 函数得到的值。紧接着,又调用了 do_filp_open 函数, 该函数通过调用函数 get_empty_filp 得到一个新的 file 结构体,之后的代码做了许多复杂的工作, 如解析文件路径,查找该文件的文件节点 inode 等,直接来到了函数 do_dentry_open 函数,如下 所示。
//do_dentry_open 函数(内核源码/fs/open.c)static int do_dentry_open(struct file *f,struct inode *inode,int(*open)(struct inode *,             struct file *),const struct cred *cred)
{……f->f_op = fops_get(inode->i_fop);……if (!open)open = f->f_op->open;if (open) {error = open(inode, f);if (error)goto cleanup_all;}……
}
4 行:使用 fops_get 函数来获取该文件节点 inode 的成员变量 i_fop ,我们使用 mknod 创建字符设备文件时,将 def_chr_fops 结构体赋值给了该设备文件 inode i_fop 成 员。
7 行:到了这里,我们新建的 file 结构体的成员 f_op 就指向了 def_chr_fops
注:def_chr_fops 是字符设备通用的操作函数,类比于我们自己在写驱动程序时的file_operation
// def_chr_fops 结构体(内核源码/fs/char_dev.c)const struct file_operations def_chr_fops = {.open = chrdev_open,.llseek = noop_llseek,
};
最终,会执行 def_chr_fops 中的 open 函数,也就是 chrdev_open 函数,可以理解为一个字符设备的通用初始化函数,根据字符设备的设备号,找到相应的字符设备,从而得到操作该设备的方法。

//chrdev_open 函数(内核源码/fs/char_dev.c)
static int chrdev_open(struct inode *inode, struct file *filp)
{const struct file_operations *fops;struct cdev *p;struct cdev *new = NULL;int ret = 0;spin_lock(&cdev_lock);p = inode->i_cdev;if (!p) {struct kobject *kobj;int idx;spin_unlock(&cdev_lock);kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);if (!kobj)return -ENXIO;new = container_of(kobj, struct cdev, kobj);spin_lock(&cdev_lock);/* Check i_cdev again in case somebody beat us to it whilewe dropped the lock.*/p = inode->i_cdev;if (!p) {inode->i_cdev = p = new;list_add(&inode->i_devices, &p->list);new = NULL;} else if (!cdev_get(p))ret = -ENXIO;} else if (!cdev_get(p))ret = -ENXIO;spin_unlock(&cdev_lock);cdev_put(new);if (ret)return ret;ret = -ENXIO;fops = fops_get(p->ops);if (!fops)goto out_cdev_put;replace_fops(filp, fops);if (filp->f_op->open) {ret = filp->f_op->open(inode, filp);if (ret)goto out_cdev_put;}return 0;out_cdev_put:cdev_put(p);return ret;}

函数 chrdev_open 最终将创建的文件结构体 file 的成员 f_op 替换成了 cdev 对应的 ops 成员,并执行 ops 结构体中的 open 函数。

最后,调用上图的 fd_install 函数,完成文件描述符和文件结构体 file 的关联,之后我们使用对该文件描述符 fd 调用 read write 函数,最终都会调用 file 结构体对应的函数,实际上也就是调用cdev 结构体中 ops 结构体内的相关函数。
总结一下整个过程,当我们使用 open 函数,打开设备文件时,会根据该设备的文件的设备号找到相应的设备结构体,从而得到了操作该设备的方法。也就是说如果我们要添加一个新设备的话,我们需要提供一个设备号,一个设备结构体以及操作该设备的方法(file_operations 结构体)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/671031.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于深度学习检测恶意流量识别框架(80+特征/99%识别率)

基于深度学习检测恶意流量识别框架 目录 基于深度学习检测恶意流量识别框架简要示例a.检测攻击类别b.模型训练结果输出参数c.前端检测页面d.前端训练界面e.前端审计界面(后续更新了)f.前端自学习界面(自学习模式转换)f1.自学习模式…

Python安装以及环境配置

目录 一、下载安装包二级目录三级目录 一、下载安装包 方式网址Python官网python.org镜像下载地址Download pythonpycharmDownload PyCharm https://blog.csdn.net/sun80760/article/details/135256627 二级目录 三级目录

C#连接S7-200 smart通讯测试

honeytree 一、编程环境 VS2022软件,选择windows窗体应用(.NET FrameWork):​博途TIA/WINCC社区VX群 ​博途TIA/WINCC社区VX群 添加NuGet程序包;S7netplus 二、引用http://S7.net 三、建立PLC链接 S7-200smart和…

Window如何运行sh文件以及wget指令

Git下载 官网链接如下:https://gitforwindows.org/ 安装就保持一路无脑安装就行,不需要改变安装过程中的任何一个选项。 配置Git 切刀桌面,随便右击屏幕空白处,点open Git Bash here 把这行复制过去,回车&#xff1…

Linux第三节--常见的指令介绍集合(持续更新中)

点赞关注不迷路!,本节涉及初识Linux第三节,主要为常见的几条指令介绍。 如果文章对你有帮助的话 欢迎 评论💬 点赞👍🏻 收藏 ✨ 加关注👀 期待与你共同进步! Linux下基本指令 1. man指令 Linu…

io (fscanf fprintf)

20 #include <sys/un.h>21 typedef struct stu22 {23 char name[16];24 int age;25 double score;26 }stu;27 int main(int argc, const char *argv[])28 {29 /* 有如下结构体30 31 申请该结构体数组&#xff0c;容量为5&#xff0c;初始化5个学生的信息32 …

Flink窗口理论到实践 | 大数据技术

⭐简单说两句⭐ ✨ 正在努力的小叮当~ &#x1f496; 超级爱分享&#xff0c;分享各种有趣干货&#xff01; &#x1f469;‍&#x1f4bb; 提供&#xff1a;模拟面试 | 简历诊断 | 独家简历模板 &#x1f308; 感谢关注&#xff0c;关注了你就是我的超级粉丝啦&#xff01; &a…

奶爸预备 |《P.E.T.父母效能训练:让亲子沟通如此高效而简单:21世纪版》 / 托马斯·戈登——读书笔记

目录 引出致中国读者译序前言第1章 父母总是被指责&#xff0c;而非受训练第2章 父母是人&#xff0c;不是神第3章 如何听&#xff0c;孩子才会说&#xff1a;接纳性语言第4章 让积极倾听发挥作用第5章 如何倾听不会说话的婴幼儿第6章 如何听&#xff0c;孩子才肯听第8章 通过改…

光端机(2)——光纤通信学习笔记九

学习笔记里面只关注基本原理和概念&#xff0c;复杂的公式和推导都没有涉及 光端机 光发射机 作用&#xff1a;实现电光转换。将来自电端机的电信号对光源发出的光波进行调制&#xff0c;然后将调制好的光信号耦合到光线中传输。 基本性能要求 1.合适的发光波长&#xff08;光…

Kalign 3:大型数据集的多序列比对

之前一直用的是muscle&#xff0c;看到一个文章使用了Kalign&#xff0c;尝试一下吧 安装 wget -c https://github.com/TimoLassmann/kalign/archive/refs/tags/v3.4.0.tar.gz tar -zxvf v3.4.0.tar.gz cd kalign-3.4.0 mkdir build cd build cmake .. make make test su…

“AI 程序员”席卷而来,吴恩达四步设计让 Agent 提前超越 GPT-5

作者 | 王启隆 出品 | AI 科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09; 有不少科幻片描绘了这样的世界&#xff1a;数字实体执行一座城市的所有任务&#xff0c;人工智能可以与数字世界甚至物理世界的一切事物进行交互&#xff0c;不断学习和适应新环境&#xf…

安卓应用开发(一):工具与环境

开发工具 Android Studio&#xff0c;用于开发 Android 应用的官方集成开发环境 (IDE)。包括以下功能&#xff1a; 基于Gradle的构建系统 gradle是一个项目构建工具&#xff0c;将源工程打包构建为apk 安卓模拟器统一环境代码编辑模拟器实时更新Github集成Lint功能&#xff0…