linux学习笔记2 磁盘与文件系统

Linux学习笔记2 磁盘与文件系统

关于磁盘的一些基础知识

  • 扇区,最小的物理储存单位,一般有512字节或者4K字节
  • 一圈扇区组成一个柱面
  • 早期分区使用柱面作为最小单位,现在则常用扇区
  • 磁盘分区表主要有两种格式,MBR分区表与GPT分区表
  • MBR分区表中第一扇区中存放有主开机记录(MBR 446字节)与分区表(64字节),因为分区表较小,所以只能有四个分区,当然可以有一个扩展分区,使用其他扇区来存放逻辑分区的信息
  • GPT分区表支持较多的分区数量(没有限制,但是windows只支持128个),也支持2TB以上的磁盘(MBR分区表只能用16字节储存一个分区,而这16个字节中,4个字节记录分区起始逻辑地址,4个字节表示扇区总数,他们都无法表示232以上的数字,而232 * 512字节 大约为2T https://www.jianshu.com/p/6b76ff13ca96

文件系统

分区后为什么要进行格式化?因为格式化将分区内容转换为操作系统可以利用的文件系统,使用不同的组织数据的方法。文件系统除了文件实际内容外还会储存其他的属性,如Linux的文件权限(rwx),文件属性(拥有者,群组,时间等),文件系统中,这两部分通常放在不同的区块中。

  • data block中存放文件的实际数据
  • inode 存放相关的权限与属性,一个文件占用一个inode,inode还会记录相关属性对应的block号码(目录中记录了文件名-文件的inode的对应关系,我们先找到inode再通过inode找到文件的实际数据块)
  • superblock用来记录文件系统的总体信息,如data block与inode的总量,使用情况等。

这种组织数据的方法被称为索引式文件系统。(FAT格式不是索引式文件系统而是类似于链表一样的组织形似,数据块要依次读出)

EXT文件系统

linux的ext文件系统(以ext2为例)就是索引式文件系统啦,除了文件数据,还储存了相当多的相关属性。ext文件系统在一开始格式化的时候就将inode与block分配规划好了,所以大磁盘的格式化可能会比较慢。并且大磁盘的inode和block如果都放在一起也不好管理,所以有了区块群组的概念,每个区块群组都有独立的inode/block/superblock。

区块群组的组成(都是以ext2为例):

  • data block 数据块

    ext2 仅支持1K 2K 4K三种大小,格式化的时候大小已经确定,这个会影响到整个文件系统支持的最大容量与单一文件最大大小。每个数据块中只能放一个文件。所以较大的块遇见大量零碎的文件会造成不小的浪费。

  • inode table

    inode记录了文件的属性以及该文件数据放在哪些block中,文件的存取模式,拥有者/群组,容量,三种时间参数以及特殊权限等信息。每个inode大小为128字节(ext4,xfs可以设置为256字节)系统读取文件时也会先找到inode,检查权限等信息后再通过inode记录的block查找实际的数据块。 128字节的inode为什么可以记录那么多的block信息呢?(正常情况,一个块就要花费4字节记录)。inode可以使用间接/双间接/三间接记录区 间接记录区指的是一个inode会额外使用一个区块来作为block号码的记录区,而双间接则是先使用第一个block来记录更多的block,在这些更多的block里面记录数据的block号,三间接同理 不过这还是有上限的,如1K的块大小时,上限大约为16GB,所以单文件大小存在限制。

  • superblock

    超级区块用来记录整个文件系统的相关信息,如:

    • block和inode的使用情况
    • block和inode的大小
    • 文件系统挂在时间,最后一次写入数据的时间等相关信息。
    • valid bit 文件系统被挂载时会置1
    • 每个区块群组都可能有一个超级区块,但都是第一个区块群组的超级区块的备份
  • 文件系统描述符

    描述了每个区块群组的开始与结束块的号码,并说明不同的部分(superblock bitmap inodemap等)再哪两个block号码之间

  • block bitmap 区块对照表

    标记哪些block是空的,可以用来记录新文件的

  • inode bitmap inode对照表

    记录inode map中的哪些inode可以写入

对文件系统的观察

先使用blkid列出系统中被格式化的设备 (lsblk也可以)。

/dev/sda1: UUID="5b97527f-f1fd-4f40-90ef-2c05c247c897" TYPE="ext4" PARTUUID="544e0bf2-01"

dumpe2fs /dev/sda1 输出了大量的信息(我这块1T的硬盘输出了七千多个区块群组),先单独看看超级区块的内容吧。

superblock

文件系统2

可以看见很多信息,如文件系统名称,上一次挂载的目录,默认挂载参数,文件系统的状态(clean/dirty),inode/block的总数/可用数,block的大小,每个区块群组的大小,历史写入量还有日志式系统的相关信息。

再看看区块群组的信息

区块群组

文件系统与目录树关系

目录也作为特殊的文件,创建时也会被分配一个inode和至少一个block,inode记录目录的权限和属性,block记录了目录下的文件名和文件名对应的inode号码。(所以对于目录的r权限可以读取出文件列表而w权限可以直接增加和删除目录下的文件,即使对文件无操作权限),目录的大小也取决于它用了几个block来储存文件名和inode信息。

对于文件来说,创建一个文件时,ext2会分配一个inode与足够容纳文件的block给该文件,如: 一个block为4K,创建一个100K的文件时,会有1个inode和26个block(inode只能由12个直接指向,所以多出的一个block用作inode间接记录)

读取目录树时,是一层一层向下读取的,并且读取到inode时,操作系统还会做权限的检查

日志式文件系统

在新建文件/目录时文件系统的处理流程:

  1. 对目录进行权限检查,看操作者是否有w与x权限
  2. inode bitmap 找到没有使用的inode的号码,并将文件的权限与属性写入
  3. block bitmap 找到没有使用的block号码,并把实际数据写入
  4. 更新两个对照表的内容接着更新超级区块中的内容

但是如果在写入的过程中突然系统中断了(如断电),数据写入只进行了一半,怎么处理呢?

ext2 在开机的时候会检查super block中的valid bit是否挂载与filesystem state (是否clean),来判断是否需要进行数据一致性检查,但是这是相当耗费时间的,因为要对于整个文件系统的元数据区块(超级区块和对照表)和数据区块进行一致性检查。所以有了日志式文件系统(ext2是没有日志journal机制的),在日志式系统中,操作流程如下

  1. 将要写入文件时,现在日志区块中记录文件准备要写入
  2. 实际写入
  3. 写入完成后,在日志区块中标记完成

这样即使写入过程发生了异常中断,操作系统也能很方便的定位到哪里出了问题,而不需要对整个文件系统进行检查。

文件系统的运行

linux运行时使用了异步处理的方式,文件载入到内存中,如果文件被更改了,状态会被标记为dirty,但是并没有马上写入到磁盘中,而是由系统不定时的将内存中的dirty数据写回磁盘,可以用sync命令手动要求写入磁盘。所以linux的内存一般越用越少,但是其实很大的一部分都是用来缓存文件,并不代表内存不够用。

除了ext,linux还能支持很多其他的文件系统,如fat,xfs,zfs,nfs等,内核通过VFS来管理不同的文件系统,使用者并不需要知道实际操作的文件系统是什么,操作系统会帮助我们管理。

针对ext文件系统对于大磁盘格式化缓慢(预先分配inode与block)的问题,我们可以改用xfs,inode和block是动态配置产生的。

文件系统的指令操作

df指令

指令 df 查看文件系统的整体使用量,df主要读取超级区块中的内容,所以还是比较快的。

df -hmT

du指令

指令 du 文件/目录名称 查看一个文件系统内的磁盘使用量(可以用来查看目录容量)常用参数

  • -a 列出所有文件与目录容量
  • -h 易读的容量格式
  • -s 列出总量 不列出各个目录的容量
  • -S 会列出子目录的容量(默认情况下,一个目录显示的大小会和子目录的大小相加,加上S后,就不会再加了,显示的就是各个目录的容量 不包含子目录的容量

相对于df,du指令会实际去查询文件系统中的文件数据,所以会稍微慢一些。

ln命令

ln可以用来创建实体链接和符号链接。

  1. 实体链接

    ln 链接到的文件 ./

    实体链接只是在当前目录下新增了一个名字——inode对应记录,指向同一个inode,link计数会加一,并不会创建新的文件或占用空间(除非正好用完目录的一个block),当然也没办法跨文件系统,也无法建立到目录的实体链接(因为复杂度较高,需要为每个文件建立实体链接,并且在新建文件的时候还需要在对应的另外一边再次创建链接),实体链接只要不是全部都被删除掉,文件总能访问,而符号链接一旦被链接的文件被删除,符号链接也就失效了。

  2. 符号链接 ln -s 链接到的文件 ./

    类似于快捷方式,它记录的就是一个“符号”,即指向的文件的路径,符号链接是作为文件存在的(会使用inode和block),文件的大小就是路径的字节数(/etc/crontab 十二个字母即十二个字节)

关于ls中显示的链接计数,当我们创建一个空目录的时候,可以发现链接计数已经是2了,

假设创建一个/tmp/empty目录时,会有三个东西

/tmp/empty

/tmp/empty/.

/tmp/empty/..

前两者都是指向empty目录的,而第三个链接则会指向/tmp,所以新目录link数为2,上层目录link也会加1.

分区与文件系统格式化

fdisk和gdisk分别为mbr与gpt的分区工具,parted则是通用的,要查看分区我们可以先试用lsblk查看当前的所有磁盘,然后使用parted device_name print来查看当前磁盘使用的分区类型。

parted也可以用来创建分区,并且同时支持mbr与gpt,可以一条指令创建,不需要像fdisk那样交互式的创建,不过要更为复杂一些就是了。

fdisk和gdisk 要对整块磁盘(sda)使用,而不是一个分区(sda1),修改了分区表之后不会马上生效,需要重启或者使用partprobe使之生效。不要删除或者编辑使用中的分区。

分区完毕之后还需要进行格式化来创建文件系统,使用mkfs。

文件系统检验

系统运行中由于异常死机时,由于数据的异步处理,所以可能会出现文件系统混乱,而我们也有办法进行文件系统检验纠正错误,主要针对xfs和ext4来说。 检验文件系统时,被检验的文件系统不能处于挂载状态,根目录无法卸载,这就需要我们进入单人维护模式/救援模式并使用参数强制检验(或者把硬盘插到另外一台linux主机上吧,我一直都是这样修复树莓派sd卡中错乱的文件系统的。

xfs_repair可以用来处理xfs文件系统,fsck.ext4可以用来处理ext4文件系统。

文件系统的挂载与卸载

有几点要注意的:

  • 单一文件系统不应该挂载到多个挂载点(目录)中
  • 单一目录不应该挂载多个文件系统
  • 作为挂载点的目录应该为空目录

如果用来挂载的目录不是空的,挂载文件系统后,原目录下的内容会暂时消失,卸载掉挂载的文件系统后,才看得到原来的内容

挂载与卸载的命令

mount命令可以使用 LABEL / UUID / 设备文件名 来挂载,还可以设置一些挂载时的额外参数,如是否使用同步写入/异步写入,只读或者可读写等等。

根目录不可被卸载,但是如果我们想要修改挂载参数时,要么重新开机,或者使用 -o remount参数

mount命令还可以将一个目录挂载到另外一个目录,类似于符号链接(某些程序可能不支持符号链接就要用这种方式了)

umount命令用来卸载设备文件。使用设备文件名或者挂载点都可以用来卸载。

xfs_admin和tune2fs分别可以用来修改xfs和ext4的label name和uuid。

开机挂载

通过修改/etc/fstab可以设置开机挂载,我们可以先查看一下文件内容

1
2
3
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# / was on /dev/nvme0n1p2 during installation
UUID=0c366147-d833-4555-b623-d56c96b55129 /               ext4    errors=remount-ro 0       1

可以看到,根目录时必须要挂载的,而且是最先被挂载的,如果出错的话会重新挂载为只读模式。

这里有六个字段:

  • 文件系统或者磁盘的设备文件名/文件系统的UUID/文件系统的LABEL名(卷标)
  • 挂载点
  • 磁盘分区的文件系统,fstab中必须手动指明文件系统是什么
  • 文件系统的参数 设置挂载参数
  • 是否被dump备份指令作用
  • 是否以fsck检验扇区(ext文件系统开机时会花费一些时间去检验文件系统,如果需要检验该分区,设置为1 )

编辑了fstab之后请先进行测试,不然一不小心就开不了机了!! 使用mount -a进行测试,如果真的不幸挂在失败进入单人维护模式,可以尝试重新挂载 mount -n -o remount,rw /

特殊文件挂载

mount除了能挂载一般的硬盘之外还可以用来挂载光盘或者镜像文件,设备类型需要设置成loop。 mount -o loop,挂载之后还可以编辑iso文件的内容。 关于linux下的loop设备文件

loop 设备是一种伪设备(pseudo-device),或者也可以说是仿真设备。它能使我们像块设备一样访问一个文件。

我们还可以创建出一个大文件并挂载到其他目录上(如果分区的时候容量设置不恰当,可以在容量较大的分区创建一个大文件并挂载到空间不足的目录处)。

1
2
3
dd if=/dev/zero of=/src/loopdev bs-1N count=512
mkfs.xfs -f /srv/loopdev
mount -o loop /srv/loopdev /mnt

这样即可在不变动分区的情况下创造出分区。

swap交换分区的创建

如果实体内存不足,我们内存中的程序可能就需要放到交换空间中暂存。当我们想要创建一个swap内存分区时可以使用下面的步骤:

  1. 创建一个交换分区 fdisk/gdisk从磁盘中分一个分区出来作为swap (注意设置分区类型id
  2. 格式化 mkswap 将分区格式化为swap格式
  3. 启用交换分区 swapon 设备文件名
  4. 之后使用free应该就能看到交换分区了

如果我们已经没办法再新增分区了,也可以使用文件来创建swap,使用上面提到的创建loop设备的方式。 mkswap /dec/loopdev即可。

swap的挂载也可以写到fstab中,但是如果是使用loop文件作为交换分区的话不要使用UUID,系统不会查询文件的uuid!

comments powered by Disqus
本站访客数:
使用 Hugo 构建
主题 StackJimmy 设计