- 作者: 陈孝松
- 主页: chenxiaosong.com
- 哔哩哔哩: 陈孝松
- 课程: chenxiaosong.com/courses
- 博客: chenxiaosong.com/blog
- 贡献: chenxiaosong.com/contributions
- 邮箱: chenxiaosong@chenxiaosong.com
- QQ交流群: 544216206, 点击查看群介绍
点击这里在哔哩哔哩bilibili在线观看配套的加餐视频(就是一些补充)。
一般的Linux书籍都是先讲解进程和内存相关的知识,但我想先讲解文件系统。第一,因为我就是做文件系统的,更擅长这一块,其他模块的内容我还要再去好好看看书,毕竟不能误人子弟嘛;第二,是因为文件系统模块更接近于用户态,是相对比较好理解的内容(当然想深入还是要下大功夫的),由文件系统入手比较适合初学者。
虚拟文件系统英文全称Virtual file system,缩写为VFS,又称为虚拟文件切换系统(virtual filesystem switch)。所有的文件系统都要先经过虚拟文件系统层,虚拟文件系统相当于制定了一套规则,如果你想写一个新的文件系统,只需要遵守这套规则就可以了。
VFS虽然是用C语言写的,但使用了面向对象的设计思路。
需要注意目录项表示路径中的一个部分,如/home/linux/file
路径中,/
、home
、linux
是目录,属于目录项对象,file
属于文件,也属于目录项对象。也就是说,目录项也能表示文件。目录项对象结构体定义在include/linux/dcache.h
中,成员不多。
struct dentry {
/* RCU 查找涉及的字段 */
unsigned int d_flags; /* 受 d_lock 保护,目录项标识 */
seqcount_spinlock_t d_seq; /* 每个目录项的 seqlock */
struct hlist_bl_node d_hash; /* 查找哈希列表 */
struct dentry *d_parent; /* 父目录 */
struct qstr d_name; // 目录项名,d_name.name是字符串数组
struct inode *d_inode; /* 名称所属的位置 - NULL 表示negative, 关联的索引节点 */
unsigned char d_iname[DNAME_INLINE_LEN]; /* 短文件名 */
/* 引用查找也涉及以下内容 */
struct lockref d_lockref; /* 每个目录项的锁和引用计数,用d_count()函数获取 */
const struct dentry_operations *d_op; // 目录项操作指针
struct super_block *d_sb; /* 目录项树的根,文件的超级块 */
unsigned long d_time; /* 由 d_revalidate 使用,重置时间 */
void *d_fsdata; /* 文件系统特有数据 */
union {
struct list_head d_lru; /* LRU list,Least Recently Used 最近最少使用链表 */
wait_queue_head_t *d_wait; /* 仅用于查找中的项目 */
};
struct list_head d_child; /* 父列表的子项,目录项内部形成的链表 */
struct list_head d_subdirs; /* 子目录链表 */
/*
* d_alias 和 d_rcu 可以共享内存
*/
union {
struct hlist_node d_alias; /* inode alias list,索引节点别名链表,当有多个硬链接时,就有多个dentry指向同一个inode,多个dentry都放到d_alias链表中 */
struct hlist_bl_node d_in_lookup_hash; /* 仅用于查找中的项目 */
struct rcu_head d_rcu; // RCU加锁
} d_u;
} __randomize_layout;
目录项有3种状态:
- 被使用:
d_inode
不为空,d_count()
大于等于1
- 未被使用:
d_inode
不为空,d_count()
为0
,注意曾经可能使用过 - 无效状态:
d_inode
为空
目录项缓存有3种:
- "被使用的"目录项链表:
inode->i_dentry
链表,一个inode
可能有多个链接,一个inode
可能有多个dentry
- "Least Recently Used 最近最少使用"链表:
d_lru
链表,包含未被使用和无效状态的dentry
- 散列表:
dentry_hashtable
链表,散列值由d_hash()
计算,d_lookup()
查找散列表
目录项让相应的索引节点的i_count
为正,目录项被缓存了,索引节点肯定也被缓存了。