#fuse #testing #file #write #power #behavior

app outagefs

FUSE文件系统,用于模拟和测试断电时的行为

1个不稳定版本

0.1.0 2020年8月25日

#1277文件系统

MIT 许可证

170KB
4K SLoC

outagefs

outagefs提供了一种在无需实际断电的情况下测试应用程序和文件系统行为的途径。

它通过在块设备级别记录文件系统更改,并以随机方式丢弃未同步的写入来重放写入。记录是通过使用fuse来暴露表示块设备的监控文件来完成的。

目前,outagefs主要在Linux上进行开发和测试。

安装

outagefs可以通过cargo进行安装

cargo install outagefs

示例:ext4上的“原子重命名”

通常会在文件上创建一个文件,并将其重命名为覆盖现有文件,并期望该文件要么具有新内容,要么具有旧内容。这在ext4上实际上是如何工作的?让我们来看看。

设置

首先,准备一个包含文件b的ext4基本镜像,该文件具有一些内容

# or, try `-s 1m` and see if it makes a difference
truncate -s 3m base
# or, try 'ext2'
mkfs.ext4 base
mkdir ext4root
sudo mount -o loop -t ext4 base ext4root
sudo sh -c 'seq 4000 > ext4root/b'
sudo umount ext4root

记录

然后,使用outagefs记录写入+重命名操作

# try adding 'sync' before 'mv' if 'ext2' is used
outagefs mount --record --sudo --exec 'mount -o loop -t ext4 $1 ext4root; seq 2 6000 > ext4root/a; mv ext4root/{a,b}; umount ext4root'

(如果命令因“fusermount: 选项allow_other仅允许...”而失败,请编辑/etc/fuse.conf并取消提交user_allow_other,或以root用户身份运行outagefs命令)

上述命令使用base作为基本镜像,将其作为记录开启的单个文件挂载,并将该单个文件作为$1传递给shell脚本。shell脚本将文件挂载为ext4,并对ext4文件系统进行更改。写入到挂载的ext4文件系统被转换为对$1文件的低级写入和同步操作。--record标志告诉outagefs将更改写回磁盘作为changes

让我们检查outagefs是否记录了一些更改

outagefs show

验证

我们想要验证的属性是“b应具有新或旧内容”。让我们将此表达在脚本中,并将其命名为verify.py

import pathlib
path = pathlib.Path("./ext4root/b")

def seq(start, end):
    return b"".join([b"%d\n" % i for i in range(start, end + 1)])

try:
    if not path.exists():
        print("BAD: does not exist")
    else:
        data = path.read_bytes()
        if data == b"":
            print("BAD: empty file")
        elif data == seq(1, 4000):
            print("GOOD: old content")
        elif data == seq(2, 6000):
            print("GOOD: new content")
        else:
            print("BAD: unexpected content")
except Exception as ex:
    print(f"ERROR: {ex}")

验证最终状态良好

outagefs mount --sudo --exec 'mount -o loop -t ext4 $1 ext4root && python3 verify.py; umount ext4root'
# should print 'GOOD: new content'

如果所有写入都被丢弃,那也很好

outagefs mount --filter 0 --sudo --exec 'mount -o loop -t ext4 $1 ext4root && python3 verify.py; umount ext4root'
# should print 'GOOD: old content'

生成测试

更有趣的测试将在某些写入被丢弃而其他未被丢弃时进行。在理论上,可以查看outagefs show的结果,找出要丢弃的内容,并确定位作为“过滤器”(1:取,0或未提及:丢弃),并像这样进行测试:

outagefs mount --filter 1000000001000000011 --sudo --exec 'mount -o loop -t ext4 $1 ext4root && python3 verify.py; umount ext4root'

手动找出有趣的测试案例很耗时。outagefs提供子命令来生成测试案例

outagefs gen-tests

这将以offset:bits的形式打印字符串,适合--filtergen-tests尊重Sync操作。如果一个Sync没有被丢弃,那么它之前的所有Write都不会被丢弃。它还将尝试使测试案例的数量有界,以便测试可以完成。

现在,我们只需使用生成的测试,并对它们运行验证脚本

for f in $(outagefs gen-tests); do
    outagefs mount --filter $f --sudo --exec 'mount -o loop -t ext4 $1 ext4root && python3 verify.py; umount ext4root'
done

提示

更具挑战性的测试

上述测试可能挑战性不足。例如,单个写入是原子的,预期Sync将按预期工作。硬件可能具有不同的属性。例如,具有特定于硬件的2KB块大小,或者可能不始终遵守Sync,或者可能在写入过程中损坏数据。为了更容易地练习这种行为,outagefs有一个mutate子命令来重写更改

outagefs mutate --split-write --zero-fill --drop-sync

更改文件将更新为重写的结果。请注意,内部文件系统状态可能更容易损坏。在mount命令下可能会看到一些测试失败。这也更容易触发一些错误,如EUCLEAN或挂起。

运行测试的便捷方式

手动设置、记录和运行测试既繁琐又容易出错。run-suite子命令可以使其更容易

outagefs run-suite --sudo suite-examples/rename-no-fsync-ext2.py

上述命令将创建一个临时目录,使用prepare脚本调用以创建base镜像,然后changes以记录更改,最后verify以验证测试案例。测试完成后,临时目录将被删除。

依赖关系

~7–18MB
~234K SLoC