linux 文件描述符表 打开文件表 inode vnode

本文深入解析Linux中文件描述符的工作原理,包括如何通过文件描述符访问文件,以及VFS中用于管理打开文件的file结构。解释了文件描述符的数量限制、文件位置的概念、file结构的组成及其在文件操作中的作用。讨论了文件描述符与dentry、inode之间的关系,并说明了同一文件被多个进程打开时的共享机制。
部署运行你感兴趣的模型镜像

在Linux中,进程是通过文件描述符(file descriptors,简称fd)而不是文件名来访问文件的,文件描述符实际上是一个整数。Linux中规定每个进程能最多能同时使用NR_OPEN个文件描述符,这个值在fs.h中定义,为1024*1024(2.0版中仅定义为256)。

每个文件都有一个32位的数字来表示下一个读写的字节位置,这个数字叫做文件位置。每次打开一个文件,除非明确要求,否则文件位置都被置为0,即文件的开始处,此后的读或写操作都将从文件的开始处执行,但你可以通过执行系统调用LSEEK(随机存储)对这个文件位置进行修改。Linux中专门用了一个数据结构file来保存打开文件的文件位置,这个结构称为打开的文件描述(open file description)。这个数据结构的设置是煞费苦心的,因为它与进程的联系非常紧密,可以说这是VFS中一个比较难于理解的数据结构。


file结构中主要保存了文件位置,此外,还把指向该文件索引节点的指针也放在其中。file结构形成一个双链表,称为系统打开文件表,其最大长度是NR_FILE,在fs.h中定义为8192。

file结构在include\linux\fs.h中定义如下:

struct file 

{

 struct list_head        f_list;    /*所有打开的文件形成一个链表*/

 struct dentry           *f_dentry; /*指向相关目录项的指针*/

 struct vfsmount         *f_vfsmnt; /*指向VFS安装点的指针*/

 struct file_operations  *f_op;     /*指向文件操作表的指针*/

 mode_t f_mode;                                  /*文件的打开模式*/

 loff_t f_pos;                                   /*文件的当前位置*/

 unsigned short f_flags;                         /*打开文件时所指定的标志*/

 unsigned short f_count;                           /*使用该结构的进程数*/

 unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;

 /*预读标志、要预读的最多页面数、上次预读后的文件指针、预读的字节数以及预读的页面数*/

 int f_owner;                  /* 通过信号进行异步I/O数据的传送*/

 unsigned int         f_uid, f_gid;  /*用户的UID和GID*/

 int                 f_error;       /*网络写操作的错误码*/

 

 unsigned long f_version;           /*版本号*/

 void *private_data;                      /* tty驱动程序所需 */

};




内核中,对应于每个进程都有一个文件描述符表,表示这个进程打开的所有文件。文件描述表中每一项都是一个指针,指向一个用于描述打开的文件的数据块———file对象,file对象中描述了文件的打开模式,读写位置等重要信息,当进程打开一个文件时,内核就会创建一个新的file对象。需要注意的是,file对象不是专属于某个进程的,不同进程的文件描述符表中的指针可以指向相同的file对象,从而共享这个打开的文件。file对象有引用计数,记录了引用这个对象的文件描述符个数,只有当引用计数为0时,内核才销毁file对象,因此某个进程关闭文件,不影响与之共享同一个file对象的进程.

file对象中包含一个指针,指向dentry对象。dentry对象代表一个独立的文件路径,如果一个文件路径被打开多次,那么会建立多个file对象,但它们都指向同一个dentry对象。

dentry对象中又包含一个指向inode对象的指针。inode对象代表一个独立文件。因为存在硬链接与符号链接,因此不同的dentry对象可以指向相同的inode对象.inode 对象包含了最终对文件进行操作所需的所有信息,如文件系统类型、文件的操作方法、文件的权限、访问日期等。

打开文件后,进程得到的文件描述符实质上就是文件描述符表的下标,内核根据这个下标值去访问相应的文件对象,从而实现对文件的操作。


注意,同一个进程多次打开同一个文件时,内核会创建多个file对象。
当进程使用fork系统调用创建一个子进程后,子进程将继承父进程的文件描述符表,因此在父进程中打开的文件可以在子进程中用同一个描述符访问。



链接:

http://oss.org.cn/kernel-book/ch08/8.2.4.htm
http://blog.chinaunix.net/uid-25940216-id-3118066.html
http://canbeatle.iteye.com/blog/891319
http://blog.21ic.com/user1/4132/archives/2010/75445.html

您可能感兴趣的与本文相关的镜像

HunyuanVideo-Foley

HunyuanVideo-Foley

语音合成

HunyuanVideo-Foley是由腾讯混元2025年8月28日宣布开源端到端视频音效生成模型,用户只需输入视频和文字,就能为视频匹配电影级音效

<think>我们正在讨论inode打开文件描述符列表之间的关系。根据用户提供的引用和之前的问题,我们需要解释清楚这两个概念之间的联系。 引用[1]和[2]介绍了inode的基本概念:inode存储文件的元数据(如大小、权限、位置等)以及指向文件数据的指针。每个文件都有一个inode,而目录项(dentry)则指向inode,硬链接就是多个dentry指向同一个inode。 引用[3]提到了文件描述符和打开文件表(即打开文件描述符列表)的概念。在Unix/Linux系统中,当进程打开一个文件时,会创建一个打开文件表项(在系统内核中,通常称为open file description),并返回一个文件描述符(file descriptor)给进程。文件描述符是进程级别的,每个进程有自己的文件描述符表,而打开文件表是系统级的,可以被多个进程共享(例如通过fork或dup等)。 现在,我们需要理清inode打开文件表之间的关系: 1. 打开文件表(Open File Table)的每个条目(通常称为open file description)包含: - 文件偏移量(当前读写位置) - 文件状态标志(如O_RDONLY, O_APPEND等) - 指向该文件inode的指针 2. 每个进程有一个文件描述符表File Descriptor Table),其中的每个条目指向一个打开文件表条目。 3. inode是文件系统中的概念,它代表了文件本身(即文件的元数据和数据块位置)。一个文件(inode)可以被多个打开文件表条目引用(例如,同一个文件被多个进程打开,或者同一个进程多次打开同一个文件),每个打开文件表条目都有自己的文件偏移量和状态标志。 因此,关系可以总结为: 进程的文件描述符表项 -> 打开文件表项(Open File Description) -> inode 具体步骤: - 当进程打开一个文件时,内核会: a. 根据路径名查找dentry,进而找到inode(如果文件存在)。 b. 创建一个新的打开文件表条目(如果之前没有打开过,或者即使有,但每次open一般都会创建一个新的打开文件表条目,除非使用dup等),并初始化其文件偏移量(通常为0)和状态标志。 c. 在进程的文件描述符表中分配一个空闲项,指向这个打开文件表条目。 - 当进程读写文件时,通过文件描述符找到打开文件表条目,然后通过打开文件表条目中的inode指针找到inode,从而获取文件的实际数据块位置。 注意:多个进程可以共享同一个打开文件表条目(例如,通过fork创建的子进程会继承父进程的文件描述符表,因此指向同一个打开文件表条目),也可以有多个打开文件表条目指向同一个inode(例如,同一个文件被多次打开,每次打开都会创建一个新的打开文件表条目)。 因此,inode打开文件描述符列表(即打开文件表)的关系是:打开文件表条目中有一个指针指向inode,从而将打开的文件实例与文件系统中的文件(inode)关联起来。 根据以上分析,我们可以这样回答用户: ### inode打开文件描述符列表的关系 在Unix/Linux文件系统中,inode(索引节点)和打开文件描述符列表(即内核的打开文件表)是文件管理机制中的两个重要组成部分,它们之间的关系如下: 1. **inode的作用**: inode存储文件的元数据(如文件大小、权限、时间戳、数据块位置等)[^1][^2]。每个文件在文件系统中都有一个唯一的inode编号,并通过inode结构体表示。目录项(dentry)通过指向inode来关联文件名和文件内容。 2. **打开文件描述符列表(打开文件表)的作用**: 当进程打开文件时,内核会创建一个**打开文件表条目**(open file description)[^3]。该条目包含: - 当前文件偏移量(用于记录读写位置) - 文件状态标志(如读/写模式、追加模式等) - 指向该文件inode的指针 打开文件表是系统级别的结构,可以被多个进程共享(例如,通过`fork`创建的子进程会继承父进程的文件描述符,指向同一个打开文件表条目)。 3. **文件描述符(File Descriptor)的作用**: 每个进程拥有一个**文件描述符表**(File Descriptor Table),表中的每一项包含一个指向打开文件表条目的指针。当进程调用`open`函数时,内核会: - 查找或创建inode(若文件存在则获取其inode,否则创建新文件并分配inode)。 - 创建一个新的打开文件表条目(初始化偏移量为0,设置状态标志等),并指向该文件的inode。 - 在进程的文件描述符表中分配一个空闲项(例如,返回整数3作为文件描述符),该项指向新创建的打开文件表条目。 4. **关系总结**: - 文件描述符(进程级别) → 打开文件表条目(系统级别) → inode(文件系统级别) - **关键点**: - 一个inode可以被多个打开文件表条目引用(例如,同一个文件被多次打开,每次打开都创建一个新的打开文件表条目)。 - 一个打开文件表条目可以被多个文件描述符引用(例如,通过`dup`或`fork`复制文件描述符)。 ![关系示意图](https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/File_table_and_inode_table.svg/500px-File_table_and_inode_table.svg.png) (示意图说明:进程A和进程B的文件描述符表项分别指向不同的打开文件表条目,但这两个打开文件表条目可以指向同一个inode。) 5. **示例说明**: - 场景1:进程两次打开同一个文件(例如,`open("a.txt", O_RDONLY)`两次) - 结果:两个独立的文件描述符,分别指向两个不同的打开文件表条目(每个条目有自己的偏移量),但这两个条目指向同一个inode。 - 场景2:进程调用`fork()`创建子进程 - 结果:子进程继承父进程的文件描述符表,因此父子进程的文件描述符指向同一个打开文件表条目(共享同一个文件偏移量)。 通过上述机制,文件系统能够高效地管理文件的读写操作和元数据,同时支持多进程共享文件访问。 §§相关问题§§ 1. 硬链接和软链接在inode层面有何区别? 2. 多个进程同时写入同一个文件时如何避免数据混乱? 3. 文件描述符与文件句柄(File Handle)有何异同? 注意:由于用户提供的引用中没有直接说明打开文件表的具体结构,但根据Unix/Linux系统编程的常识,我们补充了打开文件表(open file description)的概念,并解释了其与inode的关系。引用[3]提到了proc结构体和user结构体,但未详细展开,我们主要依据标准知识进行解释。 </think> ### inode打开文件描述符列表的关系 在Unix/Linux文件系统中,inode打开文件描述符列表之间存在紧密的层级关联,它们共同构成了文件访问的核心机制。具体关系如下: #### 1. **层级关系** 文件访问涉及三个关键层级: - **文件描述符表**(进程级): 每个进程独立拥有的表,存储指向**打开文件表条目**的指针。文件描述符(如`fd=3`)是该表的索引。 - **打开文件表**(系统级): 内核维护的全局表,每个条目(称为打开文件描述)包含: - 文件偏移量(当前读写位置) - 文件状态标志(如`O_RDONLY`) - **指向inode的指针** - **inode表**(文件系统级): 存储文件元数据和数据块位置,每个inode唯一标识一个文件。 > **关系链**: > 进程通过`文件描述符 → 打开文件表条目 → inode → 磁盘数据块`访问文件。 #### 2. **关键交互机制** - **inode的引用**: 当进程打开文件时,内核: 1. 根据路径找到dentry(目录项),进而定位inode[^2] 2. 创建**新的打开文件表条目**,其`inode指针`指向该文件的inode 3. 在进程的文件描述符表中分配条目指向此打开文件表条目 - **共享与独立**: - **同一进程多次打开同一文件**: 创建多个独立的打开文件表条目(每个有自己的偏移量),但**指向同一个inode**。 ```c int fd1 = open("file.txt", O_RDONLY); // 条目A int fd2 = open("file.txt", O_WRONLY); // 条目B ``` ↳ `fd1`和`fd2`对应两个打开文件表条目,但都指向同一个inode。 - **不同进程打开同一文件**: 各进程的打开文件表条目**独立**,但**共享同一个inode**。文件内容同步,但偏移量各自维护。 #### 3. **inode打开文件表的区别** | 特性 | inode | 打开文件表条目 | |--------------|--------------------------------|------------------------------| | **作用域** | 文件系统级(全局唯一) | 内核级(可跨进程共享) | | **内容** | 文件元数据(大小、权限、数据块位置)[^1] | 动态状态(偏移量、打开模式)[^3] | | **生命周期** | 文件存在即存在 | 文件关闭后销毁 | | **共享性** | 被所有打开该文件的条目引用 | 可被多个文件描述符引用 | #### 4. **示例场景 假设进程打开文件`/home/user/data.txt`: 1. 内核通过路径查找dentry,找到对应inode(假设inode编号`1234`) 2. 创建打开文件表条目: ```plaintext | 偏移量: 0 | 标志: O_RDWR | inode_ptr → [inode#1234] | ``` 3. 进程文件描述符表新增条目:`fd=3 → 上述打开文件表条目` 4. 当进程`read(fd3, buf, 100)`时: - 通过`fd=3`找到打开文件表条目 - 从条目中获取当前偏移量(如0) - 通过`inode_ptr`找到inode,读取数据块位置 - 更新打开文件表条目中的偏移量(变为100) ### 总结 inode是文件的**静态元数据载体**,而打开文件表条目是文件被访问时的**动态上下文**。多个打开文件表条目可指向同一个inode,实现多进程/多描述符的文件共享,但每个条目维护独立的读写状态[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值