我们可以在一个分区上创建两个不同的文件系统吗?

我们可以在一个分区上创建两个不同的文件系统吗?

我目前在我的计算机上使用 Ubuntu 20.04。

  1. 我们可以在一个分区上创建两个不同的文件系统吗?为什么?
  2. 另外,如果在分区中创建的文件系统的大小小于分区大小,我们将来可以扩展文件系统大小吗?

答案1

免责声明:对@Raffa 的回答超出范围的内容进行一些哲学阐述。

随着技术的进步,旧定义的界限变得越来越模糊。传统上,一个分区用一个文件系统格式化 - 现在通常仍是如此。

然而,新技术也带来了新的机遇。以下是其中一些:

  • 虚拟机在其他文件内托管虚拟文件系统,因此可以通过这种方式拥有多个嵌套文件系统。
  • 甚至包含 CD 或 DVD 媒体的磁盘映像的文件.iso.img以类似的方式嵌套和虚拟文件系统。
  • 容器也是如此。例如,Docker 容器在静态容器镜像(文件)上有一个单独的覆盖文件系统(具有特殊挂载的特殊文件系统)。
  • ZFS 可以将文件用作块设备 - 因此您可以再次在另一个文件系统之上创建“嵌套”的 ZFS 文件系统(这对于测试目的来说很有意义)。
  • 我确信还有很多我不知道的例子。

同时,还存在其他技术,例如 LVM(以及 ZFS)来实现相反的功能 - 让单个文件系统跨越多个分区或块设备。

所以最后,只有想象力才能限制使用正确工具所能实现的目标。困难的部分是明确您的需求,并找到正确的工具来实现它。

答案2

假设,通过“分区”,你的意思是硬盘上最后一级定义和连续的物理扇区组...我知道,这很难理解...但分区实际上可以是其他分区的容器,例如扩展分区(包含逻辑分区)或 LVM 物理卷(包含逻辑卷)...这些超出了这个答案的范围...这个答案的范围仅限于那些可以用文件系统在“裸机/扇区”上,而不是在另一个文件系统上)并作为数据安装在您的操作系统下(目录结构下的文件) 存储卷。

我们可以在一个分区上创建两个不同的文件系统吗?为什么?

,(我的意思是:操作系统用户实际上可以使用...不包括研究/取证/数据恢复的情况)。

创建和利用(安装和使用)文件系统,物理/逻辑边界必须通过以下方式定义/识别分区表或实际的整个磁盘边界(是的,硬盘可以在没有任何分区的情况下进行格式化、安装和使用……尽管在这种情况下,您可能需要在安装时指定文件系统类型) ... 内核读取磁盘上的分区表来确定分区边界、分区类型和文件系统...等等... 一个分区表可能只包含每个分区的一个文件系统类型... 当一个分区被挂载时,内核需要有该分区上该文件系统类型的模块/驱动程序,否则它将无法使用... 内核只能为每个分区/挂载点关联一个文件系统模块/驱动程序。

另外,如果在分区中创建的文件系统的大小小于分区大小,我们将来可以扩展文件系统大小吗?

是的,这是一种常见的做法,例如,当手动扩大具有现有文件系统的底层分区以利用未使用的相邻磁盘扇区/空间时……然后可以扩展文件系统以填充分区中的新额外空间……但是,您需要使用文件系统特定的工具来完成此任务,例如resize2fs适用于 ext2、ext3 和 ext4 文件系统。

答案3

在这个答案中,我试图回答以下问题:是否可以直接在同一个分区上创建和使用两个不同的文件系统,从偏移量 0(分区的开头)开始,在两个文件系统之间共享文件数据?

对于大多数实际目的而言,答案是对于只读用途,这是可能的(见下文),但不切实际,因为单个文件系统就足够了:大多数现代操作系统都可以读取UDF 文件系统 (ufs)exFAT 文件系统。对于读写使用,目前还不可能,因为对于写入,操作系统必须同时维护两个文件系统的文件系统元数据,而流行的操作系统没有这样的多文件系统驱动程序。必须编写用于写入这些文件系统的驱动程序或工具,据我所知,没有现成的此类工具。

但是,出于学术、黑客和演示目的,可以在分区的开头有两个文件系统,同时创建和填充这两个文件系统,然后将这两个文件系统用作只读文件系统,在 Linux 上同时最多挂载一个文件系统,并在挂载时指定文件系统类型(例如mount -o ro -t ext2mount -o ro -t vfat)。下面我使用一个概念验证来演示这一点,该概念验证创建了 2 个文件系统,两者都是正确的(没有文件系统检查错误)并且为空。

文件系统类型、大小和统计数据:

  • 第一个文件系统是 ext2(可以是 ext3、ext4 甚至 minix),第二个文件系统是 FAT16(可以是 FAT32 或 exFAT)。

  • FAT16 数据簇大小 == ext2 块大小 == 4 KiB

  • FAT16 扇区大小 == 512 字节,为了与旧的 FAT16 驱动程序兼容

  • 分区(磁盘映像)大小 == 文件系统大小 == 256 MiB == 65536 个块 * 每个块 4 KiB

  • 2 个 ext2 块组中有 65536 个 ext2 块(每个组有 32768 个块)

    最大文件大小 == 65296 * 4 KiB == 267452416 字节

    文件中有 65296 个数据块

    inode本身指向12个文件数据块

    64个间接块,每个指向1024个文件数据块(每个1个块号==4字节)

    1 个双重间接块,指向 64 个间接块(每个 1 个块号 == 4 个字节)

    数据块总数 == 65296 + 64 + 1 == 65361

  • FAT16 中的 65536 个 4-KiB 块:3 个保留块 + 32 个 FAT 块 + 1 个根目录块 + 139 个标记为坏的数据簇 + 65361 个好的数据簇

    最大文件大小 == 65361 * 4 KiB == 267718656 字节 =~ 255.316 MiB

在 Linux 上运行这些命令来创建文件系统映像两者皆可

dd if=/dev/zero bs=1M count=256 of=bothsh.img
# `*4' to convert from 4-KiB blocks to 1-KiB blocks.
(seq $((36*4)) $((106*4)) && seq $((32768*4)) $((32835*4))) >bb256m_fat16.lst
mkfs.fat -v -s 8 -S 512 -f 1 -F 16 -r 128 -R 24 -l bb256m_fat16.lst bothsh.img
# Copy (save) the FAT16 superblock, mke2fs will overwrite it.
dd if=bothsh.img of=bothsh.img.sb.tmp bs=512 count=1
# Copy (save) the FAT16 FAT, mke2fs will overwrite it.  
dd if=bothsh.img of=bothsh.img.fat.tmp bs=4K count=32 skip=3
seq 3 35 >bb256m_ext2.lst  # Counts 4 KiB blocks.
mke2fs -t ext2 -b 4096 -m 0 -O ^resize_inode -O ^dir_index -O ^sparse_super -I 128 -i 65536 -l bb256m_ext2.lst -F bothsh.img
dumpe2fs bothsh.img
# Restore the FAT16 superblock.
dd if=bothsh.img.sb.tmp of=bothsh.img bs=512 count=1 conv=notrunc
# Restore the FAT16 FAT.
dd if=bothsh.img.fat.tmp of=bothsh.img bs=4K count=32 conv=notrunc seek=3
rm -f bothsh.img.sb.tmp bothsh.img.fat.tmp
rm -f bb256m_fat16.lst bb256m_ext2.lst

请参阅完整的 Linux shell 脚本https://github.com/pts/mkfs_multi/blob/master/mkfs_ext2_fat16_shared_256m.sh

文件系统布局:

  • ext2 块组 0:(ext2 块 0..32767)
    • 块 0:
      • 前 512 个字节:FAT16 超级块(BPB,引导扇区),被 ext2 忽略(因为 ext2 忽略了文件系统的前 1024 个字节)
      • 接下来的 512 个字节:被 FAT16 忽略(因为它位于保留扇区)和 ext2 忽略(因为 ext2 忽略文件系统的前 1024 个字节)
      • 接下来的 1024 个字节:ext2 主超级块(始终位于偏移量 1024),被 FAT16 忽略(因为它位于保留扇区中)
      • 最后 2048 个字节:被 FAT16 忽略(因为它位于保留扇区中)和 ext2 忽略(因为下一个 ext2 块从偏移量 4096 开始)
    • 块 1:ext2 组描述符,被 FAT16 忽略(因为它位于保留扇区中)
    • 块 2:ext2 块位图(此 ext2 块组中每个块 1 位),被 FAT16 忽略(因为它位于保留扇区中)
    • 块 3..34:在 ext2、FAT16 FAT 中标记为坏块(65536 * 2 字节:可容纳 65536 个数据簇,每个数据簇 2 个字节)
    • 块 35:在 ext2、FAT16 根目录中标记为坏块(128 * 32 字节:可容纳 128 个条目,每个条目 32 字节)
    • 块 36:ext2 inode 位图,在 FAT16 中标记为坏块,第一个 FAT16 数据簇(数据簇 2)从这里开始
    • 块 37..100:ext2 inode 表(2048 * 128 字节:2048 个 inode 的空间,每个 inode 128 字节,使用了 11 个 inode,为什么这么多?),在 FAT16 中标记为坏块
    • 块 101:包含根目录 (/) 的目录条目的 ext2 数据块,在 FAT16 中标记为坏块
    • 块 102..105:包含 /lost+found 目录的目录条目的 ext2 数据块,在 FAT16 中标记为坏块
    • 块 106:包含 inode <1> 使用的间接块(坏块)的 ext2 数据块,在 FAT16 中标记为坏块
    • 块 107..32767:ext2 和 FAT16 中的可用数据块(32661 个块)
  • ext2 块组 1: (ext2 块 32768..65535)
    • 块 32768:ext2 备份超级块,在 FAT16 中标记为坏块
    • 块 32769:ext2 组描述符(我们为什么在这里需要它?),在 FAT16 中标记为坏块
    • 块 32770:ext2 块位图(此 ext2 块组中每个块 1 位),在 FAT16 中标记为坏块
    • 块 32771:ext2 inode 位图,在 FAT16 中标记为坏块
    • 块 32772..32835:ext2 inode 表(2048 * 128 字节:可容纳 2048 个 inode,每个 inode 128 字节,全部可用),在 FAT16 中标记为坏块
    • 块 32836..65535:ext2 和 FAT16 中的可用数据块(32700 个块)

ext2 inode(每个 128 字节):

  • inode <0>: 0 是无效的 inode 编号,它甚至没有存储在文件系统中
  • inode <1> == EXT2_BAD_INO 在偏移量 151552 处:坏块:模式 == 0,大小 == 135168(33 个坏块中的总字节数),33 个数据块:(0..11):3..14,(12..32):15..35,1 个间接块:106(包含块号 15..35,每个 4 个字节)
  • inode <2> == EXT2_ROOT_INO 位于偏移量 151680: 目录 /: 模式 == 0x41ed, 大小 == 4096, 1 个数据块: (0):101
  • inode <3> == EXT2_ACL_IDX_INO == EXT4_USR_QUOTA_INO 位于偏移量 151808:模式 == 大小 == 0,未使用,未在 ext2.h 中定义
  • inode <4> == EXT2_ACL_DATA_INO == EXT4_GRP_QUOTA_INO 位于偏移量 151936:模式 == 大小 == 0,未使用,未在 linux/fs/ext2/ext2.h 中定义
  • inode <5> == EXT2_BOOT_LOADER_INO 位于偏移量 152064:模式 == 大小 == 0,未使用,未在 linux/fs/ext2/ext2.h 中定义
  • inode <6> == EXT2_UNDEL_DIR_INO 位于偏移量 152192:模式 == 大小 == 0,未使用
  • inode <7> == EXT4_RESIZE_INO 位于偏移量 152320:模式 == 大小 == 0,未使用,保留组描述符
  • inode <8> == EXT4_JOURNAL_INO 位于偏移量 152448:模式 == 大小 == 0,未使用
  • inode <9>..<10> 位于偏移量 152576:模式 == 大小 == 0,未使用,剩余保留 inode(总共有 10 个)
  • inode <11> 位于偏移量 152832: 目录 /lost+found: 模式 == 0x41c0, 大小 == 16384 (4096 可能足够,或者根本没有 lost+found,但 mke2fs 故意留下了足够的空间),4 个数据块:(0..3):102-105
  • inode <12>..<2048> 位于偏移量 152960 处:可用 inode
  • inode <2049>..<4096> 位于偏移量 134234112 处:可用 inode

ext2 目录条目(dentry):

  • 对于 inode <2> (/):
    • 偏移量为 413696 的数据块 101:
      • inode <2> (.) 12 字节:inode=<2> size=12 name_size=1 type=2=DT_DIR name="."
      • inode <2> (..) 12 字节:inode=<2> size=12 name_size=2 type=2=DT_DIR name=".."
      • inode <11> (丢失+找到):inode=<11> 大小=4072 name_size=10 类型=2=DT_DIR name="丢失+找到"
  • 对于 inode <11> (/lost+found):
    • 偏移量为 417792 的数据块 102
      • inode <11> (.) 12 字节:inode=<11> size=12 name_size=1 type=2=DT_DIR name="."
      • inode <2> (..) 4084 字节:inode=<2> size=4084 name_size=2 type=2=DT_DIR name=".."
    • 偏移量 421888 处的数据块 103:空
      • 空:4096 字节:inode=0 size=4096 name_size=0 type=0=DT_UNKNOWN
    • 偏移量 425984 处的数据块 104:空
      • 空:4096 字节:inode=0 size=4096 name_size=0 type=0=DT_UNKNOWN
    • 偏移量 430080 处的数据块 105:空
      • 空:4096 字节:inode=0 size=4096 name_size=0 type=0=DT_UNKNOWN

用文件填充文件系统的一种方法(需要软件开发):

  • 将 ext2 文件系统挂载为读写。进行所有修改。卸载 ext2 文件系统。
  • 运行 recreator 工具,该工具在 ext2 文件系统上执行递归列表(只读),根据列表重新创建并写入所有 FAT16 元数据,并将某些 ext2 块(对应于 FAT16 子目录簇)标记为坏块。recreator 工具尚不存在,但如果有足够的动力,可以编写它。它将按如下方式工作:
    • 它读取并分析 ext2 超级块、ext2 块组和 FAT16 超级块(BPB,引导扇区),如果它们彼此不对应,则会失败。
    • 它在不挂载 ext2 文件系统的情况下对其进行递归列表。(它理解元数据。)作为递归列表的一部分,它会发现每个常规文件的数据块列表。
    • 它将大多数 ext2 坏块标记为空闲,并将其从坏块列表中删除。仅剩的 ext2 坏块是与 FAT16 FAT 和 FAT16 根目录相对应的坏块。
    • 它创建一个空的 FAT16 FAT,其中所有簇都是空闲的。根据 ext2 块位图,它将 FAT16 FAT 中所有使用的 ext2 块标记为坏块。它会相应地覆盖 FAT16 FAT。
    • 对于在递归 ext2 列表期间发现的每个常规文件,它会构建一个 FAT16 FAT 数据簇链,其中包含该文件的 ext2 文件数据块(而不是 ext2 间接块)。它会相应地更新或覆盖 FAT16 FAT。
    • 根据在递归 ext2 列表期间发现的目录和常规文件,它在内存中从头开始构建 FAT16 长文件名(VFAT、UTF-16、UCS-2)和目录条目,并将它们组织到 FAT16 数据簇中(每个子目录至少一个簇,根目录有一个特殊的簇偏移量)。它写入 FAT16 数据簇和根目录。对于每个子目录,它都会构建一个 FAT16 FAT 数据簇链。它会相应地更新或覆盖 FAT16 FAT。它将每个 FAT16 数据簇(由新创建的 FAT16 子目录使用)标记为 ext2 坏块。为此,它可能必须使用更多 ext2 文件间接块来扩展存储坏块列表的 ext2 inode。对于每个新的 ext2 文件间接块,它会将相应的 FAT16 簇标记为 FAT16 FAT 中的坏块。
    • 也许上面的一些 ext2 操作可以通过使用调试文件系统工具,从而使重建工具的实现更加简单。但是重建工具需要完全理解 FAT16 文件系统(这相对容易)。

使用此技术的最大文件系统大小:

  • 使用 FAT32 而不是 FAT16。
  • FAT32 FAT 的最大大小受 ext2 块组大小限制:每个组最多可包含 32695 个数据块(具有当前的 inode 比率),如果我们在 ext2 中将它们全部标记为坏的,那么我们有 32695 个 4 KiB 块用于 FAT32 FAT + 根目录,因此 FAT32 FAT 有 32694 个 4-KiB 块,因此 (32694 * 4096 / 4) - 2 == 33478654 FAT32 数据簇,因此 33478654 * 32 KiB == 1071316928 字节 =~ 0.99774 TiB 的可用数据。
  • ext2 和 FAT32 都可以达到 0.99774 TiB。
  • 使用 exFAT 而不是 FAT32 没有帮助,上面的 ext2 块组限制仍然适用。

答案4

  1. 另外,如果在分区中创建的文件系统的大小小于分区大小,我们将来可以扩展文件系统大小吗?

这取决于文件系统类型。要获取 Linux 上根文件系统的文件系统类型,请运行(不带前导$):

$ awk '$2=="/"&&/^\//{print$3}' </proc/mounts
ext4

然后进行 Google 搜索,找出要使用哪种工具来调整该类型的文件系统的大小。结果可能是:1. 该工具无需卸载即可调整大小;2. 卸载它(您可能需要从 USB 棒重新启动),运行该工具来调整大小,再次安装它;3. 不存在调整大小的工具(将数据复制到其他地方,创建空文件系统,再将数据复制回来)。

在上面的例子中,文件系统类型是ext4,谷歌搜索显示该工具是调整2fs大小,以及resize2fs 手册页说:

它可以用来扩大或缩小位于设备如果文件系统已经挂载,则可以使用它来扩展已挂载文件系统的大小,假设内核支持在线调整大小。

数据安全建议:为防止数据丢失,调整文件系统大小时请勿关闭计算机;调整大小前请保持笔记本电脑充电;如果断电风险较高,请将调整大小推迟到稍后进行。

  1. 我们可以在一个分区上创建两个不同的文件系统吗?为什么?

其他答案也与此相关,请阅读它们。在这个答案中,我试图回答以下问题:是否可以在同一个分区上直接创建和使用两个不同的文件系统,从偏移量 0(分区的开头)开始?

对于大多数实际目的而言,答案是。主流的文件系统创建工具会创建单个文件系统,在创建过程中,它们可能会覆盖分区上的某些块,这些块可能是前一个文件系统的元数据块,从而破坏前一个文件系统。这对于自动检测也不实用:主流的自动检测工具(例如Linux 发行版使用的文件系统将检测两个文件系统之一。Linux 挂载文件系统后,可以随意修改整个分区(文件系统覆盖的分区)以适应更改(例如,添加新文件、追加到现有文件)。此类修改最终会破坏另一个文件系统。

但是,出于学术、黑客和演示目的,可以在分区的开头有两个文件系统,最多同时挂载一个文件系统,并在挂载时指定文件系统类型(例如mount -t ext2mount -t vfat)。两个文件系统之间不会共享任何文件数据,因此必须单独复制每个文件,并且其数据将被复制。(请参阅我的其他答案以避免这种数据重复。)困难的部分是以不重叠的方式创建和填充文件系统,因为没有主流工具可以做到这一点。但是可以编写这样的工具,例如,如果文件系统 1 是 FAT16(或 FAT12 或 FAT32),而文件系统 2 是 ext2(或 minix 或其他一些)。这是因为 FAT16 将其文件系统头(超级块)存储在前 512 个字节中,而 ext2 忽略前 1024 个字节。FAT16 文件系统具有 2 字节保留扇区数字段(偏移量为 14),因此可以有近 32 MiB 的保留扇区(假设扇区大小为 512 字节)。这意味着分区的前 32 MiB(前 512 字节除外)被 FAT16 忽略。可以将整个 ext2 文件系统放在那里。通过更智能地安排多个不重叠的区域,可以拥有大于 32 MiB 的 ext2 文件系统。

在 Linux 上运行这些命令来创建一个组合的 FAT16 + ext2 文件系统(每个文件系统大约 32 MiB)来镜像文件bothfs.img

BLKDEV=bothfs.img
dd if=/dev/zero bs=1M count=64 of="$BLKDEV"
mkfs.fat -v -s 8 -S 512 -f 1 -F 16 -r 64 -R 65528 "$BLKDEV" 65536
# Copy (save) the FAT16 superblock, mke2fs will overwrite it.
dd if="$BLKDEV" of="$BLKDEV".bs.tmp bs=1K count=1
# See https://unix.stackexchange.com/q/122771 about `mke2fs -E resize=...`
# and `mke2fs -O ^resize_inode`.
mke2fs -t ext2 -b 4096 -m 0 -O ^resize_inode -O ^dir_index -I 128 -i 65536 -F "$BLKDEV" 8191
# Restore the FAT16 superblock.
dd if="$BLKDEV".bs.tmp of="$BLKDEV" bs=1K count=1 conv=notrunc
rm -f "$BLKDEV".bs.tmp
dumpe2fs "$BLKDEV"

请参阅完整的 Linux shell 脚本https://github.com/pts/mkfs_multi/blob/master/mkfs_ext2_fat16.sh

安装方法如下:

mkdir p
sudo mount -o loop -t ext2 bothfs.img p
sudo umount p
sudo mount -o loop -t vfat bothfs.img p
sudo umount p

通过使用 exFAT 而不是 FAT,可以使其他文件系统(例如 ext2)大于 32 MiB,因为 exFAT 文件系统将保留大小存储在 8 个字节中。但是,格式化文件系统工具 (源代码) 没有命令行标志来指定非零保留大小。

相关内容