linux内核如何根据文件名索引到文件内容

https://zhuanlan.zhihu.com/p/78724124

根据文件名索引到文件内容

表面上,用户通过文件名,打开文件。实际上,系统内部这个过程分成三步:首先,系统找到这个文件名对应的inode号码;其次,通过inode号码,获取inode信息;最后,根据inode信息,找到文件数据所在的block,读出数据。

现在举一个具体的例子,来说明文件是怎么读取到的,比如读取/home/bzw/test里的内容,目录结构如下图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
假设文件系统的的简单分区如下
在这里插入图片描述
获取home对应的inode号:先找根目录’/'的inode(不考虑缓存):根目录的inode号可以从super_block中获取,ext4文件系统的根目录inode号为2(xfs文件系统根目录inode号是64,ceph文件系统根目录inode号是1),所以在索引区读取inode号为2存的inode内容。假如inode中存的block地址是1000,那么去数据区读取地址为1000的block存的内容,内容如下图所示。
地址为1000的block存的内容
地址为1000的block存的内容
地址为1000的block里面存了20个目录项(struct ext4_dir_entry),可以找到目录home对应的inode号为100。

获取bzw对应的inode号:上一步获取到了目录home的inode号,在索引区读取inode号为100存的inode内容。假如inode中存的block地址为2000,那么去读地址为2000的block存的内容,内容如下图所示。
地址为2000的block存的内容
地址为2000的block存的内容
地址为2000的block里面存了3个目录项(struct ext4_dir_entry),可以找到目录bzw对应的inode号为200。

获取test对应的inode号:上一步获取到了目录bzw的inode号,在索引区读取inode号为200存的inode内容。假如inode中存的block地址为3000,那么去读地址为3000的block存的内容,内容如下图所示。
地址为3000的block存的内容
地址为3000的block存的内容
地址为3000的block里面存了2个目录项(struct ext4_dir_entry),可以找到文件test对应的inode号为300。

获取test对应的内容:上一步获取到了文件test的inode号,在索引区读取inode号为300存的inode内容。假如inode中存的block地址为4000,那么去读地址为4000的block存的内容。这个时候就完成了操作。
这里注意如果test内容很大,那么在inode里面存的block地址就不止一个了。

可以以ext4中的struct ext4_inode为例

struct ext4_inode {
__le16 i_mode; /* File mode /
__le16 i_uid; /
Low 16 bits of Owner Uid /
__le32 i_size_lo; /
Size in bytes /
__le32 i_atime; /
Access time /
__le32 i_ctime; /
Inode Change time /
__le32 i_mtime; /
Modification time /
__le32 i_dtime; /
Deletion Time /
__le16 i_gid; /
Low 16 bits of Group Id /
__le16 i_links_count; /
Links count /
__le32 i_blocks_lo; /
Blocks count /
__le32 i_flags; /
File flags /

__le32 i_block[EXT4_N_BLOCKS];/
Pointers to blocks / 这里面存的就是block的地址
__le32 i_generation; /
File version (for NFS) /
__le32 i_file_acl_lo; /
File ACL /
__le32 i_size_high;
__le32 i_obso_faddr; /
Obsoleted fragment address /

__le16 i_extra_isize;
__le16 i_checksum_hi; /
crc32c(uuid+inum+inode) BE /
__le32 i_ctime_extra; /
extra Change time (nsec << 2 | epoch) /
__le32 i_mtime_extra; /
extra Modification time(nsec << 2 | epoch) /
__le32 i_atime_extra; /
extra Access time (nsec << 2 | epoch) /
__le32 i_crtime; /
File Creation time /
__le32 i_crtime_extra; /
extra FileCreationtime (nsec << 2 | epoch) /
__le32 i_version_hi; /
high 32 bits for 64-bit version /
__le32 i_projid; /
Project ID */
};
EXT4_N_BLOCKS定义如下,即为15,其中EXT4_IND_BLOCK为12,表示有12个直接索引表,然后有1个一级间接索引表,1个二级间接索引表,1个三级间接索引表。

/*

  • Constants relative to the data blocks
    */
    #define EXT4_NDIR_BLOCKS 12
    #define EXT4_IND_BLOCK EXT4_NDIR_BLOCKS
    #define EXT4_DIND_BLOCK (EXT4_IND_BLOCK + 1)
    #define EXT4_TIND_BLOCK (EXT4_DIND_BLOCK + 1)
    #define EXT4_N_BLOCKS (EXT4_TIND_BLOCK + 1)
    inode_hashtable

那么根目录inode号为2是怎么获取到的?

我们可以知道,在mount文件系统时,会在内存中建立一个super_block;而在struct super_block中有struct dentry *s_root成员,s_root就指向的是根目录的dentry,而在struct dentry中有struct inode *d_inode成员,保存的是根目录的inode,inode号就可以从inode中获取。不需要再去读索引区中inode为2的inode内容,因为这部分内容已经在缓存中了,只需要去根目录具体所指的block区读取目录项即可。

猜你喜欢

转载自blog.csdn.net/katerdaisy/article/details/132778330