1个不稳定版本
0.1.0 | 2020年8月25日 |
---|
#1277 在 文件系统
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
的形式打印字符串,适合--filter
。 gen-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