Linux磁盘与文件系统(一)
1、Linux文件系统
1.1、磁盘的组成与分区的复习
整颗磁盘的组成主要有:
- 圆形的磁盘盘(主要记录数据的部分);
- 机械手臂,与在机械手臂上的磁盘读取头(可擦写磁盘上的数据);
- 主轴马达,可以转动磁盘盘,让机械手臂的读取头在磁盘盘上读写数据。
磁盘盘的物理组成分为:
- 扇区(sector)为最小的物理存储单位,且依据磁盘设计的不同,目前主要有512bytes和4K两种格式;
- 将扇区组成一个圆,就是磁柱(Cylinder);
- 早期的分区主要以磁柱为最小分区单位,现在的分区通常使用扇区为最小分区单位(每个扇区都有其号码);
- 磁盘分区表主要有两种格式:一种是限制较多的MBR分区表,一种是较新的且限制较少的GPT分区表;
- MBR分区表中,第一个扇区最重要,里面有:主要开机区(Master boot record,MBR)和分区表(partition table),其中MBR占有446bytes,而partition table则占有64bytes;
- GPT分区表除了分区数量扩充较多之外,支持的磁盘容量也超过2TB。
实体磁盘与虚拟磁盘:
- /dev/sd[a-p][1-128]:为实体磁盘的磁盘文件名
- /dev/vd[a-d][1-128]:为虚拟磁盘的磁盘文件名
1.2、文件系统的特性
磁盘分区完之后都需要格式化,因为每种操作系统所设定的文件属性/权限并不相同,为了存放这些文件所需的数据,因此就需要将分区进行格式化,以成为操作系统能够利用的“文件系统格式”。
那文件系统是如何运作的呢?这与操作系统的文件数据有关。较新的操作系统的文件数据除了文件实际内容外,通常含有非常多的属性,例如Linux的文件权限(rwx)与文件属性(拥有者、群组和时间参数等)。文件系统通常会将这两部分的数据分别存放在不同的区块,权限与属性放置到inode中,至于实际数据则放置到data block中。另外,还有一个超级区块(superblock)会记录整个文件系统的整体信息,包括inode与block的总量、使用量、剩余量等。
每个inode和block都有编号,至于这三个数据的意义可以简略说明如下:
- superblock:记录此filesystem的整体信息,包括inode/block的总量、使用量、剩余量等,以及文件系统的格式与相关信息等;
- inode:记录文件的权限与属性,一个文件占用一个inode,同时记录此文件的数据所在的block号码;
- block:实际记录文件的内容,若文件过大,会占用多个block。
这就是典型的索引式文件系统。假设某一文件的属性与权限放置到inode 4号,而这个inode记录了文件数据的实际放置点2,7,13,15这四个block号码,这时操作系统就能够依次排列磁盘的阅读顺序,可以一口气将四个block内容读完!
FAT格式的文件系统没有inode,每个block号码都记录在前一个block当中,读取过程如下(有点类似于单链表):
1.3、Linux的EXT2文件系统
inode的内容记录文件的权限与属性,至于block区块则是记录文件的实际内容。而且文件系统一开始就将inode与block规划好了,除非重新格式化(或者利用resize2fs等指令变更文件系统大小),否则inode与block固定后就不再变动了。如果文件系统高达数百GB,那么将所有的inode与block通通放置到一起将是很不明智的决定,为此,Ext2文件系统在格式化的时候基本上是区分为多个群组的,每个群组都有独立的inode/block/superblock系统。整个来说,Ext2格式化后优点类似于:
在整体规划当中,文件系统最前面有一个启动扇区(boot sector),这个启动扇区可以安装开机管理程序,这是一个非常重要的设计,因为如此一来我们可以将不同的开机程序安装到个别的文件系统最前端,而不用覆盖整颗磁盘唯一的MBR,这样就可以制作出多重引导环境。至于每个区块群组的六个主要内容说明如下:
-
data block(资料区块)
data block是用来放置文件内容的地方,在Ext2文件系统支持的block大小有1K,2K以及4K三种。在格式化的时候就固定了,且每个block都有编号,以方便inode记录。由于block大小的差异,会导致文件系统能够支持的最大磁盘容量与最大单一文件容量的差别:
Block大小 1K 2K 4K 最大单一文件限制 16GB 256GB 2TB 最大文件系统总容量 2TB 8TB 16TB block的基本限制如下:
- 原则上,block的大小与数量在格式化完就不能再改变了(除非重新格式化);
- 每个block内最多只能放置一个文件的数据;
- 承上,如果文件大于block大小,则一个文件会占用多个block数量;
- 承上,若文件小于block大小,则该block的剩余容量就不能再被使用了(磁盘空间会浪费)
-
inode table(inode 表格)
inode记录的至少会有:
- 该文件的存取模式(r/w/x);
- 该文件的拥有者与群组;
- 该文件的容量;
- 该文件的建立或状态改变的时间(ctime);
- 最近一次的读取时间(atime);
- 最近修改的时间(mtime);
- 定义文件特性的旗标,如Set UID;
- 该文件真正内容的指向;
inode的数量与大小也是在格式化的时候已经固定了,除此之外inode还有哪些特色呢?
- 每个inode大小均为128bytes(或256bytes);
- 每个文件都仅会占用一个inode而已;
- 承上,因此文件系统能够建立的文件数量与inode数量有关;
- 系统读取文件时需要先找到inode,并分析inode所记录的权限与属性是否与用户相符,若符合才开始实际内容block的读取。
inode记录的数据非常多,但偏偏只有128bytes,而inode记录一个block号码就要花掉4bytes,假设一个文件有400MB且每个block 4K时,那么至少也要花掉十万笔block号码的记录呢!inode哪有那么多?因此,inode记录block 号码的区域定义了间接地记录区,即多级索引。
-
superblock(超级区块)
superblock是记录整个filesystem相关信息的地方,没有superblock,就没有filesystem了。它记录的信息主要有:
- block与inode的总量;
- 未使用与已使用的indoe/block数量;
- block与inode的大小(block为1,2,4K,inode为128bytes或256bytes);
- filesystem的挂载时间、最近一次的写入数据时间、最近一次检验磁盘时间等;
- 一个vaild bit数值,若此文件系统已被挂载,则vaild bit为0,若未被挂载,则vaild bit为1。
一般来说,superblock大小一般为1024bytes。相关信息可以用dumpe2fs指令查看。
-
Filesystem Description(文件系统描述)
可以描述每个block group的开始与结束block号码,以及说明每个区段分别介于哪一个block号码之间。也可以用dumpe2fs来观察。
-
block bitmap(区块对照表)
空的block需要block bitmap来辅助查看。
-
inode bitmap(inode对照表)
空的inode号码。
1.4、dumpe2fs:查询Ext家族superblock信息的指令
[root@mysql ~]# dumpe2fs [-bh] 设备文件名
选项与参数:
-b:列出保留为坏轨的部分
-h:仅列出superblock的数据,不会列出其他的区段!
[root@mysql ~]# blkid <==可以列出目前系统中被格式化的设备
/dev/sda1: UUID="ef70d1b0-d320-4339-975f-92701572dfb9" TYPE="xfs"
/dev/sda2: UUID="zVZ55P-Jlrt-3w4I-qAJm-Nwgo-mZsT-Z3GkCW" TYPE="LVM2_member"
/dev/sr0: UUID="2020-04-22-00-54-00-00" LABEL="CentOS 7 x86_64" TYPE="iso9660" PTTYPE="dos"
/dev/mapper/centos-root: UUID="8989145a-a07f-46e2-a079-98eb11df89e0" TYPE="xfs"
/dev/mapper/centos-swap: UUID="4e9b4a44-92b1-406a-91ab-11edd02426da" TYPE="swap"
1.5、与目录树的关系
1.5.1、目录
当新建一个目录时,文件系统会分配一个inode与至少一块block给该目录。其中,inode记录该目录的相关权限与属性,并可记录分配到的那块block号码;而block是记录在这个目录下的文件名与该文件占用的inode号码数据。如果想查看root目录下的文件所占用的inode号码,可使用ls -i查看:
[root@mysql ~]# ls -il
总用量 4
33574978 -rw-------. 1 root root 1304 7月 21 16:11 anaconda-ks.cfg
33608817 -rw-r--r--. 1 root root 0 7月 28 15:40 test
1.5.2、文件
当新建一个文件时,文件系统会分配一个inode与相对应该文件大小的block数量给该文件。
1.5.3、目录树读取
比如说,想要读取etc/passwd这个文件,系统是如何读取的呢?
[root@mysql ~]# ll -di / /etc /etc/passwd
64 dr-xr-xr-x. 17 root root 224 7月 21 16:11 /
16777281 drwxr-xr-x. 74 root root 8192 7月 30 10:37 /etc
17709568 -rw-r--r--. 1 root root 934 7月 29 09:33 /etc/passwd
假设读取流程为一般用户:
-
/ 的 inode:
通过挂载点的信息找到 inode 为64的根目录 inode,且 inode 规范的权限让我们可以读取 block 的内容(有r与x);
-
/ 的 block:
经过上述的步骤取得 block 的号码,并找到该内容有 etc/ 目录的 inode 号码(16777281);
-
etc/ 的 inode:
读取16777281号的 inode 得知一般用户具有 r 与 x 的权限,因此可以读取 etc/ 的 block 内容;
-
etc/ 的 block:
找到passwd文件的 inode 号码(17709568);
-
passwd 的 inode:
读取17709568号的 inode 得知,一般用户具有 r 权限,因此可以读取 passwd 的内容;
-
passwd 的 block:
最后将该 block 内容的数据读出来。
1.6、EXT2/EXT3/EXT4文件的读取与日志文件系统
上一节只是读取,如果是新建一个文件或目录时,文件传统又是如何处理的呢?这时候就需要block bitmap及inode bitmap的帮忙了!假设我们要新增一个文件,此时文件系统的行为是:
- 先确定用户对于欲增加的文件的目录是否有w与x的权限,若有的话才能新增;
- 根据inode bitmap找到没有使用的inode号码,并将新文件的权限与属性写入;
- 根据block bitmap找到没有使用的block号码,并将实际的数据写入block中,且更新inode的block指向数据;
- 将刚刚写入的inode与block数据同步更新inode bitmap与block bitmap,并更新superblock的内容。
一般来说,我们将inode table与data block称为数据存放区域,至于其他的superblock、block bitmap与inode bitmap等区段被称为metadata(中介资料)。因为superblock、block bitmap与inode bitmap是经常变动的,每次新增、删除、编辑都会影响到这三个部分。
1.6.1、数据不一致的状态
如果发生了一些意外情况,例如:突然停电、系统核心发生错误等,导致系统中断,所以写入的数据仅有inode table 以及 data block而已,最后一个同步更新中介数据并没有完成,此时会发生metadata的内容与实际数据存放区产生不一致的情况。早期的Ext2会检查全部文件系统,太费时,这就引出了日志文件系统。
1.6.2、日志文件系统
为了避免上述问题导致的文件系统不一致的问题,文件系统专门规划出一部分,用来记录写入或修订文件时的步骤,简化一致性的检查步骤,也就是说:
- 预备:当系统要写入一个文件时,会先在日志记录区块记录某个文件准备要写入的信息;
- 实际写入:开始写入文件的权限与数据;开始更新metadata的数据;
- 结束:完成数据与metadata的更新后,在日志记录区当中完成该文件的记录。
这样,万一数据的记录过程当中发生了一些情况,系统只需要去检查日志记录区,就知道哪里不一致了,不需要检查整个文件系统。
1.7、Linux文件系统的运作
为了解决效率的问题,Linux使用的一个叫做异步处理的方式:
当系统加载一个文件到内存后,如果该文件没有被更改过,则在内存区的文件数据会被设定为干净(clean)的。但如果内存中的文件数据被更改过,此时该内存中的数据会被设定为脏的(dirty)。此时,所有的动作都还没在内存中执行,并没有写入到磁盘中!系统会不定时的将内存中设定为“dirty”的数据写回磁盘,以保证磁盘与内存的一致性。也可以使用sync指令手动写回。
文件系统与内存有非常大的关系:
- 系统会将常用的文件数据放置到主存储器的缓冲区,以加速文件系统的读/写;
- 承上,因此Linux的物理内存最后都被用光;
- 你可以手动使用sync来强制内存中设定为dirty的文件写回磁盘;
- 若正常关机,关机指令会主动呼叫sync;
- 但若不正常关机,由于数据尚未写回磁盘,因此重新启动后可能会花很多时间进行磁盘检查。
1.8、挂载点的意义
每个filesystem都有独立的inode/block/superblock等信息,这个文件系统要能够链接到目录树才能被我们使用。将文件系统与目录树结合的动作我们称为“挂载”。重点是:挂载点一定是目录,该目录为进入该文件系统的入口。
1.9、其他Linux支持的文件系统与VFS
常见的支持的文件系统:
- 传统文件系统:ext2/minix/MS-DOS/FAT/iso9660等等;
- 日志文件系统:ext3/ext4/ReiserFS/Windows‘NTFS/IBM’sNTFS等;
- 网络文件系统:NFS/SMBFS。
系统目前已加载到内存的文件系统:
[root@server ~]# cat /proc/filesystems
1.9.1、Linux VFS(Virtual Filesystem Switch)
Linux的核心是如何管理这些文件系统的?其实,整个Linux都是通过VFS的核心去读取文件系统的。也就是说,整个Linux认识的文件系统都是VFS在管理,使用者并不知道每个分区的文件系统是什么。
1.10、XFS文件系统
为什么默认的文件系统从Ext4变为了XFS了呢?
1.10.1、EXT文件系统:支持度广,但格式化超慢!
1.10.2、XFS文件系统的配置
xfs文件系统在资料的分布上,主要规划为三个部分,一个资料区(data section)、一个文件系统活动登录区(log section)以及一个实时运作区(realtime section)。
-
资料区(data section)
基本上,数据区就跟之前的ext家族一样,包括inode/data block/superblock等数据,都放置在这个区块。
-
文件系统活动登录区(log section)
主要被用来记录文件系统的变化。
-
实时运作区(realtime section)
当有文件被建立时,xfs会在这个区段里面找一个到数个extent区块,将文件放置在这个区块内,等到分配完毕,再写入到data section的inode 与 block里去。
1.10.3、XFS文件系统的描述数据观察
[root@server ~]# xfs_info 挂载点|设备文件名
[root@server ~]# df -hT /boot
文件系统 类型 容量 已用 可用 已用% 挂载点
/dev/sda1 xfs 1014M 137M 878M 14% /boot
[root@server ~]# xfs_info /dev/sda1
meta-data=/dev/sda1 isize=512 agcount=4, agsize=65536 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=0 spinodes=0
data = bsize=4096 blocks=262144, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0 ftype=1
log =internal bsize=4096 blocks=2560, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
- 第1行的 isize 指的是 inode 的大小,每个有 512bytes 这么大。至于 agcount 是存储群组的个数,共有4个, agsize 指的是每个存储区群组具有 65536 个 block。配合第 4 行的 block 设定为 4K,因此整个文件系统的容量就是 4*65536*4K 这么大!
- 第2行的 sectsz 指的是逻辑扇区的容量设定为 512bytes 这么大;
- 第4行里面的 bsize 指的是 block 的大小,每个 block 为4K的意思,共有 262144 个 block 在这个文件系统里;
- 第5行里面的 sunit 与 swidth 与磁盘阵列的 stripe 相关性较高;
- 第7行里面的 internal 指的是这个登录区的位置在文件系统内,而不是外部设备的意思。占用了 4K*2560 个 block ,总共约 10M;
- 第9行里面的 realtime 区域,里面的 extent 容量为 4K。