# 练习 20：文件系统：修改和创建文件系统，`tune2fs`，`mkfs`

> 原文：[Exercise 20. Filesystems: modifying and creating filesystems, tune2fs, mkfs](https://archive.fo/CzHiN)

> 译者：[飞龙](https://github.com/wizardforcel)

> 协议：[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)

> 自豪地采用[谷歌翻译](https://translate.google.cn/)

让我来介绍一下文件系统相关的术语：

+   [文件系统](http://en.wikipedia.org/wiki/File_system) - 一种组织数据的方式，通过提供存储，检索和更新数据的过程，以及管理包含它的设备上的可用空间，数据预期在终止后保留。
+   Inode - 索引节点是一种结构，存储文件系统对象（文件，目录等）的所有信息，除数据内容和文件名之外。
+   块 - 可以分配的最小块磁盘空间。它通常默认为 4096 字节，或 4 千字节。
+   日志 - 一种结构，允许文件系统跟踪什么时候写入了什么。这样可以快速了解在断电或类似问题时，未正确写入的内容。

接下来，让我给大家简要介绍文件系统的工作原理。为了按名称访问文件，Linux 内核将：

+   在包含该文件的目录中查找文件名。
+   获取文件 Inode 号。
+   通过 Inode 区域中的数字查找 Inode。
+   读取此 Inode 的数据块的位置。
+   使用这个位置在数据区域中从这个块读取文件。

现在，每个文件系统都有很多与之相关的选项。这些选项可以通过`tune2fs `程序查看和更改。这是一个带注解的`tune2fs -l /dev/sda8`的输出：

```
user1@vm1:~$ sudo tune2fs -l /dev/sda8
tune2fs 1.41.12 (17-May-2010)
# 只是个标签，可以是任何东西，或者没有东西
Filesystem volume name:   <none>
# 这里应该是最后的挂载点
Last mounted on:          <not available>
# 唯一的文件系统标识符
Filesystem UUID:          869db6b4-aea0-4a25-8bd2-f0b53dd7a88e
# 已知位置的特殊数字，它定义了 FS 的类型，尝试这个：
# sudo dd if=/dev/sda8 of=/dev/stdout bs=1 skip=1080 count=2 | hexdump -C
Filesystem magic number:  0xEF53
# FS 版本
Filesystem revision #:    1 (dynamic)
# 启用的 FS 功能
Filesystem features:
    # 这是一个日志文件系统。日志文件系统是一个文件系统，
    # 它跟踪日志中发生的变化（通常是一个循环日志，
    # 在文件系统的特定位置），在提交给主文件系统之前。
    # 在系统崩溃或者断电的事件中，这种文件系统能够更快
    # 恢复，并且不可能毁坏。
    # http://en.wikipedia.org/wiki/Journaling_file_system
    has_journal
    # 拥有扩展属性，例如扩展的 ACL。
    ext_attr
    # 为系统信息保留空间，这允许 FS 改变大小。
    resize_inode
    # 使用索引来加速大目录中的查找。
    dir_index
    # 在目录条目中储存文件类型信息。
    filetype
    # 意思是需要运行 fsck。
    needs_recovery
    # 更少的超级块备份，在大 FS 上节约空间。
    sparse_super
    # 是否可以包含 > 2GB 的文件。在创建 >2GB 的文件时，内核会自动设置它。
    large_file
# dir_index 中使用哪个哈希
Filesystem flags:         signed_directory_hash
# 挂载时使用什么选项
Default mount options:    (none)
# 是否需要执行 fsck
Filesystem state:         clean
# 错误时做什么：继续，以只读方式重新挂载，或者报错？
Errors behavior:          Continue
# 哪个 OS 使用这个 FS
Filesystem OS type:       Linux
# 索引节点总数。索引节点就是 "inode"。它的结构是： 
# 储存所有文件系统对象（文件、目录，以及其他）的信息
# 除了文件内容和文件名称。也就是说，
# 你的文件数量不能多于索引节点数量。
# 这就是索引节点结构，它描述了里面储存了什么信息：
#/* 出现在 Inode 表中的 Inode 结构 */
#struct dinode
#{ ushort  di_mode;     /* mode and type of file   */
#  short   di_nlink;    /* number of links to file */
#  ushort  di_uid;      /* owner's user id         */
#  ushort  di_gid;      /* owner's group id        */
#  off_t   di_size;     /* number of bytes in file */
#  char    di_addr[39]; /* disk block addresses    */
#  char    di_gen;      /* file generation number  */
#  time_t  di_atime;    /* time last accessed      */
#  time_t  di_mtime;    /* time last modified      */
#  time_t  di_ctime;    /* time created            */
#};
# 这里也有很好的解释：
# http://support.tux4u.nl/dokuwiki/lib/exe/fetch.php?media=linux:disk_bestandssysteem:inode.pdf
Inode count:              62464
# 当前有多少空闲节点
Free inodes:              62452
# 设备上的第一个块。由于每个分区都表示为单独的设备，
# 它设为 0。
First block:              0
# 这是文件系统中，第一个索引节点的节点号。
First inode:              11
# 索引节点的大小，以字节为单位。在新的 Linux 发行版中，这有时会默认增加，
# 为了允许文件中扩展属性的存储，例如，微秒时间戳。
Inode size:               256
# 添加索引节点字段所需的空间
Required extra isize:     28
# 添加索引节点字段要求的空间。不重要，因为这个大小
# 任何时候都是所需空间
Desired extra isize:      28
# 一个隐形节点，它储存文件系统的日志。
Journal inode:            8
# 块的总数。块是磁盘空间可分配的最小单位。
# 你可以使用下面的公式，以 GB 计算分区大小：
# 块的数量 * 块的大小
# ------------------------
#         1024^3
Block count:              249856
# 有多少块为超极用户保留。普通用户不能使用这个
# 保留空间。这是为了使系统保持运行，以防一些流氓软件
# 决定塞满所有可用的磁盘空间。
Reserved block count:     12492
# 当前有多少块是空闲的。 
Free blocks:              241518
# 用于目录索引（dir_index）的算法。
Default directory hash:   half_md4
# 目前为止，我可以说，这是用于 dir_index 哈希算法的种子值。
Directory Hash Seed:      d02c6099-bd06-4d29-a3d7-779df2aa2410
# 日志备份选项。
Journal backup:           inode blocks                          #
# 块的大小，以字节为单位。4096 字节就是 4 KB。
Block size:               4096
# 在 ex3 FS 中未实现。这是一个特性，它能够在一个块中写入多个小文件，
# 来节约空间。
Fragment size:            4096
# 保留的控件，所以组描述符表可能在未来会增长。
Reserved GDT blocks:      60
# 每个块组的块数量。块组包含文件系统重要的控制信息的冗余副本。
# （超级块和文件描述符），并包含一部分文件系统contains a
# （块的位图，索引节点的位图，一部分索引节点表，以及数据块）。
# 块组的结构在下表中展示：
#,---------+---------+---------+---------+---------+---------,
#| 超级    | FS      | 块的    | Inode   | Inode   | 数据    |
#| 块      | 描述符  | 位图    | 位图    | 表      | 块      |
#`---------+---------+---------+---------+---------+---------'
# http://tldp.org/HOWTO/Filesystems-HOWTO-6.html
Blocks per group:         32768
# 每个组的片段数量。因为 ext3 FS 中没有片段，
# 这等于每个组的块数量。
Fragments per group:      32768
# 每个组的索引节点数量。
Inodes per group:         7808
# 每个组的索引节点块。索引节点块是一个表的索引，
# 描述了所有文件属性，除了文件名称。它拥有数据块的索引。
# 数据块包含文件真实内容。
# http://www.porcupine.org/forensics/forensic-discovery/chapter3.html
Inode blocks per group:   488
# FS 的创建时间。
Filesystem created:       Mon Jul  2 06:16:24 2012
# 最后的 FS 挂载时间。
Last mount time:          Mon Jul  2 06:57:21 2012
# 最后的 FS 写入时间。
Last write time:          Mon Jul  2 06:57:21 2012
# FS 的挂载次数。
Mount count:              6
# 自动检查前的次数。如果文件系统的挂载次数是这个
# 或者检查间隔到了，那么 FS 会自动检查。
Maximum mount count:      34
# 最后的 fsck 执行时间
Last checked:             Mon Jul  2 06:16:24 2012
# 下一个 FS 检查间隔. 如果这个间隔到了，
# 或者到达了最大挂载数，FS 会自动检查。
Check interval:           15552000 (6 months)
# 下一个 FS 检查间隔，以人类可读的格式。
Next check after:         Sat Dec 29 05:16:24 2012
# 能够使用保留空间的用户的用户 ID。
# 它默认是 root 用户（超级用户）
Reserved blocks uid:      0 (user root)
# 能够使用保留空间的用户的组 ID。
# 它默认是 root 组
Reserved blocks gid:      0 (group root)
```

很可怕，是嘛？实际上你会发现，这个描述中只有几个参数实际上是有用的，它们是：

+   保留块数量。
+   最大挂载数。
+   检查间隔。

通常你不需要修改其他参数，默认情况下它们是正常的。以下是使用文件系统的命令列表：

+   `mkfs.ext3` - 创建一个`ext3`文件系统。如果在具有现有文件系统的设备上执行此命令，则该文件系统将被销毁，因此请小心。
+   `mkfs.ext4` - 创建一个`ext4`文件系统。这其实是相同的程序，尝试`sudo find /sbin -samefile sbin/mkfs.ext3`。
+   `tune2fs` - 打印并更改文件系统参数。

现在，你将学习如何创建新的文件系统并修改其参数。

## 这样做

```
1: sudo -s
2: umount /tmp
3: blkid | grep /dev/sda8
4: mkfs.ext3 /dev/sda8
5: blkid | grep /dev/sda8
6: blkid | grep /dev/sda8 >> /etc/fstab
7: vim /etc/fstab
```

现在你必须将`/tmp`那一行的 UUID。

```
# /tmp was on /dev/sda8 during installation
UUID=869db6b4-aea0-4a25-8bd2-f0b53dd7a88e /tmp            ext3    defaults        0       2
```

替换为你添加到文件末尾的那个：

```
/dev/sda8: UUID="53eed507-18e8-4f71-9003-bcea8c4fd2dd" TYPE="ext3" SEC_TYPE="ext2"
```

因为根据定义，你的 UUID 必须跟我的不同。在替换 UUID，编写文件，退出之后，继续并输入：

```
 8: mount /tmp
 9: tune2fs -c 2 /dev/sda8
10: unmount /tmp
11: fsck /tmp
12: for ((i=1;i<=4;i++)); do mount /tmp ; umount /tmp ; cat /var/log/messages | tail -n 4 ; done
13: fsck /tmp
14: mount -a
```

## 你会看到什么

```
user1@vm1:~$ sudo -s
root@vm1:/home/user1# umount /tmp
root@vm1:/home/user1# blkid | grep /dev/sda8
/dev/sda8: UUID="869db6b4-aea0-4a25-8bd2-f0b53dd7a88e" TYPE="ext3" SEC_TYPE="ext2"
root@vm1:/home/user1# mkfs.ext3 /dev/sda8
mke2fs 1.41.12 (17-May-2010)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
62464 inodes, 249856 blocks
12492 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=255852544
8 block groups
32768 blocks per group, 32768 fragments per group
7808 inodes per group
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376
 
Writing inode tables: done
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done
 
This filesystem will be automatically checked every 28 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.
root@vm1:/home/user1# blkid | grep /dev/sda8
/dev/sda8: UUID="53eed507-18e8-4f71-9003-bcea8c4fd2dd" TYPE="ext3" SEC_TYPE="ext2"
root@vm1:/home/user1# blkid | grep /dev/sda8 >> /etc/fstab
root@vm1:/home/user1# vim /etc/fstab
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
proc            /proc           proc    defaults        0       0
# / was on /dev/vda5 during installation
UUID=128559db-a2e0-4983-91ad-d4f43f27da49 /               ext3    errors=re
# /home was on /dev/vda10 during installation
UUID=32852d29-ddee-4a8d-9b1e-f46569a6b897 /home           ext3    defaults
# /tmp was on /dev/sda8 during installation
UUID=869db6b4-aea0-4a25-8bd2-f0b53dd7a88e /tmp            ext3    defaults
# /usr was on /dev/vda9 during installation
UUID=0221be16-496b-4277-b131-2371ce097b44 /usr            ext3    defaults
# /var was on /dev/vda8 during installation
UUID=2db00f94-3605-4229-8813-0ee23ad8634e /var            ext3    defaults
# swap was on /dev/vda6 during installation
UUID=3a936af2-2c04-466d-b98d-09eacc5d104c none            swap    sw
/dev/scd0       /media/cdrom0   udf,iso9660 user,noauto     0       0
/dev/sda8: UUID="53eed507-18e8-4f71-9003-bcea8c4fd2dd" TYPE="ext3" SEC_TYPE
                                                         22,1          Bot
 
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
proc            /proc           proc    defaults        0       0
# / was on /dev/vda5 during installation
UUID=128559db-a2e0-4983-91ad-d4f43f27da49 /               ext3    errors=re
# /home was on /dev/vda10 during installation
UUID=32852d29-ddee-4a8d-9b1e-f46569a6b897 /home           ext3    defaults
# /tmp was on /dev/sda8 during installation
UUID=53eed507-18e8-4f71-9003-bcea8c4fd2dd /tmp            ext3    defaults
# /usr was on /dev/vda9 during installation
UUID=0221be16-496b-4277-b131-2371ce097b44 /usr            ext3    defaults
# /var was on /dev/vda8 during installation
UUID=2db00f94-3605-4229-8813-0ee23ad8634e /var            ext3    defaults
 
# swap was on /dev/vda6 during installation
UUID=3a936af2-2c04-466d-b98d-09eacc5d104c none            swap    sw
/dev/scd0       /media/cdrom0   udf,iso9660 user,noauto     0       0
"/etc/fstab" 22L, 1277C written
root@vm1:/home/user1# mount /tmp
root@vm1:/home/user1# tune2fs -c 2 /dev/sda8
tune2fs 1.41.12 (17-May-2010)
Setting maximal mount count to 2
root@vm1:/home/user1# unmount /tmp
root@vm1:/home/user1# fsck /tmp
fsck from util-linux-ng 2.17.2
e2fsck 1.41.12 (17-May-2010)
/dev/sda8: clean, 11/62464 files, 8337/249856 blocks (check in 2 mounts)
root@vm1:/home/user1# for ((i=1;i<=4;i++)); do mount /tmp ; umount /tmp ; cat /var/log/messages | tail -n 4 ; done
Jul  2 12:11:43 vm1 kernel: [21080.920658] EXT3-fs: mounted filesystem with ordered data mode.
Jul  2 12:11:58 vm1 kernel: [21096.363787] kjournald starting.  Commit interval 5 seconds
Jul  2 12:11:58 vm1 kernel: [21096.364167] EXT3 FS on sda8, internal journal
Jul  2 12:11:58 vm1 kernel: [21096.364171] EXT3-fs: mounted filesystem with ordered data mode.
Jul  2 12:11:58 vm1 kernel: [21096.364171] EXT3-fs: mounted filesystem with ordered data mode.
Jul  2 12:11:58 vm1 kernel: [21096.381372] kjournald starting.  Commit interval 5 seconds
Jul  2 12:11:58 vm1 kernel: [21096.381539] EXT3 FS on sda8, internal journal
Jul  2 12:11:58 vm1 kernel: [21096.381542] EXT3-fs: mounted filesystem with ordered data mode.
Jul  2 12:11:58 vm1 kernel: [21096.396152] kjournald starting.  Commit interval 5 seconds
Jul  2 12:11:58 vm1 kernel: [21096.396158] EXT3-fs warning: maximal mount count reached, running e2fsck is recommended
Jul  2 12:11:58 vm1 kernel: [21096.396344] EXT3 FS on sda8, internal journal
Jul  2 12:11:58 vm1 kernel: [21096.396348] EXT3-fs: mounted filesystem with ordered data mode.
Jul  2 12:11:58 vm1 kernel: [21096.412434] kjournald starting.  Commit interval 5 seconds
Jul  2 12:11:58 vm1 kernel: [21096.412441] EXT3-fs warning: maximal mount count reached, running e2fsck is recommended
Jul  2 12:11:58 vm1 kernel: [21096.412610] EXT3 FS on sda8, internal journal
Jul  2 12:11:58 vm1 kernel: [21096.412612] EXT3-fs: mounted filesystem with ordered data mode.
root@vm1:/home/user1# fsck /tmp
fsck from util-linux-ng 2.17.2
e2fsck 1.41.12 (17-May-2010)
/dev/sda8 has been mounted 4 times without being checked, check forced.
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/sda8: 11/62464 files (0.0% non-contiguous), 8337/249856 blocks
root@vm1:/home/user1# mount -a
root@vm1:/home/user1#
```

## 解释

1.  执行 root（超级用户）shell。
1.  解除挂载`/tmp`，从`/etc/fstab`读取它的位置 。
1.  打印出`/dev/sda8`的UUID，`/dev/sda8`是挂载在`/tmp`上的文件系统。
1.  在`/dev/sda8`上创建一个新的文件系统。
1.  再次打印出`/dev/sda8`的 UUID，注意如何变化，因为你创建了一个新的文件系统。
1.  将此 UUID 附加到`/etc/fstab`。
1.  打开`/etc/fstab`进行编辑。
1.  挂载新创建的文件系统。这实际上是一个检查，是否你已经正确替换了 UUID，如果不是会有一个错误消息。
1.  设置每两次挂载检查`/dev/sda8`。
1.  解除挂载`/dev/sda8`。
1.  检查`/dev/sda8`。
1.  挂载，接触挂载`/dev/sda8`， 并连续四次向你展示`/var/log/messages/`的最后4 行。请注意，从第三次开始，挂载系统通知你 需要运行`e2fsck`。如果你重新启动系统，它将为你运行`e2fsck`。
1.  检查`/dev/sda8`。`fsck`确定文件系统类型并自动调用`e2fsck`。
1.  挂载所有文件系统。如果没有错误，你已经完成了这个练习。

## 附加题

+   阅读`man mkfs`，`man mkfs.ext3`，`man tune2fs`。
+   阅读页面顶部的`tune2fs -l`列表，并为你的所有文件系统读取幻数。
+   手动计算文件系统的大小，使用在`tune2fs -l`列表的块描述中提供的公式。
+   阅读这个幻灯片，并完成它展示的东西：<http://mcgrewsecurity.com/training/extx.pdf>。
