Linux内核大讲堂 () 督脉之虚拟文件系统(1)

在上一节<<Linux内核大讲堂 () 传说中的字符设备(4)>>中我们略微跟了一下文件系统相关的代码,虽然跟的不多,但是总算和虚拟文件系统和ext3打了个招呼。接下来就要专门讲文件系统了。文件系统也是分层的,简单来说分两大层。上层是虚拟文件系统,显然下层就是非虚拟文件系统了,就是“实际”的文件系统。什么才算实际?呵呵。高中学过反证法,这时候你就感谢那些比我们起的都早,睡觉比我们都晚的高中老师吧。大学老师嘛,我就不说你们了,做生意的做生意去,骗项目经费的就骗项目经费去,该干嘛干嘛去,和老子无关。

我们高中老师教会我们要有逆向思维,这些老师如果会玩内核,再教学生,我想大家就不会感觉虚拟文件系统这么难了,最少伟大的高中老师可以把虚拟文件系统和“实际文件系统”讲的很清楚。高中老师呢,我是请不来了,大家就勉为其难听我讲一下算了。

我们先把虚拟搞清楚,实际的意义就水落石出了。虚拟在我看有两层含义,首先我们看一看C++的关键字vitural,不用我多说,实现继承的一种重要手段。Linux是用C写的,没法用vitural,所以把共性抽出来让上层的实际文件系统来“继承”。显然“实际文件系统”要实现“基类”的一些“成员”才能工作,具体要实现哪些“成员”这就就看实际情况了。虚拟的第二层含义其实是与存储相关的,因为“实际文件系统”是需要存储在外存上的,比如磁盘、FLASH等非易失性存储器上。而虚拟文件系统则不会占用任何外存,他只会在内核运行的过程中占用内存资源,电一掉,就game over了!

虚拟文件系统中有一些概念是和我们通常所理解有点不一样,非常有必要先说明,否则大家会头晕。

首当其冲的当然是文件这个概念了,在虚拟文件系统中也有文件这个概念,叫文件对象,我们回顾一下之前讲字符设备中提到的fd。其实fd就是一个数字,这个数字与我们的文件对象就像许仙和白娘子一样,无论法海怎么坏,都拆不散的。有代码为证:

所在文件位置:fs/open.c

函数调用堆栈:sys_open()->do_sys_open()->fd_install(fd, f);

下面是fd_install()的函数定义:

void fd_install(unsigned int fd, struct file *file)

{

         struct files_struct *files = current->files;

         struct fdtable *fdt;

         spin_lock(&files->file_lock);

         fdt = files_fdtable(files);

         BUG_ON(fdt->fd[fd] != NULL);

         rcu_assign_pointer(fdt->fd[fd], file);

         spin_unlock(&files->file_lock);

}

第一行,struct files_struct *files = current->files;这中间的cureent其实就是代表了当前进程。由此可见文件对象是属于进程的一种资源,进程是整台机器硬件资源的虚拟,这整台机器自然包括了我们平时用于存放陈冠希老师作品的外存储设备了,最典型的就是硬盘啦。硬盘被虚拟成了file,然后伟大的linus进一步将其简化成一个fd,供我们这些菜鸟使用。另外文件对象做为进程的资源,也是一个动态的概念,你可以认为linux内核为我们准备了一个“文件对象池”,我们要的时候(open)他就分配一个给我们,不要了,我们就归还(close)给他。并且这个池子还比较聪明,随着你要求的提高(同时打开的文件数量变大)而跟着增加池子里文件对象的数量。在这里我们先不讨论这些高级的细节。只要知道有这么回事就行了。

所以文件对象根本不是我们通常意义所说的文件,真正意义的文件其实就是存储在外存储器(对于内存型文件系统则还是存在内存上)上的一块数据而已。这个文件可以是我们通常所说的文件或目录。

说到目录,我们通常理解的目录就是一种特殊的文件,和管道,设备等一起构成了linux下所谓的“一切皆文件中所指的文件。挺绕的,几个文件搞来搞去有点晕了。仔细体会一下。而在虚拟文件系统中的目录对象,则是一个更加抽象的东西,这个玩意有人也把他叫为目录项对象,有的又叫目录项缓存,有的又叫dcache,还有的叫目录项cache。在这里我们统一叫这个玩意为目录项对象。我们不是孔兄,不用去研究茴香豆的茴字有几种写法,这年头我发现就是因为孔兄太多,玩内核较熟的同志其实有的时候经常是上一句说目录项对象,下一句说dcache,撞到像我这种会点的还好,要是和新手这么讲的话,等新手变老手的时候,回想起当年你那装B的鸟样,不问候你先人才是怪事。OK。牢骚发的差不多了。

目录项对象的作用其实正如他的别名dcache,就是个目录项缓存而已,我们在一个目录下运行ls的时候(这个目录是指我们通常所说的目录),可以查看到当前目录下所有的子目录或者文件,如果运行ls –a,还可以查看另外两个东东:...。分别指代当前目录和上一级目录。想像一下吧,这整个结构就像是一颗树。并且我们经常要做目录切换的操作,每操作一次,就要读一次相应的信息,操作一次外存储设备(我们这里就假定是硬盘吧),硬盘累,内核也累,所以目录项的作用其实就是缓存。内核允许这个缓存也就是说目录项的个数默认是根据内存大小来算的,并且在内存吃紧的情况下又会回收。致于这个算法我就先不扯了。只要知道有这么一回事就行了,其实我们在学习内核的过程中发现了linux内核的一个特性,说夸张点叫智能,说得实在点就是具有自调节功能。

Inode,索引节点,又有人叫索引节点对象,在这里我们全都叫索引节点对象,全部的名字都统一叫XX对象有三个原因,一,与传统的概念区分开发。二,统一后缀,大家听起来也舒服点。最后,这个原因也是最重要的,因为虚拟文件系统采用了面向对象的思想,将数据与算法(算法后面会讨论)统一封装在我们所说的“对象”当中。索引节点对象是本文引入的第三种对象,这些对象都很重要,但是就文件系统的核心而言,索引节点对象是重中之重,理解了索引节点对象就理解了虚拟文件系统的一半。索引节点对象代表了我们通常所说的文件。一般来说都存储在磁盘等外存储设备上,当然啦,某些特例除外。比如procfssysfs等伪文件系统中的索引节点对象就直接放在内存里面啦。索引节点对象可以被多个目录项对象引用,比如硬链接。(软链接不是的,软链接是有自已的索引节点对象的,因此可以跨文件系统),在这里有必要说明一下,索引节点对象也和目录项对象一样,也是会缓存到内存中的。

超级块,又名super block,也有人叫超级块对象等。一般来说一个超级块对象就代表了一个被挂载的文件系统,或者说一个分区吧。一个文件系统可以被同时挂载到一个或多个地方。超级块对象是个家长,一家之中家长最大,没有家长,哪来的孩子(索引节点对象等)啊?不过最近据说谢霆锋家长怀疑孩子不是自已造的。哎,老婆的相片也照了,钱也被卷走了,突然间孩子是不是自已造的都不知道了,真悲剧!不过在linux内核中永远不会有这种悲剧发生,每个孩子都知道自已的亲爹是谁,每个爹也不需要借助DNA检测技术能认得自已的孩子。

Address space object,地址空间对象,这是一套统一外存与内存的接口,比如我们经常会将一个文件利用mmap映射成一段内存,这个就需要用到地址空间对象了,地址空间对象主要就是为了索引节点管理缓存中的各种页对象。

好了,到这里我们要总结一下了,实际位于磁盘上的对象有几个?

两个,超级块对象和索引节点对象,在文件系统被挂载后,我们进行查看或操作时就会多出文件对象和目录项对象。文件对象是为了方便我们用户使用的,而目录项对象是起缓存作用,加速我们的操作,降低硬盘的读写次数。

别急,还有一个东西要讲一下。file_system_type,这个东西有的同志又叫文件系统类型,有的又叫文件系统对象。没事,我们这里全都叫文件系统对象。这个,才是真正描述一个文件系统的,是一个更高层次的概念。比如一个ext3文件系统,我们一个ext3类型的分区中有一个ext3超级块对象,但我们LINUX可以支持多个分区,这时对应有多个ext3超级块对象,这些对象按照先后顺序挂在ext3文件系统对象上。所以真正的老大是文件系统对象。就像一个家族的族长一样。而我们都知道性氏有很多,比如有的姓张,有的人姓李,所以在我们的内核中难免会有多个文件系统对象。

仔细理解这些概念,一定要想清楚,这些东西是文件系统最基本的概念。好了,今天就先到这吧。下一节见。

 

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐