小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
在linux系统中有一个重要的概念:一切都是文件。 它把一切资源都看作是文件, 像是硬件设备等,我们对硬件的访问,可以通过读写文件的方式来进行。
应用程序对文件(资源)的访问会经过如下图所示的层次(即linux的IO栈):
图片来源:blog.csdn.net/github_3788…
如图所示,我们在应用层可能只是简单的一次read file,内核就需要SCI、VFS、FS、通用块管理层、磁盘等多个组件来进行复杂配合才能完成。
捋清楚这个图里的逻辑,也就理清了linux系统下读写文件的机制。本文的行文逻辑也将围绕这张图来展开。接下来,我将先解释下图中标注的User Space(用户空间或用户态)和Kernel Space(内核空间和内核态),之后再由下到上来看每一个节点代表的含义。
User Space(用户空间) 和 Kernel Space(内核空间)
操作系统的主要功能是管理硬件资源和为应用程序开发人员提供良好的环境,但是计算机系统的各种硬件资源是有限的,同时资源使用不规范造成的错误会影响整个计算机系统的运行,因此为了保证每一个进程都能安全的执行。处理器设有两种工作模式:“用户态”和“内核态”,处于用户态的程序只能访问用户空间,一些容易引发安全问题的操作会被限制在内核态执行,内核态可以访问内核空间,系统调用是连接两者的桥梁。
图片来源:segmentfault.com/a/119000003…
如上图所示,系统调用将linux分为用户态和内核态。
用户态:当进程在执行用户自己的代码时,则称其处于用户态。用户空间就是用户进程所在的内存区域。
内核态:当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核态,内核是一种特殊的软件程序,主要控制计算机的资源访问。内核空间就是内核所占据的内存区域。
为了使应用程序访问资源,如cpu、内存、io等资源,内核需要提供一组通用的访问接口,这些接口就是sci(system call interface)。
Physical Disk(物理磁盘)
我们知道现代计算机大部分文件存储功能都是由磁盘这种设备提供的,它是文件的物理存储介质。
磁盘能够提供信息存储的功能基于一种磁性存储介质。磁性存储介质能够被磁化,且磁化后会长久地保留被磁化的状态,这种被磁化状态能够被读取出来,同时这种磁化状态还能够不断地被修改,磁化正好有两个方向,可以表示0和1。
磁盘是把这种磁性存储介质做成一个个盘片,每一个盘片上都分布着数量巨大的磁性存储单位,使用磁性读写头对盘片进行写入和读取。
关于磁盘的物理结构,如下图所示:图片来源:tech.meituan.com/2017/05/19/…
磁盘内部主要部件为磁盘盘片、传动手臂、读写磁头和主轴。实际数据是写在盘片上,读写主要是通过传动手臂上的读写磁头来完成,实际运行时,主轴让磁盘盘片转动,然后传动手臂可伸展让读取头在盘片上进行读写操作。
图片来源:blog.csdn.net/jinking01/a…
上图中,右边是磁盘盘片垂直视角,左边是立体视角。如图所示盘片被分为许多扇形的区域,每个区域叫一个扇区,磁盘上中每个扇区的大小固定为512字节。盘片表面上以盘片中心为圆心,不同半径的同心圆称为磁道,不同盘片相同半径的磁道所组成的圆柱称为柱面。
为了在磁盘上写入和读取数据,我们需要采取一定寻址方式。
对于机械硬盘而言,对应两种寻址方式:CHS寻址方式和LBA寻址方式。
- CHS寻址方式:磁盘上的读写和读取都是沿柱面进行的,也就是一个柱面内依次从低序号向高序号盘片进行读写,读写完一个柱面的最后一个盘片的数据后,再转到下一个柱面。在柱面读取数据时,是按照磁头的序号依次读写的,在一个磁道内,是按照扇区依次读写的。磁盘读写的整体顺序依次为Cylider(柱面)、Head(磁头)、Sector(扇区),这也是CHS寻址名称的由来。
CHS要求每个磁道的扇区数相等,而外道的周长要大于内道,所以外道的记录密度要远低于内道,不仅造成了空间的浪费,也限制了磁盘的容量。为了进一步提高磁盘容量,厂商开始该用等密度结构生产磁盘,也即,外道磁道的扇区数比内圈磁道的扇区数要多,采用这种结构后,寻址方式也发生了改变。 - LBA寻址方式(Logic Block Address) ,LBA寻址是一种“线性寻址模式”, 这种模式下,不考虑磁盘的物理结构,直接将磁盘上的所有扇区依次从0开始编号。直到磁盘的最大扇区数减1。
衡量磁盘性能的主要方式是磁盘完成一个IO请求所花费的时间。完成一次磁盘IO所需的时间可分解为寻道时间、旋转延时时间、数据传输时间。
- 寻道时间:指将读写磁头移动至正确的磁道上所需要的时间。
- 旋转延迟时间:盘片旋转将请求数据所在扇区移至读写磁头下方所需时间。
- 数据传输时间:完成传输所请求的数据所需要的时间。
其中影响比较大的是寻道时间和旋转延时时间。
基于磁盘的物理结构,我们可以看出磁盘的连续读写性能好,但随机读写性能差。这是因为磁盘寻道时间(磁头移动到正确的磁道时间)耗时,随机读写时,磁头需要不停的移动,时间都浪费在寻址上,所以性能不高。
磁盘是现代计算机系统中最常用的存储数据的方式,但是磁盘只是存储数据的一种物理手段,缺少的是组织。这个组织以分区的名义出现,磁盘分区将磁盘划分为几个逻辑单元,每个单元可以单独被管理。
磁盘将有关分区位置和大小的信息存储在一个被称为分区表的区域中,操作系统在读取磁盘之前都要先读取分区表。
磁盘分区只是简单地划分磁盘上的空间,但是不足以以有序的方式(文件)存储数据,为此我们需要另一个系统——文件系统(后面的模块会详细说明)。
硬盘分区是硬盘结合到文件体系的第一步,本质是把磁盘这个物理概念转化成分区这个逻辑概念,为一下格式化(格式化为不同的文件系统)做准备。分区并不是必须的,我们可以把整块磁盘作为一个分区。但是从数据的安全性和系统性能角度来看,一般都会对磁盘进行分区。
现在主流的分区标准有两种:MBR(Main Boot Record)和GPT(GUID Partition Table)
- MBR:MBR信息存在于磁盘最开始的512字节(第一个扇区)中,这个扇区中有磁盘主引导记录(MBR)以及分区表,其中分区表仅占64字节,本身只能记录四块分区(分区本身就是对分区表进行设置)。 只能分四个区太少了,于是就有了扩展分区的概念,扩展分区的分区信息记录在额外的扇区中。
图片来源:www.bilibili.com/read/cv2324…
- GPT: 该方案中只有一种分区类型,主分区。磁盘中包含的分区数量没有限制。它是 Unified Extensible Firmware Interface 标准定义的分区规范。使用 GUID 或 Linux 中的 UUID 来定义分区和分区类型。
linux下,使用fdisk命令进行磁盘分区。
fdisk [必要参数][选择参数]
Device Driver(磁盘驱动)
磁盘驱动。驱动程序是一种计算机程序,它操作附在计算机上的特定类型的设备。驱动程序为硬件设备提供了一个软件接口,使操作系统和其他程序能够访问硬件功能,而不需要知道正在使用的硬件的精确细节。
General Block Device Layer(通用层)
不同的磁盘驱动会提供不同的IO接口,为了对内核屏蔽磁盘驱动接口的不同,我们需要进一步将这一层抽象,为内核提供一个统一的IO操作接口。
file system(文件系统)
上面讲磁盘分区时我们提过,分区不足以以有序的方式存储数据块(文件),为此我们需要另一个系统——文件系统。在磁盘分区之后把它格式化成具体的文件系统, 对应图中的Ext3、Ext4、...Btrfs。
格式化分区
mkfs -t ext3 /dev/sda1
表示将sda1分区格式化为ext3类型。以某种方式格式化磁盘的过程就是在其之上建立一个文件系统的过程。创建文件系统时,会在磁盘的特定位置写入关于该文件系统的控制信息。
挂载
在一个区被格式化为一个文件系统之后,它就可以被 linux操作系统使用了,只是这个时候Linux操作系统还找不它,我们还需要把这个文件系统注册进linux操作系统中,这个操作就是挂载(mount) 。
在linux中,使用目录树来进行管理,所谓的目录树就是以根目录(/)为主,向下呈现分枝状的一种文件结构。linux必须能够将根文件系统挂载到根目录上,当根目录挂载完成之后,我们可以将其它文件系统挂载于树形结构各种挂载点上。根结构下的任何目录都可以作为挂载点,挂载点实际上就是linux中的磁盘文件系统的入口目录。
图片来源:www.cnblogs.com/sammyliu/p/…
挂载使用mount命令
mount /dev/sda1 /test
表示将sda1挂载到/test目录。
文件系统(file system)是文件在逻辑上的组织形式,它以一种更加清晰的方式来存放文件。文件是计算机访问资源的载体,那么linux中,文件组成又是什么样的?
linux文件组成
文件是由什么组成的?首先文件存储在磁盘上,磁盘的最小存储单位为扇区,每个扇区存储512个字节。操作系统读取磁盘的时候,如果一个扇区一个扇区地读取,效率会很低,所以会选择一次性连续读取多个扇区,即一次性读取一个块(block)。由多个多个扇区组成的“块”,是文件存取的最小单位。
文件的数据存储在“块”中,同时我们还想存储文件的元信息,比如文件创建者、创建时间、大小等着中存储文件元信息的区域叫做inode。每个文件都有对应的inode。
所以可以说文件=数据块+inode组成。
Inodb也会消耗磁盘空间,磁盘格式化时,操作系统自动将硬盘分成两个区域,一个数据区;一个inode区。inode节点的总数在格式化时就已给定。由于每个文件都必须有一个inode,因此可能发生磁盘还未满,但inode已经用光的场景,此时我们也无法在磁盘上创建新文件。
Vitual file system(VFS虚拟文件系统)
VFS位于File system的上层,扮演着文件系统管理者的角色,它的作用是屏蔽下层具体文件系统的差异,为上层的操作提供一个统一的接口。
VPS包含着向下层文件系统转换的一系列结构。主要包括四个主要的数据结构:super block、inode、dentry、file。
- Super block:表示一个文件系统,它存储一个已安装的文件系统的控制信息,包括文件系统名称(如Ext2)、文件系统的大小和状态、块设备的引用和元数据信息。vfs super block存在于内存中,它在文件系统安装时建立,并且在文件系统卸载时自动删除。
- inode:inode对象存储了文件的相关元数据信息。inode分vfs的inode和文件系统的inode,前者在内存中,后者在磁盘中。
- dentry(目录项):引入目录项对象的概念主要是出于方便查找文件的目的。不同于前面的两个对象,目录项对象没有对应的磁盘数据结构,只存在于内存中。一个路径的各个组成部分,不管是目录还是普通的文件,都是一个目录项对象。
- file(文件对象):文件对象描述的是进程已打开的文件。一个文件可以被多个进程打开,所以一个文件可以存在多个文件对象,但是其对应的inode和目录项对象是唯一的。
system call interface(系统调用接口)
前面我们也提到了,为了使应用程序访问资源,如cpu、内存、io等资源,内核需要提供一组通用的访问接口,这些接口就是sci(system call interface) 。
像是我们经常用到的文件读写操作,open、read、write操作都是SCI。
参考文档:
www.cnblogs.com/huxiao-tee/…
www.cnblogs.com/bellkosmos/…
juejin.cn/post/684490…
tech.meituan.com/2017/05/19/…
www.eassos.cn/jiao-cheng/…