第 5 章 Linux 磁盘管理

作者: Brinnatt 分类: ARM64 Linux 基础精修 发布时间: 2022-01-20 15:43

第 5 章 Linux 磁盘管理

一般情况下,采购回来的磁盘都是裸磁盘,需要格式化成文件系统后才能存储数据,所以磁盘管理和文件系统管理是密不可分的。当今主流的硬盘有机械硬盘和固态硬盘两种形态。下面分别介绍。

5.1、机械硬盘

real physical disk

机械硬盘由多块盘片组成,它们都绕着主轴旋转。

每块盘片上下方都有读写磁头悬浮在盘片上下方,它们与盘片的距离极小。

每次读写数据时盘片旋转,读写磁头被磁臂控制着不断的移动来读取其中的数据。

所有的盘片都是同时同步转动,所有的磁头也是同步移动。

disk track

磁盘在物理上划分了扇区、磁道和柱面。如果划分了分区,则分区是逻辑上柱面的分隔边界。

读写磁头在停止状态下,在盘片旋转时磁头扫过的一圈轨迹称为磁道,所有的磁道都是同心圆。从盘片外圈开始向内数,磁道号从 0 开始逐数增加。

每个磁道以 512 字节等分为多个弧段,每个弧段就是一个扇区。但是需要说明的是,扇区的大小并非一定是 512 字节。

所以外圈磁道的扇区数较多,内圈磁道的扇区数较少,有些硬盘参数上写的磁道扇区数通常用一个范围来标识,如 373-768 表示最外圈磁道有 768 个扇区,最内圈有 373 个扇区,这就可以计算出每个磁道的字节数。

扇区上记录了物理数据、扇区号、磁头号(或者盘片号)及磁道号。

disk zone track

旧式磁盘的结构不分区(without zones),每个磁道扇区数相同,但是每个扇区仍然是 512 字节,也就是说磁性材料记录的 0 和 1 的数量是相同的。这种结构的缺点是外圈磁道的面积大,存储的数据分布宽松,内圈磁道面积小,存储的数据分布密集,这样就导致盘片外圈面积浪费。

新式磁盘结构进行了分区,将每个磁道等面积划分 512 字节的空间作为一个扇区,所以不同磁道扇区数不同。

现在的磁盘都是新式扇区划分结构。

disk cylinder

将所有盘片相同磁道数的磁道划分为柱面。和磁道号的标记方式一样,从外向内从 0 开始逐数增加。

之所以划分柱面,是因为所有磁盘同步旋转,所有磁头同步移动,所有的磁头在任意一个时刻总是会出在同一个磁道同一个扇区上。读写数据时,任意一段数据总是按柱面来读写的。所以盘片数越多,读写所扫的扇区数就越少,所需的时间相对就越少,性能就越好。

向磁盘写数据是从外圈柱面向内圈柱面写的,只有写完一个柱面才写下一个柱面。

5.2、固态硬盘

ssd

不像机械硬盘里的一摞子圆形碟片,SSD 是由一些电路和黑色的存储颗粒构成。

SSD 硬盘是基于 NAND Flash 存储技术的,属于非易失性存储设备,换成人话说,就是掉电了数据不会丢。

其中每一个黑色的存储颗粒也叫做一个 Die。 我们 "拆开" 一个 Die 来看一下。

SSD die

每个 Die 有若干个 Plane,每个 Plane 有若干个 Block,每个 Block 有若干个 Page。Page 是磁盘进行读写的最小单位,一般为 2KB/4KB/8KB/16KB 等。

5.2.1、SSD 扇区

由于历史原因,操作系统等软件里,512KB 扇区的概念是“根深蒂固”。新的机械硬盘虽然把物理扇区已经做到 4KB 的了,但为了兼容老系统还得整出个逻辑扇区的概念来适配。

到了 SSD 里也一样,虽然每一个物理 Page 的大小为 2K 到 16K 不等,但是为了兼容性,也必须得整出个逻辑扇区才行。

SSD 控制器在逻辑上会把整个磁盘再重新划分成一个个的“扇区”,采用和新机械硬盘一样的 LBA 方式来进行编址(整个磁盘的扇区从 0 到某个最大值方式排列,并连成一条线)。

当需要读取某几个 "扇区" 上数据的时候,SSD 控制器通过访问这个 LBA MapTable, 再来找到要实际访问的物理 Page,如下图:

SSD addressing

  • 假设某 SSD 的 Page 大小是 4KB,一个文件是 16KB。那么该文件是存在一个黑色的存储颗粒里,还是多个?
    • 假设只写在一个颗粒里,那么对该文件进行读取的时候,就只能用到一条 Flash 通道,这样速度就会比较慢。
    • 如果存在相邻的 4 个颗粒里,每个写入 4KB。这样多个 Flash 通道的带宽会充分发挥出来,传输速度也更快。所以,实际中是分散在多个。

5.2.2、闪存单元

SSD 是由一个个的 Page 组成。而在每一个 Page 里,又包含了许许多多的闪存单元。。现代的闪存单元有多种类型,目前主流的主要分为 SLC、MLC 和 TLC。

SSD SLC MLC TLC

在 SLC 里,一个单元的电压只分成高低两种状态,所以只能表示 1bit 数据。

到了 MLC,硬是把一个单元里的电压按照高低分成了四种状态,所以可以表示 2bit。

到了TLC,直接一个单元应拆分成8个电压高低不同的状态,为了表示3bit。

  • 由于TLC在数据读写需要八种不同电压状态,而施加不同的电压状态、 就需要更精确,也就需要更长的时间才能得以实现。另外由于电压状态多,出错的可能性也会更大。

以上三种闪存单元对比:从性能和稳定性角度来看,SLC 最好。从容量角度看,TLC 最大。这就是为什么日常我们看到的工业级的 SSD 要比笔记本 SSD 要贵很多,其中一个很重要的原因就是工业级的盘往往采用的闪存单元是 SLC 或 MLC,而我们家用的笔记本一般都是 TCL,因为便宜嘛。目前主流闪存类型 TLC 居多,因为价格便宜,容量大。

闪存类型 单 cell 电压变化 单 cell 表示 bit 数 速度 擦写次数 价格
SLC(Single-Level Cell) 两种 1 bit 约 10W 次
MLC(Multi-Level Cell) 四种 2 bit 一般 约 3K 次 一般
TLC(Trinary-Level Cell) 八种 3 bit 约 1K 次 便宜

5.3、分区

分区是为了在逻辑上将某些柱面隔开形成边界。它是以柱面为单位来划分的,但是从 CentOS 7 开始,是按照扇区进行划分的。

在磁盘数据量非常大的情况下,划分分区的好处是扫描块位图等更快速:不用再扫描整块磁盘的块位图,只需扫描对应分区的块位图。

5.3.1、分区方法

MBR 格式的磁盘中,会维护磁盘第一个扇区——MBR 扇区,在该扇区中第 446 字节之后的 64 字节是分区表,每个分区占用 16 字节,所以限制了一块磁盘最多只能有 4 个主分区(Primary, P),如果多于 4 个区,只能创建主分区少于 4 个,通过建立扩展分区(Extend, E),然后在扩展分区建立逻辑分区(Logical, L)的方式来突破 4 个分区的限制,逻辑分区的数量不限制。

在 Linux 中,MBR 格式的磁盘主分区号从 1 - 4,扩展分区号从 2 - 4,逻辑分区号从 5 开始。

例如,一块盘想分成6个分区,方式如下

  • 1P+5L:sda1 + sda5 + sda6 + sda7 + sda8 + sda9
  • 2P+4L:sda1 + sda2 + sda5 + sda6 + sda7 + sda8
  • 3P+3L:sda1 + sda2 + sda3 + sda5 + sda6 + sda7

而 GPT 格式突破了 MBR 的限制,它不再限制只能存储 4 个分区表条目,而是使用了类似 MBR 扩展分区表条目的格式,它允许有 128 个主分区,这也使得它可以对超过 2TB 的磁盘进行分区。

5.3.2、MBR 和 GPT 分区表

在 MBR 格式分区表中,MBR 扇区占用 512 个字节,前 446 个字节是主引导记录,即 boot loader。

中间 64 字节记录着分区表信息,每个主分区信息占用 16 字节,因此最多只能有 4 个主分区,最后 2 个字节是有效标识位。

如果使用扩展分区,则扩展分区对应的 16 字节记录的是指向扩展分区中扩展分区表的指针。

MBR disk

在 MBR 磁盘上,分区和启动信息是保存在一起的,如果这部分数据被覆盖或破坏,只能重建 MBR。

而 GPT 在整个磁盘上保存多个这部分信息的副本,因此它更为健壮,并可以恢复被破坏的这部分信息。

GPT 还为这些信息保存了循环冗余校验码(CRC)以保证其完整和正确,如果数据被破坏,GPT 会发现这些破坏,并从磁盘上的其他地方进行恢复。

下面是 GPT 格式的分区表信息,大致约占 17 个字节。

GPT disk

EFI 部分可以分为 4 个区域:EFI 信息区(GPT头)、分区表、GPT 分区区域和备份区域。

  1. EFI 信息区(GPT头):起始于磁盘的 LBA1,通常也只占用这个单一扇区。其作用是定义分区表的位置和大小。GPT 头还包含头和分区表的校验和,这样就可以及时发现错误。
  2. 分区表:分区表区域包含分区表项。这个区域由 GPT 头定义,一般占用磁盘 LBA2~LBA33 扇区,每扇区可存储 4 个主分区的分区信息,所以共能分 128 个主分区。分区表中的每个分区项由起始地址、结束地址、类型值、名字、属性标志、GUID 值组成。分区表建立后,128 位的 GUID 对系统来说是唯一的。
  3. GPT 分区:最大的区域,由分配给分区的扇区组成。这个区域的起始和结束地址由 GPT 头定义。
  4. 备份区:备份区域位于磁盘的尾部,包含 GPT 头和分区表的备份。它占用 GPT 结束扇区和 EFI 结束扇区之间的 33 个扇区。其中最后一个扇区用来备份 1 号扇区的 EFI 信息,其余的 32 个扇区用来备份 LBA2~LBA33 扇区的分区表。

5.3.3、添加磁盘

正常情况下,添加磁盘后需要重启系统才能被内核识别,在 /dev/ 下才有对应的设备号,使用 fdisk -l 才会显示出来。但是有时候不方便重启,所以下面介绍一种磁盘热插拔方式。

# 查看主机scsi总线号
[root@compute1 ~]# ls /sys/class/scsi_host/ 
host0  host1  host2  host3  host4
[root@compute1 ~]#

重新扫描 scsi 总线以热插拔方式添加新设备。

[root@compute1 ~]# echo "- - -" > /sys/class/scsi_host/host0/scan
[root@compute1 ~]# echo "- - -" > /sys/class/scsi_host/host1/scan
[root@compute1 ~]# echo "- - -" > /sys/class/scsi_host/host3/scan
[root@compute1 ~]# echo "- - -" > /sys/class/scsi_host/host4/scan

# 再查看就有了
[root@compute1 ~]# fdisk -l

5.3.4、交互式命令

交互式命令的好处在于,可以每一步完成一个小目标,最后实现整体目标,思路更加清晰,排错更加容易等。

5.3.4.1、fdisk 命令

fdisk 工具用来分 MBR 磁盘上的区。要分 GPT 磁盘上的区,可以使用 gdisk。parted 工具对这两种格式的磁盘分区都支持。

如果一个存储设备已经分过区,那么它可能是 mbr 格式的,也可能是 gpt 格式的,如果已经是 mbr 格式的,则只能继续使用 fdisk 进行分区,如果已经是 gpt 格式的,则只能使用 gdisk 进行分区。

当然,无论什么格式的都可以使用 parted 进行分区,只不过也只能划分和已存在分区格式一样的分区,因为无论何种格式的分区,它的分区表和分区标识是已经固定的。

使用 fdisk 分区,它只能实现 MBR 格式的分区。

root@arm64v8:~# fdisk /dev/vdb

Welcome to fdisk (util-linux 2.27.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

命令(输入 m 获取帮助): m

Help:

  DOS (MBR)
   a   toggle a bootable flag
   b   edit nested BSD disklabel
   c   toggle the dos compatibility flag

  Generic
   d   delete a partition                   # 删除分区,如果删除扩展分区同时会删除里面的逻辑分区
   F   list free unpartitioned space        # 列出空闲未分区的空间
   l   list known partition types           # 列出分区类型
   n   add a new partition                  # 创建新的分区
   p   print the partition table            # 查看分区表
   t   change a partition type              # 修改分区类型
   v   verify the partition table           # 查看剩下多少未分配的扇区
   i   print information about a partition  # 查看分区详情

  Misc
   m   print this menu
   u   change display/entry units
   x   extra functionality (experts only)

  Script
   I   load disk layout from sfdisk script file
   O   dump disk layout to sfdisk script file

  Save & Exit
   w   write table to disk and exit
   q   quit without saving changes

  Create a new label
   g   create a new empty GPT partition table
   G   create a new empty SGI (IRIX) partition table
   o   create a new empty DOS partition table
   s   create a new empty Sun partition table

命令(输入 m 获取帮助):

新建第一个主分区

root@arm64v8:~# fdisk /dev/vdb

Welcome to fdisk (util-linux 2.27.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

命令(输入 m 获取帮助): n                                # 新建分区
Partition type
   p   primary (0 primary, 0 extended, 4 free)       # 添加主分区
   e   extended (container for logical partitions)   # 添加扩展分区
Select (default p): p                                # 选择建立主分区
分区号 (1-4, default 1): 1                            # 输入分区号,从1开始
First sector (2048-209715199, default 2048): 2048    # 输入起始扇区
Last sector, +sectors or +size{K,M,G,T,P} (2048-209715199, default 209715199): +10G # 分区给10G大小

Created a new partition 1 of type 'Linux' and of size 10 GiB.

命令(输入 m 获取帮助): p    # 查看分区建立的情况
Disk /dev/vdb: 100 GiB, 107374182400 bytes, 209715200 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x2528187f

设备       启动 Start   末尾   扇区 Size Id 类型
/dev/vdb1        2048 20973567 20971520  10G 83 Linux

命令(输入 m 获取帮助):

新建扩展分区

命令(输入 m 获取帮助): n    # 新建分区
Partition type
   p   primary (1 primary, 0 extended, 3 free)
   e   extended (container for logical partitions)
Select (default p): e   # 建立扩展分区
分区号 (2-4, default 2):   # 选择分区号,默认就可以
First sector (20973568-209715199, default 20973568):    # 起始扇区
Last sector, +sectors or +size{K,M,G,T,P} (20973568-209715199, default 209715199):  # 结束扇区,这里默认把剩下的所有空间都用上

Created a new partition 2 of type 'Extended' and of size 90 GiB.

命令(输入 m 获取帮助): p    # 查看扩展分区有没有成功
Disk /dev/vdb: 100 GiB, 107374182400 bytes, 209715200 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x2528187f

设备       启动    Start    末尾    扇区 Size Id 类型
/dev/vdb1           2048  20973567  20971520  10G 83 Linux
/dev/vdb2       20973568 209715199 188741632  90G  5 扩展     # 显示出来了,成功

命令(输入 m 获取帮助): n    # 在扩展分区上建立逻辑分区
All space for primary partitions is in use. # 扩展分区把剩余空间用完了,即使4个主分区没用完,也没得选
Adding logical partition 5
First sector (20975616-209715199, default 20975616):    # 逻辑分区起始扇区
Last sector, +sectors or +size{K,M,G,T,P} (20975616-209715199, default 209715199):  # 逻辑分区结束扇区,这里默认选择最后一个扇区用完空间

Created a new partition 5 of type 'Linux' and of size 90 GiB.

命令(输入 m 获取帮助): p    # 查看逻辑分区创建成功没有
Disk /dev/vdb: 100 GiB, 107374182400 bytes, 209715200 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x2528187f

设备       启动    Start    末尾    扇区 Size Id 类型
/dev/vdb1           2048  20973567  20971520  10G 83 Linux
/dev/vdb2       20973568 209715199 188741632  90G  5 扩展
/dev/vdb5       20975616 209715199 188739584  90G 83 Linux  # 逻辑分区创建成功,所有的扩展空间用完

命令(输入 m 获取帮助): w    # 分区结束,保存。如果不保存,则按q,如果没保存,所有分区都白做了
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

root@arm64v8:~#

分区的过程,实质上是划分扇区以及修改分区表。

上面的 fdisk 操作全部是在内存中执行的,必须保存生效。保存后,内核还未识别该分区,可以查看 /proc/partition 目录下存在的文件,这些文件是能被内核识别的分区。

运行 partprobe 或 partx 命令重新读取分区表让内核识别新的分区,内核识别后才可以格式化。而且分区结束时按 w 保存分区表有时候会失败,提示重启,这时候运行 partprobe 命令可以代替重启就生效。

# 这个命令可以读取所有的磁盘分区,也可以用 partprobe /dev/vdb 只读一个磁盘
root@arm64v8:~# partprobe

5.3.4.2、gdisk 命令

gdisk 用来划分 gpt 分区,需要单独安装这个工具包。

root@arm64v8:~# aptitude install gdisk
下列“新”软件包将被安装。         
  gdisk 
0 个软件包被升级,新安装 1 个, 0 个将被删除, 同时 486 个将不升级。
需要获取 189 kB 的存档。 解包后将要使用 772 kB。
读取: 1 http://archive.kylinos.cn/kylin/KYLIN-ALL 10.0/main arm64 gdisk arm64 1.0.1-1kord1 [189 kB]
已下载 189 kB,耗时 0秒 (530 kB/s)
正在选中未选择的软件包 gdisk。
(正在读取数据库 ... 系统当前共安装有 230153 个文件和目录。)
正准备解包 .../gdisk_1.0.1-1kord1_arm64.deb  ...
正在解包 gdisk (1.0.1-1kord1) ...
正在处理用于 man-db (2.7.5-1kord) 的触发器 ...
正在设置 gdisk (1.0.1-1kord1) ...

root@arm64v8:~#

分区的时候直接带上设备即可。以下是对新硬盘划分 gpt 分区的过程。

root@arm64v8:~# gdisk /dev/vdb
GPT fdisk (gdisk) version 1.0.1

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.

Command (? for help): ?
b   back up GPT data to a file
c   change a partition's name
d   delete a partition                                  # 删除分区
i   show detailed information on a partition            # 列出分区详细信息
l   list known partition types                          # 列出通用的分区类型
n   add a new partition                                 # 创建新分区
o   create a new empty GUID partition table (GPT)       # 创建一个新的空的guid分区表
p   print the partition table                           # 输出分区表信息
q   quit without saving changes                         # 退出 gdisk 工具
r   recovery and transformation options (experts only)
s   sort partitions
t   change a partition's type code                     # 修改分区类型
v   verify disk
w   write table to disk and exit                        # 将分区信息写入到磁盘
x   extra functionality (experts only)
?   print this menu

Command (? for help):

添加一个新分区

root@arm64v8:~# gdisk /dev/vdb
GPT fdisk (gdisk) version 1.0.1

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.

Command (? for help): n     # 新建一个分区
Partition number (1-128, default 1):    # 第一个分区
First sector (34-209715166, default = 2048) or {+-}size{KMGTP}:     # 起始扇区选择,默认即可
Last sector (2048-209715166, default = 209715166) or {+-}size{KMGTP}: +10G  # 结束扇区选择,使用+10G这种格式,它自己会计算需要多少个扇区
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300):   # 选择分区类型,默认即可
Changed type of partition to 'Linux filesystem'

Command (? for help): p     # 查看创建分区的情况
Disk /dev/vdb: 209715200 sectors, 100.0 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): 76D04934-547A-4030-93CE-AC4F71B6713A
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 209715166
Partitions will be aligned on 2048-sector boundaries
Total free space is 188743613 sectors (90.0 GiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048        20973567   10.0 GiB    8300  Linux filesystem

Command (? for help): w     # 保存分区表到磁盘

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): Y
OK; writing new GUID partition table (GPT) to /dev/vdb.
The operation has completed successfully.
root@arm64v8:~#

执行 partprobe 重新读取分区表信息。

root@arm64v8:~# partprobe /dev/vdb

5.3.4.3、parted 命令

parted 支持 mbr 格式和 gpt 格式的磁盘分区。它的强大在于可以一步到位而不需要不断的交互式输入(也可以交互式)。

parted 分区工具是实时的,所以每一步操作都是直接写入磁盘而不是写进内存,它不像 fdisk/gdisk 还需要 w 命令将内存中的结果保存到磁盘中。

root@arm64v8:~# parted /dev/vdb
GNU Parted 3.2
使用 /dev/vdb
欢迎使用 GNU Parted! 输入 'help'可获得命令列表.
(parted) help                                                             
  align-check TYPE N                       check partition N for TYPE(min|opt) alignment
  help [COMMAND]                           print general help, or help on COMMAND
  mklabel,mktable LABEL-TYPE               create a new disklabel (partition table)
  mkpart 分区类型 [文件系统类型] 起始点 终止点   创建一个分区
  name NUMBER NAME                         将编号为NUMBER 的分区命名为“NAME”
  print [devices|free|list,all|NUMBER]     display the partition table, available devices, free space, all found partitions, or a particular partition
  quit                                     退出程序
  rescue START END                         挽救临近“起始点”、“终止点”的遗失的分区
  resizepart NUMBER END                    resize partition NUMBER
  rm NUMBER                                删除编号为 NUMBER 的分区
  select DEVICE                            choose the device to edit
  disk_set FLAG STATE                      change the FLAG on selected device # 设置 flag
  disk_toggle [FLAG]                       toggle the state of FLAG on selected device # 设置 flag on 或者 off
  set NUMBER FLAG STATE                    change the FLAG on partition NUMBER
  toggle [NUMBER [FLAG]]                   toggle the state of FLAG on partition NUMBER
  unit UNIT                                set the default unit to UNIT
  version                                  display the version number and copyright information of GNU Parted
(parted)

常用的命令是 mklabel/rm/print/mkpart/help/quit

parted 分区的前提是磁盘已经有分区表(partition table)或磁盘标签(disk label),否则将显示 "unrecognised disk label",这是和 fdisk/gdisk 不同的地方,所以需要先使用 mklabel 创建标签或分区表。

最常见的标签(分区表)为 "msdos" 和 "gpt",其中 msdos 分区就是 MBR 格式的分区表,也就是会有主分区、扩展分区和逻辑分区的概念和限制。

使用 parted 对/dev/sda 创建 msdos 的新分区。

[root@arm64v8 ~]# parted /dev/sda
GNU Parted 3.1
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) mkpart     # 创建分区
Partition type?  primary/extended? primary  # 选择主分区或是扩展分区
File system type?  [ext2]? xfs  # 这里有一定误导,这个文件系统选择是给GUID表做参考,并不会把分区格式化成 xfs
Start? 1    # 起始位置选择,注意这个 1 表示的是 1MB,默认单位就是 MB;默认单位可以用 unit <UNIT> 指定,强调 MB 和 MiB 是有区别的,1KB=10^3=1000B,1KiB=2^10=1024B,1MiB=2^20=1048576=1024KiB
End? 1024   # 结束位置,不包括 1024MB,实际上是 1MB 到 1023MB
(parted) p  # 查看分区创建成功
Model: QEMU QEMU HARDDISK (scsi)
Disk /dev/sda: 1100GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 

Number  Start   End     Size    Type     File system  Flags
 1      1049kB  1024MB  1023MB  primary

(parted) mkpart primary ext4 1024 2048  # 上面的创建方式是交互式创建,可以用一行命令完成
(parted) p  # 查看第二个分区创建完成
Model: QEMU QEMU HARDDISK (scsi)
Disk /dev/sda: 1100GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 

Number  Start   End     Size    Type     File system  Flags
 1      1049kB  1024MB  1023MB  primary
 2      1024MB  2048MB  1023MB  primary

(parted) rm 2   # 删除分区的语法,这里删除第 2 个分区
(parted) p  # 查看第 2 个分区删除完成
Model: QEMU QEMU HARDDISK (scsi)
Disk /dev/sda: 1100GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 

Number  Start   End     Size    Type     File system  Flags
 1      1049kB  1024MB  1023MB  primary

(parted) mkpart extended xfs 1030 -1    # 创建扩展分区是不用指定文件系统的,会报错
Error: Invalid number.
(parted) mkpart extended 1030 -1    # 创建扩展分区的正确方式,-1 表示用完所有的剩余空间
(parted) p  # 查看扩展分区创建成功
Model: QEMU QEMU HARDDISK (scsi)
Disk /dev/sda: 1100GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 

Number  Start   End     Size    Type      File system  Flags
 1      1049kB  1024MB  1023MB  primary
 2      1030MB  1100GB  1098GB  extended               lba

(parted) mkpart     # 在扩展分区上创建逻辑分区
Partition type?  primary/logical? l # 可以选择主分区或者逻辑分区
File system type?  [ext2]? xfs  # 这里有一定误导,这个文件系统选择是给GUID表做参考,并不会把分区格式化成 xfs
Start? 1    # 起始位置选择,随意写个 1,结合下面的警告(你已经分过1MB-1024MB的分区,扩展分区的起始是1030MB,建议从这里开始),往下看
End? 1024   # 结束位置选择,随意写个 1024,结合下面的警告(你已经分过1MB-1024MB的分区,扩展分区的起始是1030MB,建议从这里开始),往下看
Warning: You requested a partition from 1000kB to 1024MB (sectors 1953..2000000).
The closest location we can manage is 1030MB to 1030MB (sectors 2011137..2011137).
Is this still acceptable to you?
Yes/No? yes # 接受建议
Warning: The resulting partition is not properly aligned for best performance.  # 警告:扇区没有对齐,看上面警告括号中的sector,这是我故意没有对齐的,1024MB 和 1030MB 中间明显有一点空间,这些扇区浪费了,所以警告,最好的方式是连续划分。
Ignore/Cancel? Ignore   # 选择忽略扇区没有对齐问题
(parted) p  # 查看创建了一个 1030MB 到 1030MB 的分区,也就是 1 个扇区,512 Bytes。
Model: QEMU QEMU HARDDISK (scsi)
Disk /dev/sda: 1100GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 

Number  Start   End     Size    Type      File system  Flags
 1      1049kB  1024MB  1023MB  primary
 2      1030MB  1100GB  1098GB  extended               lba
 5      1030MB  1030MB  512B    logical

(parted) mkpart l xfs 1030 -1   # 重新创建逻辑分区,从 1030MB 开始到 -1 结束表示用完所有的剩余空间
Warning: The resulting partition is not properly aligned for best performance.
Ignore/Cancel? Ignore   # 忽略扇区没有对齐问题
(parted) p  # 查看逻辑分区成功
Model: QEMU QEMU HARDDISK (scsi)
Disk /dev/sda: 1100GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 

Number  Start   End     Size    Type      File system  Flags
 1      1049kB  1024MB  1023MB  primary
 2      1030MB  1100GB  1098GB  extended               lba
 5      1030MB  1030MB  512B    logical
 6      1030MB  1100GB  1098GB  logical

(parted) quit   # 退出 parted 工具
  • 掌握好 parted 分区工具,Linux 下的分区基本上没有什么障碍,所以上面的实验每一步我都做了详细的说明。
  • parted 最难理解的就是扇区对齐问题,所以磁盘基础知识要扎实,开篇也做了详细的陈述,可以前后对照学习。
  • 上面的实验是 msdos 格式的分区,gpt 格式的分区步骤更简单,只要准确地理解了上述实验中的每一步骤,gpt 格式分区也就不在话下。

5.3.5、非交互式命令

使用非交互分区时,最重要的是待分的区的起始点不能是已使用的。

可以使用 lsblk 或 fdisk -l 或 parted DEV print 来判断将要从哪个地方开始分区。

其实 parted 在非交互分区时是最佳的工具,不仅是因为其书写方式简洁,而且待分区的起点如不合理它会自动提示是否要自动调整。

5.3.5.1、fdisk 命令

fdisk 实现非交互的原理是从标准输入中读取,每读取一行传递一次操作。

所以可以有两种方式:

使用 echo 和管道传递

# 下面的命令创建了两个分区,使用默认值时传递空行即可
[root@arm64v8 ~]# echo -e "n\np\n1\n\n+5G\nn\np\n2\n\n+1G\nw\n"  | fdisk /dev/sda

将操作写入到文件中,从文件中读取

# 如果要传递的操作很多,则可以将它们写入到一个文件中,从文件中读取
[root@arm64v8 ~]# echo -e "n\np\n1\n\n+5G\nn\np\n2\n\n+1G\nw\n" >/tmp/a.txt
[root@arm64v8 ~]# fdisk /dev/sda </tmp/a.txt

5.3.5.2、gdisk 命令

同理 fdisk 命令

5.3.5.3、parted 命令

parted 命令只能一次非交互一个命令中的所有动作

parted /dev/sdb mklabel msdos                 # 设置硬盘flag
parted /dev/sdb mkpart primary ext4 1 1000    # Mbr格式分区,分别是partition type/fstype/start/end
parted /dev/sdb mkpart 1 ext4 1M 10240M       # gpt格式分区,分别是name/fstype/start/end
parted /dev/sdb mkpart 1 10G 15G              # 省略fstype的交互式分区
parted /dev/sdb rm 1                          # 删除分区
parted /dev/sdb p                             # 输出信息

如果不确定分区的起点大小,可以加上 -s 选项使用 script 模式,该模式下 parted 将回答一切默认值,如 yes、no。

[root@arm64v8 ~]# parted -s /dev/sda mkpart 3 14G 16G
Warning: You requested a partition from 14.0GB to 16.0GB.                
The closest location we can manage is 15.0GB to 16.0GB.
Is this still acceptable to you?
Information: You may need to update /etc/fstab.

5.4、格式化分区

分区结束后就需要格式化创建文件系统了,格式化分区的过程就是创建文件系统的过程。

可以使用 mkfs(make filesystem) 工具进行格式化,也可以使用该工具家族的其他工具如 mkfs.ext4/mkfs.xfs 等专门针对文件系统的工具。

要查看支持的文件系统类型,只需简单的输入 mkfs 然后按两下 tab 键,就可以列出各文件系统对应的格式化命令,这些就是支持的文件系统类型。

[root@arm64v8 ~]# mkfs
mkfs         mkfs.cramfs  mkfs.ext3    mkfs.fat     mkfs.msdos   mkfs.xfs     
mkfs.btrfs   mkfs.ext2    mkfs.ext4    mkfs.minix   mkfs.vfat    
[root@arm64v8 ~]# mkfs

5.4.1、mkfs 命令

该工具非常简单,它只需指定一个可选的 "-t" 选项指定要创建的文件系统类型,如果省略则默认创建 ext2 文件系统。

该工具指定的 "-t" 选项其实是在调用对应文件系统专属的格式化工具。

mkfs [-t fstype] 分区
mkfs.<fstype> 分区

[root@arm64v8 ~]# mkfs.ext4 /dev/sda1 
mke2fs 1.42.9 (28-Dec-2013)
Discarding device blocks: done                            
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
61056 inodes, 243968 blocks
12198 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=251658240
8 block groups
32768 blocks per group, 32768 fragments per group
7632 inodes per group
Superblock backups stored on blocks: 
    32768, 98304, 163840, 229376

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

[root@arm64v8 ~]#

5.4.2、mke2fs 命令

mkfs.ext2/mkfs.ext3/mkfs.ext4 或 mkfs -t extX 其实都是在调用 mke2fs 命令

该工具创建文件系统时,会从 /etc/mke2fs.conf 配置中读取默认的配置项

mke2fs [ -c ] [ -b block-size ] [ -f fragment-size ] [ -g blocks-per-group ] [ -G number-of-groups ] 
       [ -i bytes-per-inode ] [ -I inode-size ] [ -j ] [ -N number-of-inodes ] [ -m reserved-blocks-percentage ] 
       [ -q ] [ -r fs-revision-level ] [ -v ] [ -L volume-label ] [ -S ] [ -t fs-type ] device [ blocks-count ]

选项说明:
-t fs-type          :指定要创建的文件系统类型(ext2,ext3 ext4),若不指定,则从/etc/mke2fs.conf中获取默认的文件系统类型。
-b block-size       :指定每个block的大小,有效值有1024、2048和4096,单位是字节。
-I inode-size       :指定inode大小,单位为字节。必须为2的幂次方,且大于等于128字节。值越大,说明inode的集合体inode table占用越多的空
                     间,这不仅会挤占文件系统中的可用空间,还会降低性能,因为要扫描inode table需要消耗更多时间,但是在linux kernel 2.6.10
                     之后,由于使用inode存储了很多扩展的额外属性,所以128字节已经不够用了,因此ext4默认的inode size已经变为256,尽管
                     inode大小增大了,但因为使用inode存储扩展属性带来的性能提升远高于inode size变大导致的负面影响,所以仍建议使用256字
                     节的inode。
-i bytes-per-inode  :指定每多少个字节就为其分配一个inode号。值越大,说明一个文件系统中分配的inode号越少,更适用于存储大量大文件,值越
                     小,inode号越多,更适用于存储大量小文件。该值不能小于一个block的大小,因为这样会造成inode多余。
                     注意,创建文件系统后该值就不能再改变了。
-c                  :创建文件系统前先检查设备是否有bad blocks。
-f fragment-size    :指定fragments的大小,单位字节。
-g blocks-per-group :指定每个块组中的block数量。不建议修改此项。
-G number-of-groups :该选项用于ext4文件系统(严格地说是启用了flex_bg特性),指定虚拟块组(即一个extent)中包含的块组个数,必须为2的幂次方。
                     对于ext4文件系统来说,使用extent的功能能极大提升其性能。
-j                  :创建带有日志功能的文件系统,即ext3。如果要指定关于日志方面的设置,在-j的基础上再使用-J指定,不过一般默认即可,具体可
                     指定的选项看man文档。 
-L new-volume-label :指定卷标名称,名称不得超出16字节。
-m reserved-blocks-percentage   :指定文件系统保留block数量的比例,保留一部分block,可以降低物理碎片。默认比例为5%。
-N number-of-inodes :强制指定该文件系统应该分配多少个inode号,它会覆盖通过计算得出inode数量的结果(根据block大小、数量和每多少字节分配
                     一个inode得出Inode数量),但是不建议这么做。
-q                  :安静模式,可用于脚本中
-S                  :重建superblock和group descriptions。在所有的superblock和备份的superblock都损坏时有用。它会重新初始化superblock和
                     group descriptions,但不会改变inode table、bmap和imap(若真的改变,该分区数据就全丢了,还不如重新格式化)。在重建
                     superblock后,应该执行e2fsck来保证文件系统的一致性。但要注意,应该完全正确地指定block的大小,其改选项并不能完全保
                     证数据不丢失。
-v                  :输出详细执行过程 

所以,有可能用到的选项也就 "-t" 指定文件系统类型,"-b" 指定 block 大小,"-I" 指定 inode 大小,"-i" 指定分配 inode 的比例。

[root@arm64v8 ~]# mke2fs -t ext4 -I 256 /dev/sda1 -b 4096
mke2fs 1.42.9 (28-Dec-2013)
Discarding device blocks: done                            
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
61056 inodes, 243968 blocks
12198 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=251658240
8 block groups
32768 blocks per group, 32768 fragments per group
7632 inodes per group
Superblock backups stored on blocks: 
    32768, 98304, 163840, 229376

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

[root@arm64v8 ~]#

5.4.3、tune2fs 命令

该工具其实没什么太大作用,文件系统创建好后很多属性是固定不能修改的,能修改的属性很有限,且都是无关紧要的。

但有些时候还是可以用到它做些事情,例如刚创建完ext文件系统后会提示修改自检时间。

tune2fs [  -c  max-mount-counts ] [ -i interval-between-checks ] [ -j ] device
-j:将ext2文件系统升级为ext3;
-c:修改文件系统最多挂载多少次后进行自检,设置为0或-1将永不自检;
-i:修改过了多少时间进行自检。时间单位可以指定为天(默认)/月/星期[d|m|w],设置为0将永不自检。

5.5、查看文件系统

5.5.1、lsblk 命令

lsblk(list block devices) 用于列出设备及其状态,主要列出非空的存储设备。其实它只会列出 /sys/dev/block 中的主次设备号文件,且默认只列出非空设备。

[root@arm64v8 ~]# lsblk 
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sr0     11:0    1 755.8M  0 rom  
sda      8:0    0     1T  0 disk 
└─sda1   8:1    0   953M  0 part 
vda    253:0    0   500G  0 disk 
├─vda4 253:4    0 482.9G  0 part /
├─vda2 253:2    0     1G  0 part /boot
├─vda3 253:3    0    16G  0 part [SWAP]
└─vda1 253:1    0   200M  0 part /boot/efi
[root@arm64v8 ~]#
  • NAME:设备名称;
  • MAJ:MIN:主设备号和此设备号;
  • RM:是否为可卸载设备,1 表示可卸载设备。可卸载设备如光盘、USB 等。并非能够 umount 的就是可卸载的;
  • SIZE:设备总空间大小;
  • RO:是否为只读;
  • TYPE:是磁盘 disk,还是分区 part,亦或是 rom,还有 loop 设备;
  • mountpoint:挂载点。
[root@arm64v8 ~]# lsblk /dev/sda
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda      8:0    0    1T  0 disk 
└─sda1   8:1    0  953M  0 part 
[root@arm64v8 ~]# lsblk /dev/sda1
NAME MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda1   8:1    0  953M  0 part 
[root@arm64v8 ~]#

另外常用的一个选项是 "-f",它可以查看到文件系统类型,和文件系统的 uuid 和挂载点。

[root@arm64v8 ~]# lsblk -f
NAME   FSTYPE  LABEL            UUID                                 MOUNTPOINT
sr0    iso9660 CentOS 7 aarch64 2018-05-08-14-09-45-00               
sda                                                                  
└─sda1 ext4                     f2151d94-6fb5-48af-af4f-b36c403d4247 
vda                                                                  
├─vda4 xfs                      c50aefdd-bc0f-4761-a47f-60deadbc0f30 /
├─vda2 xfs                      cfcb5471-b488-41ab-8622-35b57ebb0395 /boot
├─vda3 swap                     e0421809-f014-4ea5-8183-fd96c8423be3 [SWAP]
└─vda1 vfat                     AD9C-FE26                            /boot/efi
[root@arm64v8 ~]#

每个已经格式化的文件系统都有其类型和 uuid,而没有格式化的设备,将只显示一个Name结果,表示该设备还未进行格式化。

5.5.2、blkid 命令

虽然它有不少比较强大的功能,但一般只用它一个功能,就是查看器文件系统类型和 uuid。

[root@arm64v8 ~]# blkid 
/dev/vda1: SEC_TYPE="msdos" UUID="AD9C-FE26" TYPE="vfat" PARTLABEL="EFI System Partition" PARTUUID="6f5cb7a5-6d83-4f67-af13-1f01f31eb637" 
/dev/vda2: UUID="cfcb5471-b488-41ab-8622-35b57ebb0395" TYPE="xfs" PARTUUID="efc59722-5d36-4bcd-87a4-412df21e362d" 
/dev/vda3: UUID="e0421809-f014-4ea5-8183-fd96c8423be3" TYPE="swap" PARTUUID="a5d2758f-0a2c-4145-9c04-9b6ddce9b07c" 
/dev/vda4: UUID="c50aefdd-bc0f-4761-a47f-60deadbc0f30" TYPE="xfs" PARTUUID="6e441755-2842-4746-8f24-8c54019c72b6" 
/dev/sda1: UUID="f2151d94-6fb5-48af-af4f-b36c403d4247" TYPE="ext4" 
/dev/sr0: UUID="2018-05-08-14-09-45-00" LABEL="CentOS 7 aarch64" TYPE="iso9660" 
[root@arm64v8 ~]# 
[root@arm64v8 ~]# blkid /dev/sda1
/dev/sda1: UUID="f2151d94-6fb5-48af-af4f-b36c403d4247" TYPE="ext4" 
[root@arm64v8 ~]#

5.5.3、file 命令

[root@arm64v8 ~]# file -s /dev/sda1
/dev/sda1: Linux rev 1.0 ext4 filesystem data, UUID=f2151d94-6fb5-48af-af4f-b36c403d4247 (extents) (64bit) (large files) (huge files)
[root@arm64v8 ~]# 

5.5.4、du 命令

du 命令用于评估文件的空间占用情况,它会统计每个文件的大小,统计时会递归统计目录中的文件,也就是说,它会遍历整个待统计目录,所以统计速度上可能并不理想。

du [OPTION]... [FILE]...
选项说明:
-a, --all:列出目录中所有文件的统计信息,默认只会列出目录中子目录的统计信息,而不列出文件的统计信息
-h, --human-readable:人性化显示大小
-0, --null:以空字符结尾,即"\0"而非换行的"\n"
-S, --separate-dirs:不包含子目录的大小
-s, --summarize:对目录做总的统计,不列出目录内文件的大小信息
-c,--total:对给出的文件或目录做总计。在统计非同一个目录文件大小时非常有用。见下文例子。
-d,--max-depth:指定显示时的目录深度,默认会递归显示所有层次
--max-depth=N:只列出给定层次的目录统计,如果N=0,则等价于"-s"
-x, --one-file-system:忽略不同文件系统上的文件,不对它们进行统计
-X, --exclude-from=FILE:从文件中读取要排除的文件
--exclude=PATTERN:指定要忽略不统计的文件
  • 上面的选项中,有些是不列出某些项,有些是不统计某些项,它们是不一样的。
  • 如果要统计的目录下挂载了一个文件系统,那么这个文件系统的大小也会被计入该目录的大小中。
[root@arm64v8 ~]# du -sh /etc/
29M /etc/
[root@arm64v8 ~]# 
[root@arm64v8 ~]# du -ah /tmp/
0   /tmp/.XIM-unix
0   /tmp/.font-unix
0   /tmp/.Test-unix
0   /tmp/.X11-unix
0   /tmp/.ICE-unix
4.0K    /tmp/yum_save_tx.2021-06-10.09-43.sULMgF.yumtx
4.0K    /tmp/a.txt
8.0K    /tmp/
[root@arm64v8 ~]# 
[root@arm64v8 ~]# du -h --max-depth=1 /usr/
78M /usr/bin
43M /usr/sbin
468M    /usr/lib
155M    /usr/lib64
238M    /usr/share
0   /usr/etc
0   /usr/games
36K /usr/include
14M /usr/libexec
0   /usr/local
0   /usr/src
991M    /usr/
[root@arm64v8 ~]# 
[root@arm64v8 ~]# du -h --max-depth=1 --exclude=/usr/lib64 /usr
78M /usr/bin
43M /usr/sbin
468M    /usr/lib
238M    /usr/share
0   /usr/etc
0   /usr/games
36K /usr/include
14M /usr/libexec
0   /usr/local
0   /usr/src
837M    /usr
[root@arm64v8 ~]#

5.5.5、df 命令

df 用于报告磁盘空间使用率,默认显示的大小是 1K 大小 block 数量,也就是以 k 为单位。

和 du 不同的是,df 是读取每个文件系统的 superblock 信息,所以评估速度非常快。由于是读取 superblock,所以如果目录下挂载了另一个文件系统,是不会将此挂载的文件系统计入目录大小的。

如果用 df 统计某个文件的空间使用情况,将会转而统计该文件所在文件系统的空间使用情况。

df [OPTION]... [FILE]...
选项说明:
-h:人性化转换大小的显示单位
-i:统计inode使用情况而非空间使用情况
-l, --local:只列出本地文件系统的使用情况,不列出网络文件系统信息
-T, --print-type:同时输出文件系统类型
-t, --type=TYPE:只列出给定文件系统的统计信息
-x, --exclude-type=TYPE:指定不显示的文件系统类型的统计信息
[root@arm64v8 ~]# df -hT
Filesystem     Type      Size  Used Avail Use% Mounted on
devtmpfs       devtmpfs   16G     0   16G   0% /dev
tmpfs          tmpfs      16G     0   16G   0% /dev/shm
tmpfs          tmpfs      16G   20M   16G   1% /run
tmpfs          tmpfs      16G     0   16G   0% /sys/fs/cgroup
/dev/vda4      xfs       483G  1.2G  482G   1% /
/dev/vda2      xfs      1014M  108M  907M  11% /boot
/dev/vda1      vfat      200M  7.6M  193M   4% /boot/efi
tmpfs          tmpfs     3.2G     0  3.2G   0% /run/user/0
[root@arm64v8 ~]# 
[root@arm64v8 ~]# df -i
Filesystem        Inodes IUsed     IFree IUse% Mounted on
devtmpfs          260971   349    260622    1% /dev
tmpfs             261119     1    261118    1% /dev/shm
tmpfs             261119   498    260621    1% /run
tmpfs             261119    16    261103    1% /sys/fs/cgroup
/dev/vda4      253159936 28461 253131475    1% /
/dev/vda2         524288    16    524272    1% /boot
/dev/vda1              0     0         0     - /boot/efi
tmpfs             261119     1    261118    1% /run/user/0
[root@arm64v8 ~]# 

5.6、挂卸载文件系统

5.6.1、mount 命令

mount 用来显示挂载信息或者进行文件系统挂载,它的功能及其的强大,

它不仅支持挂载非常多种文件系统,如 ext/xfs/nfs/smbfs/cifs (win上的共享目录) 等,还支持共享挂载点、继承挂载点(父子关系)、绑定挂载点、移动挂载点等等功能。在本文只介绍其最简单的挂载功能。

mount 并非只能挂载文件系统,也可以将目录挂载到另一个目录下,其实它实现的是目录"硬链接",默认情况下,是无法对目录建立硬链接的,但是通过 mount 可以完成绑定,绑定后两个目录的 inode 号是完全相同的,但尽管建立的是目录的"硬链接",但其实也仅是拿来当软链接用。

以下是 ext 类文件系统的选项,可能有些选项是不支持其他文件系统的。

mount # 将显示当前已挂载信息
mount [-t 欲挂载文件系统类型 ] [-o 特殊选项] 设备名 挂载目录

选项说明:
-a  将/etc/fstab文件里指定的挂载选项重新挂载一遍。
-t  支持ext2/ext3/ext4/vfat/fat/iso9660(光盘默认格式)。 不用-t时默认会调用blkid来获取文件系统类型。
-n  不把挂载记录写在/etc/mtab文件中,一般挂载会在/proc/mounts中记录下挂载信息,然后同步到/etc/mtab,指定-n表示不同步该挂载信息。
-o  指定挂载特殊选项。下面是两个比较常用的:
    loop  挂载镜像文件,如iso文件
    ro  只读挂载
    rw  读写挂载
    auto  相当于mount -a
    dev 如果挂载的文件系统中有设备访问入口则启用它,使其可以作为设备访问入口
    default rw,suid,dev,exec,auto,nouser,async,and relatime
    async   异步挂载,只写到内存
    sync    同步挂载,通过挂载位置写入对方硬盘
    atime   修改访问时间,每次访问都修改atime会导致性能降低,所以默认是noatime
    noatime 不修改访问时间,高并发时使用这个选项可以减少磁盘IO
    nodiratime  不修改文件夹访问时间,高并发时使用这个选项可以减少磁盘IO
    exec/noexec  挂载后的文件系统里的可执行程序是否可执行,默认是可以执行exec, 优先级高于权限的限定
    remount  重新挂载,此时可以不用指定挂载点。
    suid/nosuid 对挂载的文件系统启用或禁用suid,对于外来设备最好禁用suid
    _netdev 需要网络挂载时默认将停留在挂载界面直到加载网络了。使用_netdev可以忽略网络正常挂载。如NFS开机挂载。
    user  允许普通用户进行挂载该目录,但只允许挂载者进行卸载该目录
    users  允许所有用户挂载和卸载该目录
    nouser  禁止普通用户挂载和卸载该目录,这是默认的,默认情况下一个目录不指定user/users时,将只有root能挂载
  • 一般 user/users/nouser 都用在 /etc/fstab 中,直接在命令行下使用这几个选项意义不是很大。

mount 应用举例

  1. 挂载 CentOS 的安装镜像到 /mnt

    [root@arm64v8 ~]# mount /dev/cdrom /mnt
    • 其实 /dev/cdrom 是 /dev/sr0 的一个软链接,/dev/sr0 是光驱设备,所以也可以用 /dev/sr0 进行挂载。
  2. 重新挂载

    [root@arm64v8 ~]# mount -t ext4 -o remount /dev/sda1 /data1
  3. 重新挂载文件系统为可读写

    [root@arm64v8 ~]# mount -t ext4 -o rw remount /dev/sda1 /data1
  4. 基于ssh挂载远程目录

    如何基于 ssh 像 NFS 一样挂载远程主机上的目录?可以通过 sshfs 工具,该工具在 fuse-sshfs 包中,这个包在 epel 源中提供。

    [root@brinnatt ~]# yum install epel-release -y
    [root@brinnatt ~]# yum install fuse-sshfs -y
    
    [root@brinnatt ~]# sshfs -p 7422 36.158.226.101:/ /mnt/
    The authenticity of host '[36.158.226.101]:7422 ([36.158.226.101]:7422)' can't be established.
    ECDSA key fingerprint is SHA256:URVNsjkxt5/51QYjJ/5K5POzrGOvDHkL51jqDaew7UY.
    ECDSA key fingerprint is MD5:34:c2:d9:36:d1:9a:ea:ba:45:14:22:2e:2a:66:f3:a2.
    Are you sure you want to continue connecting (yes/no)? yes
    root@36.158.226.101's password: 
    [root@brinnatt ~]# ls /mnt/
    bin   dev  Greatwall  lib    media  opt   root  sbin  sys  usr
    boot  etc  home       lib64  mnt    proc  run   srv   tmp  var
    [root@brinnatt ~]# 
  5. 挂载目录到另一个目录下。挂载目录时,挂载目录和挂载点的 inode 是相同的,它们两者的内容也是完全相同的

    [root@arm64v8 ~]# mkdir /tmp/mpoint
    [root@arm64v8 ~]# touch /tmp/mpoint/{1,2,3}.txt
    [root@arm64v8 ~]# ls /tmp/mpoint/
    1.txt  2.txt  3.txt
    [root@arm64v8 ~]# 
    [root@arm64v8 ~]# mkdir /tmp/point
    [root@arm64v8 ~]# touch /tmp/point/{a,b,c}.txt
    [root@arm64v8 ~]# ls /tmp/point/
    a.txt  b.txt  c.txt
    [root@arm64v8 ~]# 
    [root@arm64v8 ~]# mount --bind /tmp/mpoint/ /tmp/point/
    [root@arm64v8 ~]# ls /tmp/point/
    1.txt  2.txt  3.txt
    [root@arm64v8 ~]#
  6. 查看某个目录是否是挂载点,使用 mountpoint 命令

    [root@arm64v8 ~]# mountpoint /tmp/
    /tmp/ is not a mountpoint
    [root@arm64v8 ~]# mountpoint /tmp/point/
    /tmp/point/ is a mountpoint
    [root@arm64v8 ~]#

    挂载的参数信息存放在 /proc/mounts(是/proc/self/mounts的软链接) 中,在 /proc/self/mountstats 和 /proc/mountinfo 里则记录了更详细的挂载信息。

    [root@arm64v8 ~]# cat /proc/mounts | tail -6
    hugetlbfs /dev/hugepages hugetlbfs rw,relatime,pagesize=512M 0 0
    debugfs /sys/kernel/debug debugfs rw,relatime 0 0
    /dev/vda2 /boot xfs rw,relatime,attr2,inode64,noquota 0 0
    /dev/vda1 /boot/efi vfat rw,relatime,fmask=0077,dmask=0077,codepage=437,iocharset=ascii,shortname=winnt,errors=remount-ro 0 0
    tmpfs /run/user/0 tmpfs rw,nosuid,nodev,relatime,size=3342336k,mode=700 0 0
    /dev/vda4 /tmp/point xfs rw,relatime,attr2,inode64,noquota 0 0
    [root@arm64v8 ~]#

    文件系统是需要驱动支持的,没有驱动的文件系统也无法挂载,Linux 中支持的文件系统驱动在 /lib/modules/$(uname -r)/kernel/fs 下。

    [root@arm64v8 ~]# ls /lib/modules/$(uname -r)/kernel/fs/
    binfmt_misc.ko  cifs    fat      isofs  mbcache.ko  nfsd       pstore    xfs
    cachefiles      cramfs  fscache  jbd2   nfs         nls        squashfs
    ceph            ext4    fuse     lockd  nfs_common  overlayfs  udf
    [root@arm64v8 ~]# 

5.6.2、挂载镜像文件

mount 是一个极其强大的挂载工具,它支持挂载很多种文件类型,其中就支持挂载镜像文件,其实它连挂载目录都支持。

[root@controller1 3.5.2_arm_greatwall]# mount Greatwall-aarch64-DVD-3.5.2-190918-c75.iso /mnt/
mount: /dev/loop0 is write-protected, mounting read-only
[root@controller1 3.5.2_arm_greatwall]# lsblk 
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
loop0    7:0    0     3G  0 loop /mnt
sda      8:0    0 837.9G  0 disk 
├─sda4   8:4    0 832.7G  0 part /
├─sda2   8:2    0     1G  0 part /boot
├─sda3   8:3    0     4G  0 part [SWAP]
└─sda1   8:1    0   200M  0 part /boot/efi
[root@controller1 3.5.2_arm_greatwall]#

5.6.3、umount 命令

umount 设备名或挂载目录
umount -lf 强制卸载

卸载时,既可以使用设备名也可以使用挂载点卸载。有时候挂载网络系统(如NFS)时,设备名很长,这时候可以使用挂载点来卸载就方便多了。

如果用户正在访问某个目录或文件,使得卸载一直显示 Busy,使用 fuser -v DIR 可以知道谁正在访问该目录或文件。

[root@controller1 ~]# fuser -v /mnt/
                     USER        PID ACCESS COMMAND
/mnt:                root     kernel mount /mnt
[root@controller1 ~]#

使用 -k 选项 kill 掉正在使用目录或文件的进程,使用 -km 选项 kill 掉文件系统上的所有进程,然后再 umount。

[root@controller1 ~]# fuser -km /mnt/; umount /mnt/

5.6.4、开机自动挂载

通过将挂载选项写入到 /etc/fstab 中,系统会自动挂载该文件中的配置项。但要注意,该文件在开机的前几个过程中就被读取,所以配置错误很可能会导致开机失败。

fstable

其中最后两列,它们分别表示备份文件系统和开机自检,一般都可以设置为 0。由于能用的备份工具众多,没人会在这里设置备份,所以备份列设置为 0。

最后一列是开机自检设置列,开机自检调用的是 fsck 程序,所有有些 ext 类文件系统作为 "/" 时,可能会设置为1,但是 fsck 是不支持 xfs 文件系统的,所以对于 xfs 文件系统而言,该项必须设置为 0。

其实无需考虑那么多,直接将这两列设置为 0 就可以了。

5.6.5、修复错误

万一 /etc/fstab 配置错误,导致开机无法加载。一般是停留在 "Give root password for maintenance" 这样的界面,输入 root 密码进入系统,重新修改 /etc/fstab 文件,重启即可。

如果卡住没法进入系统,可以利用 grub 配置传入 rd.break 参数进入特权模式,修改 /etc/fstable 然后重启即可。

5.7、swap 分区

虽说个人电脑上基本已经无需设置 swap 分区了,但是在服务器上还是应该准备swap分区。

5.7.1、查看 swap

[root@arm64v8 ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:            31G        224M         31G         35M        441M         28G
Swap:           15G          0B         15G
[root@arm64v8 ~]#

使用 mount/lsblk 等可以查看出哪个分区在充当 swap 分区。使用 swapon -s 也可以直接查看出。

[root@arm64v8 ~]# swapon -s
Filename                Type        Size    Used    Priority
/dev/vda3                               partition   16712640    0   -2
[root@arm64v8 ~]# 

5.7.2、添加 swap 分区

  1. 可以新分一个区,在分区时指定其分区的 ID 号为 SWAP 类型。

    mbr 和 gpt 格式的磁盘上这个 ID 可能不太一样,不过一般 gp t中的格式是在 mbr 格式的 ID 后加上两位数的数值,如 mbr 中 swap 的类型 ID 为 82,在 gpt 中则是 8200,在 mbr 中 linux filesystem 类型的 ID 为 83,在 gpt 中则为 8300,在 mbr 中 lvm 的 ID 为 8e,在 gpt 中为 8e00。

  2. 格式化为 swap 分区:mkswap

    [root@arm64v8 ~]# mkswap /dev/sda1
    mkswap: /dev/sda1: warning: wiping old ext4 signature.
    Setting up swapspace version 1, size = 975808 KiB
    no label, UUID=9a96b5d9-70b4-4a70-a1d6-31ed99175b52
    [root@arm64v8 ~]# 
  3. 加入 swap 分区空间(swapon)

    [root@arm64v8 ~]# swapon /dev/sda1
    [root@arm64v8 ~]# free -h
                 total        used        free      shared  buff/cache   available
    Mem:            31G        225M         31G         35M        441M         28G
    Swap:           16G          0B         16G
    [root@arm64v8 ~]# 
  4. 取消 swap 分区空间(swapoff)

    [root@arm64v8 ~]# swapoff /dev/sda1
    [root@arm64v8 ~]# 
    [root@arm64v8 ~]# free -h
                 total        used        free      shared  buff/cache   available
    Mem:            31G        224M         31G         35M        441M         28G
    Swap:           15G          0B         15G
    [root@arm64v8 ~]#
  5. 开机自动加载 swap 分区

    # 修改 /etc/fstab,加上一行
    /dev/sda1    swap    swap    defaults    0    0
标签云