在LINUX系统下, 一切皆是文件。所有的读写, 包含块设备, 字符设备,socket, 管道等的操作, 都被设计为对文件的IO操作。
文件系统的位置
在LINUX系统下, 所有的文件及设备都是通过文件系统来操作的, 文件系统在整个系统中处于核心的地位。
在一个进程里面, 我们每打开一个文件, 就会在内核里面保存对应改文件的一个file结构, 在该结构里面有一个f_entry指向问价的目录项dentry, dentry是一个树形的结构, 通过某一个dentry我们可以向上找到该节点的父节点, 向下找到子节点。 在dentry里面有一个d_node字段, 代表给目录指向的inode, inode记录了文件的许多的元数据信息, 通过它我们可以知道文件的访问权限以及相关的数据块的位置信息等。
fs_struct主要记录了某一种文件系统的系统结构,每一种具体的文件系统都有root dentry和pwd dentry分别来记录文件系统root dentry的位置和当前的dentry。root dentry记录了文件系统的挂载点, 通常就是根目录。dentry里面的d_op记录了可以进行的操作, 比如创建删除dentry等, 就会将文件系统从根目录逐层的扩展开来。
还有一个vfsmoun列表, 记录了所有注册过的文件系统, 以及该系统的super_block。
VFS架构
LINUX能够支持多种文件系统, 比如, XFS,EXT3,EXT4以及GlusterFS等等, 它们对外的使用方式是一样的, 它们有统一的对外接口, 对于应用层, 无需要知道具体的文件系统的实现细节,只要对文件操作的接口编程就可以。LINUX文件系统之所以能做到对外一致性的实现, 最重要的实, 它提供了VFS层, 它处于具体的文件系统了应用层之间。
引用网上的一张图, 显示VFS的结构:
如果要新添加一种新的文件系统, 只需要针对VFS提供的接口,实现这些接口, 并且将将新的文件系统添加到系统中去。我的理解是, 每一种文件系统都有自己的具体实现方式, 在底层与磁盘的交互是与硬件的驱动程序紧密相关的, 作为一个开发人员, 我们没有办法知悉每一种文件系统底层的实现细节, 但是可以很明确知道它能够对外部提供什么什么接口。
page cache
page cache是操作系统读写磁盘文件的时候, 为了提升性能, 将一部分内容放在内存缓存。我们可以用free命令来看系统的page 缓存情况, free是系统读取/proc/meminfo来展示的。
$free -h
total used free shared buff/cache available
Mem: 251G 4.3G 181G 225M 65G 245G
Swap: 15G 0B 15G
项目 | 含义 |
---|---|
total | 系统总内存大小(分物理内存mem、交换分区swap) |
used | 已使用的内存(total - free - buffers - cache) |
free | 未使用的内存 |
shared | 通常情况下是tmpfs(内存文件系统)使用的内存 |
buffers | 内核缓冲区使用的内存 |
cache | page cache和slab所占用的内存之和 |
buff/cache | buffers + cache |
inode cache
为了提升inode的访问效率, VFS在每次访问inode的时候, 首先从inode cache里面查找, 该cache里面采用了一个hash+链表的方式。 具体可以参考: The VFS inode cache.
dentry cache
dentry cache也是为了提升文件路径到dentry的路径查找效率, 其实现方式和inode cache类似, 底层采用了hash+链表的方式。 具体细节可参考: The VFS dentry cache。
减少dentry & inode cache的方法
有时候, 系统可能会导致dentry cache或者inode cache占用了过多的内存空间, 可以通过如下的方式来调整:
http://www.science.unitn.it/~fiorella/guidelinux/tlk/node111.html
参考文章
https://blog.youkuaiyun.com/heikefangxian23/article/details/51579971