struct inode 结构体详解

本文详细解析了inode的概念,包括其在Linux文件系统中的角色,VFSinode与Ext2inode的区别,以及inode在文件链接中的作用。介绍了inode的分配、inode与硬链接、软链接的关系,深入探讨了文件系统中的关键结构。

inode的定义
inode译成中文就是索引节点,它用来存放档案及目录的基本信息,包含时间、档名、使用者及群组等。
二、inode的分类及其具体涵义
inode分为内存中的inode和文件系统中的inode,为了避免混淆,我们称前者为VFS inode, 而后者以EXT2为代表,我们称为Ext2 inode。下面分别对VFS inodee与Ext2 inode做一下简单的描述:
1、VFS inode包含文件访问权限、属主、组、大小、生成时间、访问时间、最后修改时间等信息。它是linux管理文件系统的最基本单位,也是文件系统连接任何子目录、文件的桥梁。inode结构中的静态信息取自物理设备上的文件系统,由文件系统指定的函数填写,它只存在于内存中,可以通过inode缓存访问。虽然每个文件都有相应的inode结点,但是只有在需要的时候系统才会在内存中为其建立相应的inode数据结构,建立的inode结构将形成一个链表,我们可以通过遍历这个链表去得到我们需要的文件结点,VFS也为已分配的inode构造缓存和哈希表,以提 高系统性能。inode结构中的struct inode_operations *i_op为我们提供了一个inode操作列表,通过这个列表提供的函数我们可以对VFS inode结点进行各种操作。每个inode结构都有一个i结点号i_ino,在同一个文件系统中每个i结点号是唯一的。
struct inode {
struct list_headi_hash;
struct list_headi_list;
struct list_headi_dentry;
struct list_headi_dirty_buffers;
unsigned longi_ino; /*每一个inode都有一个序号,经由super block结构和其序号,我们可以很轻易的找到这个inode。*/
atomic_t i_count; /*在Kernel里,很多的结构都会记录其reference count,以确保如果某个结构正在使用,它不会被不小心释放掉,i_count就是其reference count。*/
kdev_t i_dev; /* inode所在的device代码 */
umode_t i_mode; /* inode的权限 */
nlink_t i_nlink; /* hard link的个数 */
uid_t i_uid; /* inode拥有者的id */
gid_t i_gid; /* inode所属的群组id */
kdev_t i_rdev; /* 如果inode代表的是device的话,那此字段将记录device的代码 */ 
off_t i_size; /* inode所代表的档案大小 */
time_t i_atime; /* inode最近一次的存取时间 */
time_t i_mtime; /* inode最近一次的修改时间 */
time_t i_ctime; /* inode的产生时间 */ 
unsigned long i_blksize; /* inode在做IO时的区块大小 */
unsigned long i_blocks; /* inode所使用的block数,一个block为512 byte*/
unsigned long i_version; /* 版本号码 */ 
unsigned short i_bytes;
struct semaphore i_sem;
struct rw_semaphore i_truncate_sem;
struct semaphore i_zombie;
struct inode_operations *i_op;
struct file_operations *i_fop;/* former ->i_op->default_file_ops */
struct super_block *i_sb; /* inode所属档案系统的super block */
wait_queue_head_t i_wait;
struct file_lock *i_flock; /* 用来做file lock */
struct address_space *i_mapping;
struct address_space i_data;
struct dquot *i_dquot [MAXQUOTAS];
/* These three should probably be a union */
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct char_device *i_cdev;
unsigned longi_dnotify_mask; /* Directory notify events */
struct dnotify_struct *i_dnotify; /* for directory notifications */
unsigned long i_state; /* inode目前的状态,可以是I_DIRTY,I_LOCK和 I_FREEING的OR组合 */ 
unsigned int i_flags; /* 记录此inode的参数 */ 
unsigned char i_sock; /* 用来记录此inode是否为socket */ 
atomic_t i_write count;
unsigned int i_attr_flags; /* 用来记录此inode的属性参数 */ 
__u32 i_generation;
union {
struct minix_inode_info minix_i;
struct ext2_inode_info ext2_i;
struct ext3_inode_info ext3_i;
struct hpfs_inode_info hpfs_i;
struct ntfs_inode_info ntfs_i;
struct msdos_inode_info msdos_i;
struct umsdos_inode_info umsdos_i;
struct iso_inode_info isofs_i;
struct sysv_inode_info sysv_i;
struct affs_inode_info affs_i;
struct ufs_inode_info ufs_i;
struct efs_inode_info efs_i;
struct romfs_inode_info romfs_i;
struct shmem_inode_info shmem_i;
struct coda_inode_info coda_i;
struct smb_inode_info smbfs_i;
struct hfs_inode_info hfs_i;
struct adfs_inode_info adfs_i;
struct qnx4_inode_info qnx4_i;
struct reiserfs_inode_info reiserfs_i;
struct bfs_inode_info bfs_i;
struct udf_inode_info udf_i;
struct ncp_inode_info ncpfs_i;
struct proc_inode_info proc_i;
struct socketsocket_i;
struct usbdev_inode_info usbdev_i;
struct jffs2_inode_infojffs2_i;
void *generic_ip;
} u;
};
2、EXT2 inode用来定义文件系统的结构以及描述系统中每个文件的管理信息,每个文件都有且只有一个inode,即使文件中没有数据,其索引结点也是存在的。每个文件用一个单独的Ext2 inode结构来描述,而且每一个inode都有唯一的标志号。Ext2 inode为内存中的inode结构提供了文件的基本信息,随着内存中inode结构的变化,系统也将更新Ext2 inode中相应的内容。Ext2 inode对应的是Ext2_inode结构。
struct ext2_inode {
__u16 i_mode;/* File mode */
__u16 i_uid;/* Low 16 bits of Owner Uid */
__u32 i_size;/* Size in bytes */
__u32 i_atime;/* Access time */
__u32 i_ctime;/* Creation time */
__u32 i_mtime;/* Modification time */
__u32 i_dtime;/* Deletion Time */
__u16 i_gid;/* Low 16 bits of Group Id */
__u16 i_links_count;/* Links count */
__u32 i_blocks;/* Blocks count */
__u32 i_flags;/* File flags */
union {
struct {
__u32 l_i_reserved1;
} linux1;
struct {
__u32 h_i_translator;
} hurd1;
struct {
__u32 m_i_reserved1;
} masix1;
} osd1;/* OS dependent 1 */
__u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
__u32 i_generation;/* File version (for NFS) */
__u32 i_file_acl;/* File ACL */
__u32 i_dir_acl;/* Directory ACL */
__u32 i_faddr;/* Fragment address */
union {
struct {
__u8l_ i_frag;/* Fragment number */
__u8l_ i_fsize;/* Fragment size */
__u16 i_pad1;
__u16l_ i_uid_high;/* these 2 fields */
__u16l_ i_gid_high;/* were reserved2[0] */
__u32l_ i_reserved2;
} linux2;
struct {
__u8h_ i_frag;/* Fragment number */
__u8h_ i_fsize;/* Fragment size */
__u16h_ i_mode_high;
__u16h_ i_uid_high;
__u16h_ i_gid_high;
__u32h_ i_author;
} hurd2;
struct {
__u8m_ i_frag;/* Fragment number */
__u8m_ i_fsize;/* Fragment size */
__u16m_ pad1;
__u32m_ i_reserved2[2];
} masix2;
} osd2;/* OS dependent 2 */
};
从结构的定义中可以看出来inode(VFS inode)与ext2_inode的差别是很大的,它们都包含动态信息和静态信息,通过union指定的内容一定是动态的。inode结构中的union u实际上反映了VFS支持的文件系统。
可以看出inode结构与ext2_inode结构有些内容是相似的,如:
inode定义的
unsigned long i_ino;
umode_t i_mode;
nlink_t i_nlink;
uid_t i_uid;
gid_t i_gid;
loff_t i_size;
time_t i_atime;
time_t i_mtime;
time_t i_ctime;
unsigned long i_blksize;
unsigned long i_blocks;
和ext2_inode定义的定义部分
__u16 i_mode;/* File mode */
__u16 i_uid;/* Low 16 bits of Owner Uid */
__u32 i_size;/* Size in bytes */
__u32 i_atime;/* Access time */
__u32 i_ctime;/* Creation time */
__u32 i_mtime;/* Modification time */
__u32 i_dtime;/* Deletion Time */
__u16 i_gid;/* Low 16 bits of Group Id */
__u16 i_links_count;/* Links count */
__u32 i_blocks;/* Blocks count */
__u32 i_flags;/* File flags */
这些都可以对应上,当然还有一些不同的地方,如inode中定义的
kdev_t i_rdev;
kdev_t i_dev;
unsigned short i_bytes;
struct semaphore i_sem;
在ext2_inode中没有体现,不过这部分对ext2_inode是没有用途而且无法确定的。类似的,可以推广到两个结构的其余部分,最终在代码中的区别还是与原理中分析的区别相关的,也是原理的具体体现。
3、从上面的描述,我们可以对VFS inode与ext2 inode做出比较:
位置:VFS inode结构位于内存中,而Ext2_inode位于磁盘。
生存期:VFS inode在需要时才会被建立,如果系统断电,此结构也随之消失。
Ext2_inode的存在与系统是否上电无关,而且无论文件是否包含数据,Ext2_inode都是存在的。
唯一性:两者在自己的作用域中都是唯一的。
关系:VFS inode是Ext2 inode的抽象、映射与扩充,而后者是前者的静态信息部分,也是对前者的具体化、实例化和持久化。
操作:对VFS inode的操作具有通用性,对文件系统inode的操作则是文件系统相关的,依赖于特定的实现。
组织管理:系统通过VFS inode链表来对其进行组织,并且为了提高访问效率相应地构造了inode构造缓存和hash table。
Ext2 inode的信息位于EXT2文件系统的划分的块组中,在每个块组中包含相应的inode位图、inode表指定具体的inode信息,每个inode对应Ext2_inode结构。
三、 inode的分配 (对于ext2 inode)
1、每个inode大小128 byte
2、在分割扇区时,系统会先做出一堆inode以供以后使用,inode 的数量关系着系统中可以建立的档案及目录总数。有时候,这些inode或许会不够用,例如当一个程序产生大量小文件的时候,此时文件系统就需要增加索引节点。
同样,如果我们事先知道此文件系统只用来存放少数大文件,我们就可以通过减少索引节点的数目来达到节省磁盘空间的目的——毕竟每个索引节点占用128字节。
创建文件系统的时候,可以使用newfs命令的-i选项来增加或者减少索引节点的数目。
3、newfs -i 2048 -b 8192 -f 1024
newfs创建新的文件系统
-i 2048更改inode每2KB创建一个
-b 8192设置block size的大小为8kB
-f 1024设置fragments的大小为1KB 
四、inode与ln (对于ext2 inode)
1、当我们用ls 查看某个目录或文件时,如果加上-i 参数,就可以看到inode节点了;
[root@localhost ~]# ls -li lsfile.sh
2408949 -rwxr-xr-x 1 root root 7 04-21 12:47 lsfile.sh
可见lsfile.sh 的inode值是2408949 ; 
2、创建硬链接,硬链接和源文件关系;
用ln创建文件硬链接的语法:
[root@localhost ~]#ln 源文件 目标文件
下面我们举一个例子,在这个例子中,我们要为sun.txt创建其硬链接sun002.txt。然后看一下 sun.txt和sun002.txt的属性的变化;
[root@localhost ~]# ls -li sun.txt 注:查看sun.txt的属性;
2408263 -rw-r--r-- 1 root root 29 04-22 21:02 sun.txt 注:这是sun.txt的属性;
[root@localhost ~]# ln sun.txt sun002.txt 注:我们通过ln 来创建sun.txt的硬链接文件sun002.txt
[root@localhost ~]# ls -li sun* 注:我们列一下sun.txt 和sun002.txt
2408263 -rw-r--r-- 2 root root 29 04-22 21:02 sun002.txt
2408263 -rw-r--r-- 2 root root 29 04-22 21:02 sun.txt
我们可以看到sun.txt在没有创建硬链接文件sun002.txt的时候,其链接个数是1(也就是-rw-r--r--后的那个数值),创建了硬链接 sun002.txt创建后,这个值变成了2。也就是说,我们每次为sun.txt创建一个新的硬链接文件后,其硬链接个数都会增加1。
inode值相同的文件,他们的关系是互为硬链接的关系。当我们修改其中一个文件的内容时,互为硬链接的文件的内容也会跟着变化。如果我们删除互为硬链接关系的某个文件时,其它的文件并不受影响。比如我们把sun.txt删除后,我们还是一样能看到sun002.txt的内容,并且sun02.txt仍是存在的。
可以这么理解,互为硬链接关系的文件,他们好像是克隆体,他们的属性几乎是完全一样;
下面的例子,我们把sun.txt删除,然后我们看一下sun002.txt是不是能看到其内容。
[root@localhost ~]# rm -rf sun.txt
[root@localhost ~]# more sun002.txt
注意:硬链接不能为目录创建,只有文件才能创建硬链接。
3、软链接的创建,及软接与源文件的关系;
创建软链接(也被称为符号链接)的语法; 
[root@localhost ~]# ln -s 源文文件或目录 目标文件或目录
软链接也叫符号链接,他和硬链接有所不同,软链接文件只是其源文件的一个标记。当我们删除了源文件后,链接文件不能独立存在,虽然仍保留文件名,但我们却不能查看软链接文件的内容了。
[root@localhost ~]# ls -li linuxsir001.txt
2408274 -rw-r--r-- 1 root root 29 04-22 21:53 linuxsir001.txt
[root@localhost ~]# ln -s linuxsir001.txt linuxsir002.txt
[root@localhost ~]# ls -li linuxsir001.txt linuxsir002.txt
2408274 -rw-r--r-- 1 root root 29 04-22 21:53 linuxsir001.txt
2408795 lrwxrwxrwx 1 root root 15 04-22 21:54 linuxsir002.txt -> linuxsir001.txt
上面的例子,首先我们查看 linuxsir001.txt 的属性,比如inode、所属文件种类、创建或修改时间等... ...我们来对比一下:
首先 对比一下节点:两个文件的节点不同;
其次 两个文件的归属的种类不同 linuxsir001.txt是-,也就是普通文件,而linuxsir002.txt 是l,它是一个链接文件;
第三 两个文件的读写权限不同 linuxsir001.txt 是rw-r--r-- ,而linuxsir002.txt的读写权限是 rwxrwxrwx
第三 两者的硬链接个数相同;都是1
第四 两文件的属主和所归属的用户组相同;
第五 修改(或访问、创建)时间不同;
我们还注意到了linuxsir002.txt 后面有一个标记 ->,这表示linuxsir002.txt 是linuxsir001.txt的软链接文件。
值得我们注意的是:当我们修改链接文件的内容时,就意味着我们在修改源文件的内容。当然源文件的属性也会发生改变,链接文件的属性并不会发生变化。当我们把源文件删除后,链接文件只存在一个文件名,因为失去了源文件,所以软链接文件也就不存在了。这一点和硬链接是不同的;
[root@localhost ~]# rm -rf linuxsir001.txt 注:删除linuxsir001.txt
[root@localhost ~]# ls -li linuxsir002.txt 注:查看linuxsir002 的属性;
2408795 lrwxrwxrwx 1 root root 15 04-22 21:54 linuxsir002.txt -> linuxsir001.txt
[root@localhost ~]# more linuxsir002.txt 注:查看linuxsir002.txt的内容;
linuxsir002.txt: 没有那个文件或目录 注:得到提示,linuxsir002.txt不存在。
上面的例子告诉我们,如果一个链接文件失去了源,就意味着他已经不存在了;
我们可以看到软链接文件,其实只是源文件的一个标记,当源文件失去时,他也就是存在了。软链接文件只是占用了inode来存储软链接文件属性等信息,但文件存储是指向源文件的。
软链接,可以为文件或目录都适用。无论是软链接还是硬链接,都可以用rm来删除。rm工具是通用的

<think>嗯,用户再次聚焦于struct file和struct inode的区别与联系,看来需要更系统地对比这两个核心结构体。用户提供了两份站内引用[^1][^2],其中[^1]非常清晰地描述了二者的基本差异:file代表动态的打开实例,inode存储静态文件元数据;[^2]则补充了file_operations的操作接口细节。 注意到用户可能是嵌入式开发者或内核学习者,需要理论结合实践的理解。上次回答已概述过二者关系,这次应该深化三点:1)生命周期差异(动态vs静态),2)结构体内存归属(slab分配器vs文件系统),3)典型交互场景(如open时如何关联)。特别要强调"一个inode对应多个file"这个关键点,这在多进程打开同一文件时至关重要。 用户没有询问代码示例,但引用[^2]提到file_operations的函数签名,可以隐含说明:当驱动程序操作inode参数时,实际是在获取文件物理属性;而操作file参数时,则在处理特定进程的上下文(如f_pos)。这能自然引出并发场景下数据一致性的实现机制——例如inode自旋锁如何保护临界区。 考虑到用户连续三次追问内核数据结构,后续问题设计可以更深入:1) 探讨vfs抽象层中super_block的作用,2) 逆向思考为什么file不直接包含inode而用指针关联(内存效率考量),3) 扩展学习ext4文件系统的磁盘inode布局。不过当前回答需保持专注,用表格对比核心差异后,再用文件读写流程示例说明协作关系。 </think>在Linux内核中,`struct file` 和 `struct inode` 是文件系统的核心数据结构,二者协同工作但职责分明。以下是它们的区别与联系详解(基于引用[^1][^2]): --- ### **一、核心区别** | **特性** | **struct file** | **struct inode** | |------------------------|--------------------------------------------|-------------------------------------------| | **本质** | 动态对象 | 静态对象 | | **生命周期** | 文件打开时创建,关闭时销毁 | 文件创建时生成,删除时释放 | | **数量关系** | 同一文件可被多次打开,生成多个`file`实例 | 每个文件唯一对应一个`inode` | | **存储内容** | 文件操作状态(位置指针、打开模式等) | 文件元数据(大小、权限、物理位置等) | | **作用范围** | 进程级别(每个进程独立维护) | 文件系统级别(全局唯一) | | **内核操作接口** | 通过`f_op`链接到`file_operations`函数集[^2] | 作为参数传递给`file_operations`中的函数 | > **典型场景**: > 若进程A和B同时打开`/tmp/test.log`: > - 内核创建 **两个`struct file`**(分别维护A和B的读写位置`f_pos`) > - 但仅有一个共享的 **`struct inode`**(记录文件大小、磁盘块位置等)[^1] --- ### **二、内在联系** 二者的协作通过 **VFS(虚拟文件系统)** 实现: 1. **文件打开流程** ```mermaid graph LR A[open系统调用] --> B[内核创建struct file] B --> C[根据路径查找inode] C --> D[file.f_inode = inode] D --> E[file.f_op = inode关联的操作函数] ``` - `struct file` 通过 `f_inode` 指针关联到对应的 `inode`[^1] - `inode` 决定 `file.f_op` 指向的具体操作函数(如ext4/ntfs的实现) 2. **文件读写流程** 当进程调用 `read()` 时: ```c ssize_t read(struct file *file, char *buf, size_t count, loff_t *pos) { // 通过file->f_inode获取文件物理信息 struct inode *inode = file->f_inode; // 通过file->f_op->read调用驱动函数 return file->f_op->read(file, buf, count, pos); } ``` - `file` 提供操作上下文(如当前偏移量 `f_pos`) - `inode` 提供底层数据定位依据(如磁盘块号)[^2] --- ### **三、典型协作示例** 假设字符设备驱动实现读取操作: ```c static ssize_t mydev_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) { // 通过filp->f_inode获取设备信息 struct mydev *dev = filp->f_inode->i_private; // 从设备硬件读取数据 copy_to_user(buf, dev->data, len); // 更新文件偏移量(动态状态) *ppos += len; return len; } static struct file_operations fops = { .owner = THIS_MODULE, .read = mydev_read, // 关联到struct file }; // 设备初始化时关联inode与驱动 init_module() { struct inode *inode = ...; inode->i_private = &my_device; // 存储设备私有数据 } ``` > **关键点**: > - `struct file` 处理 **动态状态**(如偏移量更新) > - `struct inode` 存储 **静态信息**(如设备对象指针)[^1][^2] --- ### **四、总结** | **维度** | **struct file** | **struct inode** | |--------------|--------------------------|---------------------------| | **角色** | 文件的“操作句柄” | 文件的“身份证明” | | **变化频率** | 高频变化(每次读写更新) | 低频变化(文件属性修改时)| | **依赖关系** | 依赖inode获取文件信息 | 独立于进程存在 | 二者共同构建了Linux **“文件-操作”分离模型**: $$\text{文件操作} = \underbrace{\text{struct file}}_{\text{动态上下文}} + \underbrace{\text{struct inode}}_{\text{静态元数据}} + \underbrace{\text{file\_operations}}_{\text{操作接口}}$$ 这种设计实现了: 1. 同一文件支持多进程并发访问(各进程维护独立`file`) 2. 文件操作与存储解耦(`inode`可关联不同文件系统) 3. 驱动开发标准化(通过`file_operations`接口)[^1][^2] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值