NILFS2

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

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

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

用户空间工具包含在 nilfs-utils 包中,可从以下下载页面获得。至少需要 “mkfs.nilfs2”、“mount.nilfs2”、“umount.nilfs2” 和 “nilfs_cleanerd”(所谓的 cleaner 或垃圾收集器)。工具的详细信息在软件包中包含的 man 页面中描述。

项目网页:

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

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

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) 调用 cleaner。

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

lscp

列出检查点或快照。

mkcp

创建检查点或快照。

chcp

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

rmcp

使指定的检查点无效。

要挂载快照

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

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

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

# umount /dir

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

磁盘格式

nilfs2 卷被平均分成多个段,除了超级块 (SB) 和段 #0。段是日志的容器。每个日志由摘要信息块、有效负载块和一个可选的超级根块 (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 设计的任何专利或其他知识产权。允许复制该设计,希望其他操作系统可以共享(挂载、读取、写入等)以这种格式存储的数据。