内核达人

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2|回复: 0

目录在Linux内核中的样子,dcache

[复制链接]

25

主题

25

帖子

83

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
83
发表于 7 天前 | 显示全部楼层 |阅读模式
哈喽,大家好,我就是那个不喜欢在大厂搬砖,不喜欢在研究院做研究,只喜欢创业做计算机底层课程的coder,子牙老师

众所周知,我最近在更新《实战Linux内核》四期的视频:源码级带你透彻理解VFS+手写文件系统,今天算是把目录这东西玩明白了,写篇文章分享一下

在图形界面的眼中,目录长这样
在黑窗口那里,目录长这样
在Linux内核眼中,目录长啥样呢?目录在Linux内核中又是如何存储的呢?目录在Linux内核中有哪些状态呢?dcache又是什么?目录的CRUD在Linux内核中是如何实现的……

当然,关于目录不仅仅只有这么几个问题,这篇文章就先讲明白这几个吧。其实你把这篇文章讲到的都看懂了,相关的Linux内核源码你就能轻松看懂了,不用等我分享,你自己就能玩明白

以下,enjoy

Linux内核眼中的目录
在Linux内核中,一切皆文件,目录也是一种文件。Linux内核通过dentry+inode来描述一个文件,如图
dentry主要用来记录文件名、关联的inode、目录层次关系、关联dcache、引用计数、关联超级块等
其中目录层次关系是这样的,子目录的dentry->d_child挂到父目录的dentry->d_subdirs上。通过遍历父目录的dentry->d_subdirs就能得到所有子目录的dentry+子文件的dentry

如果你想拿到某个目录的属性信息,比如
你就需要通过dentry->d_inode拿到目录的inode,里面存储的就是目录属性信息
这里拓展一下:文件系统分为dev形式的与非dev形式的。如果是nodev形式,即内存文件系统,那目录的层次关系完全依赖dentry的两个属性维护:d_child、d_subdirs

如果是dev形式的,就是需要依赖硬盘的,比如EXT4文件系统,那目录的dentry、inode是需要落盘的。EXT4文件系统目录对应的dentry叫ext4_dir_entry_2
EXT4文件系统目录对应的inode叫ext4_inode
前面提到的dentry、inode,你可以理解成是Linux内核中的VFS的,独立于具体的文件系统。Linux内核在操作EXT4文件系统的目录的时候,会把ext4_dir_entry_2提取出来,填充到dentry中,会把ext4_inode的信息提取出来,填充到inode中

对于EXT4文件系统,子目录的dentry信息存储在哪呢?父目录的ext4_inode中有个属性i_block,用来存储硬盘块号,子目录的dentry信息就存储在这些磁盘中

EXT4文件系统存储内容,即i_block,是用传统的寻址算法:直接块、单间接块、双间接块、三间接块,还是使用extent算法,具体怎么玩的,后面再分享。关注公众号【硬核子牙】,看计算机底层硬核文章

关于nodev形式的文件系统的目录在内存中的样子,dev形式的文件系统的目录在内存中+在硬盘中的样子,你应该都清楚了吧

接着走~

dcache
VFS的dentry,在Linux内核中是如何存储的呢?是存储在dcache中的,如图
不论是dev形式的文件系统,还是nodev形式的文件系统,Linux内核最终都会alloc一个dentry与具体的文件或目录关联,把这个dentry存储到全局的dentry_hashtable中,这个就是大家看有些资料提到的dcache

dcache是个什么数据机构呢?hashtable,即哈希表

哈希表,玩底层不多的小伙伴可能不太理解,一句话说到位就是:数组+链表!先把要存储的dentry,通过散列函数,算出key,存储到key关联的位置。再来一个dentry,经过散列函数计算,如果出现了撞针,即key相同,一般采用头插法,插到之前元素的前面

看下dcahce,即dentry_hashtable的庐山真面目

static struct hlist_bl_head *dentry_hashtable __read_mostly;struct hlist_bl_head {        struct hlist_bl_node *first;};struct hlist_bl_node {        struct hlist_bl_node *next, **pprev;};

存储时,value不用说,就是dentry,那key是怎么算出来的呢?就以将mnt目录加入dcahce为例

先找生成key的相关代码:hash_name,这个函数就是散列函数
看这个函数怎么用的
可以看出来:要计算一个目录的hash key,需要传入父目录的dentry的内存地址,还有就是字符串mnt。不知道你有没有注意,散列函数hash_name最终输出的结果是hashlen,那这个hashlen与hash key之间有没有关系呢?

自然是有的,看两个宏
hashlen共64位,其中尾32位是hash key。那高32位呢?存储的是目录名的长度,要这个有什么用呢?后面查找目录精确匹配用,比如在函数__d_lookup_rcu中
至此,文件或目录对应的dentry在dcache中是如何存储的,你应该清楚了吧!

接着走~

论证
我前面说了,你只要掌握了足够的基础知识,Linux内核这块的代码你就能轻松看懂,那咱们来论证一下如何?就看目录的创建与删除两个函数吧

目录的创建,主要两件事:申请内存,入口函数是d_alloc,将dentry插入dcache,入口函数是d_add

来看看d_alloc
先申请内存,然后设置父目录,将子目录的d_child挂到父目录的d_subdirs链表中

再来看d_add
将dentry插入dcache,核心函数是__d_rehash
轻松看懂吧

目录的删除呢?目录的删除涉及到两步:脱离dcache,入口函数是d_delete,核心逻辑在d_drop中;释放内存,入口函数是d_free

来看看d_delete
再来看看d_free
目录父子关系的建立,插入dcahce与从dcache中断链,申请内存,释放内存……是不是能轻松看懂了。剩下的函数VIP课中再带大家读源码,本篇文章就不继续了,感兴趣的自行看源码吧


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|内核达人

GMT+8, 2025-12-6 12:38 , Processed in 0.082883 second(s), 20 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表