本文目标
什么是文件描述符?
进程打开文件相关信息管理
Linux设备文件三大结构:inode,file,file_operations
mknod 做了什么事?
进程打开设备文件
驱动如何支持同类型设备?
如何获得注册的设备结构体私有地址?
Linux 中一切都可以看作文件,包括普通文件、链接文件、Socket 以及设备驱动等,对其进行相关操作时,都可能会创建对应的文件描述符。文件描述符(file descriptor)是内核为了高效管理已被打开的文件所创建的索引,用于指代被打开的文件,对文件所有 I/O 操作相关的系统调用都需要通过文件描述符。
Linux启动后,会默认打开3个文件描述符,分别是:
0:标准输入 standard input
1:正确输出 standard output
2:错误输出 error output
这就是为什么我们在程序运行时可以直接打印信息和从命令终端获取信息的原因。
并且以后打开文件后。新增文件绑定描述符 可以依次增加(从3开始累加)。每一条shell命令执行,都会继承父进程的文件描述符。因此,所有运行的shell命令,都会有默认3个文件描述符。
在这里插入图片描述
进程级别的文件描述符表files_struct:内核为每个进程维护一个文件描述符表,该表记录了文件描述符的相关信息,包括文件描述符、指向打开文件表中记录的指针。
系统级别的打开文件表file:内核对所有打开文件维护的一个进程共享的打开文件描述表,表中存储了处于打开状态文件的相关信息,包括文件类型、访问权限、文件操作函数(file_operations)等。
系统级别的 i-node 表:i-node 结构体记录了文件相关的信息,包括文件长度,文件所在设备,文件物理位置,创建、修改和更新时间等,"ls -i" 命令可以查看文件 i-node 节点。
进程在Linux内核中是由结构体task_struct维护,进程打开的所有文件描述符都在进程维护的结构体task_struct的files变量中维护:
//includelinuxsched.hstruct task_struct { …… /* open file information */ struct files_struct *files; ……}
该结构体定义如下:
/* * Open file table structure */struct files_struct { /* * read mostly part */ atomic_t count; struct fdtable __rcu *fdt; struct fdtable fdtab; /* * written part on a separate cache line in SMP */ spinlock_t file_lock ____cacheline_aligned_in_smp; int next_fd; unsigned long close_on_exec_init[1]; unsigned long open_fds_init[1]; struct file __rcu * fd_array[NR_OPEN_DEFAULT];};
该进程所有打开的文件对应的file指针均由fd_array维护,文件描述符和数组下标一一对应。
文件描述符是一种系统资源,可以通过以下命令来查看文件描述符的上限。
查看所有进程允许打开的最大 fd 数量
查看所有进程已经打开的 fd 数量以及允许的最大数量
查看单个进程允许打开的最大 fd 数量.
查看某个文件被哪些进程打开?
可以借助lsof命令编写调试代码如下:
该代码功能是打开文件test,然后休眠100秒,我们需要在这100秒内执行lsof操作。
&是程序放在后台运行,为了释放终端,方便输入下一个命令;
7284:程序进程ID;
lsof功能:查看某个文件被进程打开的详细信息。
查看某个进程打开了哪些文件?
接着上述的例子,ls -l /proc/{PID}/fd 可以查看某个进程打开了哪些文件。