Linux 挂载的本质是让让内核解析设备文件里的文件系统的过程。

基础挂载命令

mount 命令用于将外存文件系统挂载到 OS 维护的前端文件系统上。其命令格式为

mount -t <fs_type> <device> <mount point>

显示挂载情况

如果直接输入 mount 命令,那么就会显示 OS 当前的挂载情况,但是输出是线性的,不太好看。所以可以使用如下命令获得挂载点的树形显示

findmnt

多个挂载点

同一文件系统可以被挂载到多个 mount point,这被称为”bind mount”(多个路径是 bind 在一起的):

mount --bind <old_directory> <new_directory>

其实这并不难理解,它就像是文件系统层面的一个 symbol link。

共用挂载点

反过来,不同的文件系统也可以共用同一个 mount point,新挂载的文件系统会覆盖掉这个位置之前的文件系统。但如果使用”union mount”的形式,最后呈现的目录结构则是新旧文件系统 merge 后的结果:

mount --union /dev/sdb /mnt

卸载

挂载的时候需要同时指定块设备和挂载点,而卸载的时候只需指定其中一个元素即可:

umount <directory>
umount <device>

偏移量

一个磁盘镜像文件上可能存在多个分区,如果这时直接挂载设备,那么就会导致报错,如下所示:

$ sudo mount ./gem5/extern/disks/x86-ubuntu.img /mnt 
mount: /mnt: fsconfig system call failed: Can't find a SQUASHFS superblock on loop0.
       dmesg(1) may have more information after failed mount system call.

这里的意思是说在 loop0 上找不到超级块,这是因为虽然看似我们挂载的是磁盘镜像文件 ./gem5/extern/disks/x86-ubuntu.img ,但是实际上这个磁盘镜像文件并不能被挂载,只有设备文件才能被挂载,所以 mount 指令隐式地增加了这个步骤:

sudo losetup /dev/loop0 ./gem5/extern/disks/x86-ubuntu.img

也就是将磁盘镜像文件和回环设备 loop0 联系在了一起。当然在结束这一切后,还会有一个“取消联系”的操作

sudo losetup -d /dev/loop0

另外说一嘴,回环设备(Loop device)的最大作用就是允许用户将普通文件当作块设备进行操作,也就是它的本来用法。

正因我们将 loop0x86-ubuntu.img 联系在一起,所以报错中会显式的指出 loop0 没有超级块,这是因为超级块是文件系统的头部,而对于有分区的磁盘镜像,它的头部是分区表。

在理解这个无关紧要的报错后,我们意识到必须找到具体的分区并挂载。所以我们用 FDisk 命令去查看分区情况,会得到如下内容

> sudo fdisk -l ./gem5/extern/disks/x86-ubuntu.img 
Disk ./gem5/extern/disks/x86-ubuntu.img:2 GiB,2147483648 字节,4194304 个扇区
单元:扇区 / 1 * 512 = 512 字节
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘标签类型:dos
磁盘标识符:0xd0c30ca2
 
设备                                启动  起点    末尾    扇区 大小 Id 类型
./gem5/extern/disks/x86-ubuntu.img1 *     2048 4192255 4190208   2G 83 Linux

注意到这个磁盘镜像中只有一个分区,它的起点是 2048 ,所以我们可以在挂载的时候指定偏移量(也就是 2048 * 512),进而完成正确地挂载:

sudo mount -o loop,offset=$((2048*512)) ./gem5/extern/disks/x86-ubuntu.img /mnt

其中 -o 是指定挂载的参数, loop 就是回环设备的意思,而 offset 指定偏移量。