open系统调用、syscall_open函数和drv_open函数之间的联系和区别
-
open
系统调用:-
角色:用户空间的系统调用接口,用于打开文件或设备。
-
作用:这是用户程序用来请求打开文件的接口。用户程序通过调用
open
系统调用(如open("/dev/mydevice", O_RDWR)
)来打开文件或设备,获取一个文件描述符。 -
实现:
open
系统调用在用户空间的C标准库(如glibc
)中实现,会触发内核中的相应处理函数陷入内核空间,最终调用具体的文件或设备驱动程序的open
实现。 -
示例:
int fd = open("/dev/my_device", O_RDWR);
-
-
syscall_open
函数:-
角色:位于内核空间,是内核中的系统调用处理函数,是
open
系统调用在内核中的实现。 -
作用:
syscall_open
是内核处理open
系统调用的入口点。它负责解析用户空间传入的参数(如文件路径、打开标志等),并调用与文件或设备关联的file_operations
结构体中具体的驱动程序的open
方法,即drv_open
来打开文件。 -
实现:
syscall_open
通常由内核开发者实现,是内核的一个内部函数。 -
示例:
// 内核中系统调用处理函数的简化示例 long sys_open(const char __user *filename, int flags, umode_t mode) { // 查找文件路径,获取 inode 和 file 结构体 struct file *filp = do_filp_open(AT_FDCWD, filename, flags); // 调用文件的 open 方法 return finish_open(filp, NULL, O_RDWR);c }
-
-
drv_open
函数:-
角色:
drv_open
位于具体的设备驱动程序代码中,是设备驱动程序中的具体实现函数,是file_operations
结构体中的一个函数指针。 -
作用:
drv_open
是具体设备驱动程序实现的open
方法。它执行与设备打开相关的具体操作,如初始化设备、分配资源等。 -
实现:
drv_open
由设备驱动开发者实现,作为file_operations
结构体中的open
方法,主要功能是执行设备特定的操作,如初始化硬件、分配设备资源、设置设备状态等。 -
示例:
// 设备驱动程序中的 open 方法实现 static int drv_open(struct inode *inode, struct file *filp) { // 设备特定的初始化操作 printk(KERN_INFO "Device opened\n"); return 0; } static const struct file_operations my_fops = { .owner = THIS_MODULE, .open = drv_open, // 其他操作函数 };
-
之间的联系和流程
-
用户空间调用
open
系统调用:-
用户空间的应用程序通过调用
open
系统调用请求打开一个文件或设备。
-
-
进入内核空间,调用
syscall_open
:-
系统调用机制将控制权转交给内核,进入
syscall_open
函数(具体名称和实现可能因内核版本不同而有所不同)。
-
-
内核找到对应的文件系统操作方法:
-
syscall_open
通过文件路径找到对应的inode
结构体,从而找到与该文件或设备相关的struct file_operations
结构体。
-
-
调用驱动程序的
open
方法(drv_open
):-
内核通过
file_operations
结构体中的open
方法指针,调用具体驱动程序实现的drv_open
函数。 -
drv_open
执行设备特定的打开操作,如硬件初始化、资源分配等。
-
函数实现的伪代码
syscall_open函数实现的伪代码:
int syscall_open(const char *filename,int flag) { dev_t devno; struct inode *pnode = NULL; struct cdev *pcdev = NULL; struct file *pfile = NULL; int fd = -1; /*根据filename在内核中查找该文件对应的struct inode对象地址 找到则pnode指向该对象 未找到则创建新的struct inode对象,pnode指向该对象,并从文件系统中读取文件的元信息到该对象*/ if(/*未找到对应的struct inode对象*/) {/*根据文件种类决定如何进行下面的操作,如果是字符设备则执行如下操作*/ /*从pnode指向对象中得到设备号*/ devno = pnode->i_rdev; /*用devno在字符设备链表查找对应节点,并将该节点的地址赋值给pcdev*/ /*pcdev赋值给pnode的i_cdev成员*/ pnode->i_cdev = pcdev; } /*创建struct file对象,并将该对象的地址赋值给pfile*/ pfile->f_op = pnode->i_cdev->ops; pfile->f_flags = flag; /*调用驱动程序的open函数*/ pfile->f_op->open(pnode,pfile,flag); /*将struct file对象地址填入进程的描述符数组,得到对应位置的下标赋值给fd*/ return fd; }