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里面存了20个目录项(struct ext4_dir_entry),可以找到目录home对应的inode号为100。

获取bzw对应的inode号:上一步获取到了目录home的inode号,在索引区读取inode号为100存的inode内容。假如inode中存的block地址为2000,那么去读地址为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里面存了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_blockEXT4_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区读取目录项即可。

相关推荐
天空'之城3 分钟前
Linux 系统编程 14:Reactor 反应堆模式
linux·开发语言·网络编程·reactor 反应堆模式
法号:行颠13 分钟前
《Linux内核源码全景解读:从上电到用户态》之 目录
linux
mounter6253 小时前
深入解析 RDMA 中的 Address Handler (AH) 缓存:AWS EFA 驱动的硬件演进与软件复用艺术
linux·kernel·rdma·hashtable·hash table·address handle
笑锝没心没肺10 小时前
fail2ban工具安装配置及使用
linux·运维·服务器
大卡片12 小时前
linux内核驱动开发
linux·运维·驱动开发
心心喵13 小时前
[linux] nohup和pm2的区别 进程保活
linux·运维·服务器
醉熏的石头14 小时前
Ubuntu 中的编程语言(中)
linux·ubuntu·scala
dddwjzx17 小时前
嵌入式Linux C应用编程入门——信号
linux·嵌入式
范什么特西18 小时前
网络代理问题
java·linux·服务器
utf8mb4安全女神18 小时前
【Redis数据库】哨兵集群/redis集群/安装配置/主从复制/数据持久化操作/数据结构/安全限制/PHP redis/
linux·服务器·数据结构·数据库·redis·缓存