NILFS2

NILFS2 是一个支持连续快照的日志结构文件系统 (LFS)。除了整个文件系统的版本控制功能外,用户甚至可以恢复几秒钟前错误覆盖或破坏的文件。由于 NILFS2 可以像传统的 LFS 一样保持一致性,因此它可以在系统崩溃后实现快速恢复。

NILFS2 每隔几秒或在每次同步写入的基础上创建许多检查点(除非没有更改)。用户可以选择连续创建的检查点中的重要版本,并可以将它们更改为快照,这些快照将被保留,直到它们被改回检查点。

在卷满之前,快照的数量没有限制。每个快照都可以与其可写挂载同时作为只读文件系统挂载,此功能方便在线备份。

用户空间工具包含在 nilfs-utils 包中,可从以下下载页面获取。至少需要“mkfs.nilfs2”、“mount.nilfs2”、“umount.nilfs2”和“nilfs_cleanerd”(所谓的清理器或垃圾收集器)。有关这些工具的详细信息,请参阅软件包中包含的手册页。

项目网页:

https://nilfs.sourceforge.io/

下载页面:

https://nilfs.sourceforge.io/en/download.html

列表信息:

http://vger.kernel.org/vger-lists.html#linux-nilfs

注意事项

NILFS2 尚未支持的功能

  • atime

  • 扩展属性

  • POSIX ACL

  • 配额

  • fsck

  • 碎片整理

挂载选项

NILFS2 支持以下挂载选项:(*) == 默认

barrier(*)

这启用/禁用写入屏障的使用。这

nobarrier

需要一个可以支持屏障的 IO 堆栈,如果 nilfs 在屏障写入时出现错误,它将发出警告并再次禁用。

errors=continue

在文件系统错误时继续。

errors=remount-ro(*)

在发生错误时将文件系统重新挂载为只读。

errors=panic

如果发生错误,则发出 panic 并停止机器。

cp=n

指定要挂载的快照的检查点号。检查点和快照由 lscp 用户命令列出。只有标记为快照的检查点才能使用此选项挂载。快照是只读的,因此必须一起指定只读挂载选项。

order=relaxed(*)

应用宽松的顺序语义,允许在没有元数据更新的情况下将修改后的数据块写入磁盘,而无需进行检查点。此模式等效于 ext3 文件系统的有序数据模式,只是数据块上的更新仍然保留原子性。这将提高覆盖写入的同步写入性能。

order=strict

应用严格的按顺序语义,保留所有文件操作的顺序,包括覆盖数据块。这意味着,保证在崩溃后恢复的文件系统中不会发生事件超车。

norecovery

在挂载时禁用文件系统的恢复。这会禁用只读挂载或快照设备上的所有写入访问。对于不干净卷上的 r/w 挂载,此选项将失败。

discard

这启用/禁用 discard/TRIM 命令的使用。

nodiscard(*)

当释放块时,discard/TRIM 命令将发送到基础块设备。这对于 SSD 设备和稀疏/精简配置的 LUN 非常有用。

Ioctls

有一些 NILFS2 特有的功能,可以通过系统调用接口供应用程序访问。下表显示了所有 NILFS2 特有的 ioctl 的列表。

NILFS2 特有的 ioctl 表

Ioctl

描述

NILFS_IOCTL_CHANGE_CPMODE

更改给定检查点在检查点和快照状态之间的模式。此 ioctl 用于 chcp 和 mkcp 实用程序。

NILFS_IOCTL_DELETE_CHECKPOINT

从 NILFS2 文件系统中删除检查点。此 ioctl 用于 rmcp 实用程序。

NILFS_IOCTL_GET_CPINFO

返回有关请求的检查点的信息。此 ioctl 用于 lscp 实用程序和 nilfs_cleanerd 守护程序。

NILFS_IOCTL_GET_CPSTAT

返回检查点统计信息。此 ioctl 由 lscp、rmcp 实用程序和 nilfs_cleanerd 守护程序使用。

NILFS_IOCTL_GET_SUINFO

返回有关请求的段的段使用信息。此 ioctl 用于 lssu、nilfs_resize 实用程序和 nilfs_cleanerd 守护程序。

NILFS_IOCTL_SET_SUINFO

修改请求的段的段使用信息。此 ioctl 由 nilfs_cleanerd 守护程序使用,以跳过不必要的段清理操作,并减少由于重复移动使用中的块而导致的性能损失或闪存设备的磨损。

NILFS_IOCTL_GET_SUSTAT

返回段使用统计信息。此 ioctl 用于 lssu、nilfs_resize 实用程序和 nilfs_cleanerd 守护程序。

NILFS_IOCTL_GET_VINFO

返回有关虚拟块地址的信息。此 ioctl 由 nilfs_cleanerd 守护程序使用。

NILFS_IOCTL_GET_BDESCS

返回有关磁盘块号的描述符的信息。此 ioctl 由 nilfs_cleanerd 守护程序使用。

NILFS_IOCTL_CLEAN_SEGMENTS

在用户空间请求的参数环境中执行垃圾回收操作。此 ioctl 由 nilfs_cleanerd 守护程序使用。

NILFS_IOCTL_SYNC

创建检查点。此 ioctl 用于 mkcp 实用程序。

NILFS_IOCTL_RESIZE

调整 NILFS2 卷的大小。此 ioctl 由 nilfs_resize 实用程序使用。

NILFS_IOCTL_SET_ALLOC_RANGE

定义段的字节下限和段的字节上限。此 ioctl 由 nilfs_resize 实用程序使用。

NILFS2 用法

要将 nilfs2 用作本地文件系统,只需

# mkfs -t nilfs2 /dev/block_device
# mount -t nilfs2 /dev/block_device /dir

这还将通过挂载助手程序 (mount.nilfs2) 调用清理器。

检查点和快照由以下命令管理。它们的手册页包含在上面的 nilfs-utils 包中。

lscp

列出检查点或快照。

mkcp

创建检查点或快照。

chcp

将现有检查点更改为快照,反之亦然。

rmcp

使指定的检查点无效。

要挂载快照

# mount -t nilfs2 -r -o cp=<cno> /dev/block_device /snap_dir

其中 <cno> 是快照的检查点号。

要卸载 NILFS2 挂载点或快照,只需

# umount /dir

然后,清理器守护程序将由 umount 助手程序 (umount.nilfs2) 自动关闭。

磁盘格式

除了超级块 (SB) 和段 #0 之外,nilfs2 卷被均等地划分为许多段。段是日志的容器。每个日志由摘要信息块、有效负载块和一个可选的超级根块 (SR) 组成

 ______________________________________________________
| |SB| | Segment | Segment | Segment | ... | Segment | |
|_|__|_|____0____|____1____|____2____|_____|____N____|_|
0 +1K +4K       +8M       +16M      +24M  +(8MB x N)
     .             .            (Typical offsets for 4KB-block)
  .                  .
.______________________.
| log | log |... | log |
|__1__|__2__|____|__m__|
      .       .
    .               .
  .                       .
.______________________________.
| Summary | Payload blocks  |SR|
|_blocks__|_________________|__|

有效负载块按文件组织,每个文件由数据块和 B 树节点块组成

 |<---       File-A        --->|<---       File-B        --->|
_______________________________________________________________
 | Data blocks | B-tree blocks | Data blocks | B-tree blocks | ...
_|_____________|_______________|_____________|_______________|_

由于只有修改后的块写入日志,因此它可能具有没有数据块或 B 树节点块的文件。

块的组织记录在摘要信息块中,其中包含标头结构 (nilfs_segment_summary)、每个文件结构 (nilfs_finfo) 和每个块结构 (nilfs_binfo)

 _________________________________________________________________________
| Summary | finfo | binfo | ... | binfo | finfo | binfo | ... | binfo |...
|_blocks__|___A___|_(A,1)_|_____|(A,Na)_|___B___|_(B,1)_|_____|(B,Nb)_|___

日志包括常规文件、目录文件、符号链接文件和几个元数据文件。元数据文件是用于维护文件系统元数据的文件。当前版本的 NILFS2 使用以下元数据文件

1) Inode file (ifile)             -- Stores on-disk inodes
2) Checkpoint file (cpfile)       -- Stores checkpoints
3) Segment usage file (sufile)    -- Stores allocation state of segments
4) Data address translation file  -- Maps virtual block numbers to usual
   (DAT)                             block numbers.  This file serves to
                                     make on-disk blocks relocatable.

下图显示了日志的典型组织

 _________________________________________________________________________
| Summary | regular file | file  | ... | ifile | cpfile | sufile | DAT |SR|
|_blocks__|_or_directory_|_______|_____|_______|________|________|_____|__|

为了跨越段边界,此文件序列可能会拆分为多个日志。应被视为逻辑上一个日志的日志序列使用在段摘要中标记的标志分隔。nilfs2 的恢复代码会查找此边界信息,以确保更新的原子性。

每个检查点都会插入超级根块。它包括三个特殊的 inode,用于 DAT、cpfile 和 sufile 的 inode。常规文件、目录、符号链接和其他特殊文件的 inode 包含在 ifile 中。ifile 本身的 inode 包含在 cpfile 中相应的检查点条目中。因此,可以按如下方式描述 NILFS2 文件之间的层次结构

Super block (SB)
     |
     v
Super root block (the latest cno=xx)
     |-- DAT
     |-- sufile
     `-- cpfile
            |-- ifile (cno=c1)
            |-- ifile (cno=c2) ---- file (ino=i1)
            :        :          |-- file (ino=i2)
            `-- ifile (cno=xx)  |-- file (ino=i3)
                                :        :
                                `-- file (ino=yy)
                                  ( regular file, directory, or symlink )

有关每个文件格式的详细信息,请参阅位于 include/uapi/linux 目录中的 nilfs2_ondisk.h。

在 NILFS2 的设计方面,我们没有通过专利或其他知识产权来保护。允许复制该设计,希望其他操作系统可以共享(挂载、读取、写入等)以这种格式存储的数据。