共计 7529 个字符,预计需要花费 19 分钟才能阅读完成。
「所有皆文件」是 UNIX 的根本设计哲学。文件依照层级关系组织为树形目录,形成了文件系统 的根本状态。用户应用文件系统来保留数据时,不用关怀数据底层的存储形式,便能够依照约定的接口标准进行拜访。
概念篇
对于文件系统的接口标准,利用最为宽泛的莫过于 POSIX,源于 IEEE 委员会编写的相干规范,其中有些章节是对于文件及目录操作的。规范自身比拟简短艰涩,在此不作深入探讨。咱们能够参考 Quora 上的一个问答“What does POSIX conformance/compliance mean in the distributed systems world?”,对此概括的比拟全面。
POSIX 兼容要求文件系统具备以下几项特色:
- 层级化的目录构造,反对任意深度
- 文件通过
open(O_CREAT)
,目录通过mkdir
创立等等 - 目录能够通过
opendir/readdir
遍历 - 门路 / 命名空间能够通过
rename
、link / unlink
、symlink / readlink
等批改 - 数据通过
write
或writev
写入,fsync
时要求长久化,通过read
或readv
读取 - 其余一些接口如
stat
,chmod / chown
等 - 与某些风行的说法相悖,扩大属性看起来并不是 POSIX 的一部分,参见 The Open Group Base Specifications Issue 7, 2018 edition 里的函数列表
测试篇
一个文件系统是否真正满足 POSIX 兼容性,咱们能够通过测试工具来测验。比拟风行的一个测试用例集是 pjdfstest,来源于 FreeBSD,也实用于 Linux 等零碎。pjdfstest 的测试用例须要以 root 身份来运行,并且要求零碎里装置了 Perl 和 TAP::Harness(Perl 软件包),测试过程如下:
cd /path/to/filesystem/under/test
sudo prove --recurse --verbose /path/to/pjdfstest/tests
咱们选取了几种云环境中的共享文件系统进行测试,统计测试后果中的失败用例如下:
因为 Amazon EFS 失败的测试用例相比其余产品大了几个数量级,为了不便比拟,上图的横坐标应用了对数坐标。
咱们还同时测试了 S3FS 和 Goofys,失败的用例数均为数百项乃至上千项,其根本原因是这两个我的项目并不是严格依照文件系统来设计的:
- Goofys 能够将 S3 挂载为文件系统,但仅仅是“POSIX-ish”接口的“Filey”零碎(这两个形容来自于官网我的项目介绍,翻译成中文即“似是而非”或“同床异梦”)。Goofys 在设计理念上为了性能而就义了 POSIX 兼容性,所反对的文件操作极大地受限于 S3 等对象存储自身。测试后果也验证了这一点。倡议在生产应用之前全面评审利用的数据拜访形式,免得落入陷阱。
- S3FS 只管名为文件系统,但实际上更靠近于用 文件系统视图 治理 S3 bucket 中对象的一种办法。只管 S3FS 反对了 POSIX 的一个较大子集,但只是将零碎调用一一映射为对象存储申请,并不反对惯例文件系统的语义及一致性(例如目录的原子重命名,独占模式关上时的互斥,附加文件内容会导致重写整个文件以及不反对硬连贯等等)。这些缺点导致 S3FS 并不能用于代替惯例文件系统(即使不思考性能问题),因为当利用拜访文件系统时,预期的行为应该是合乎 POSIX 标准的,而 S3FS 远远不能满足这一点。
剖析篇
上面咱们将测试的失败用例进行分类统计,筛选几类比拟有代表性的来剖析下会对利用造成何种限度。
总的来说,无论从数量还是类别来看,JuiceFS 的失败用例都更少,有更好的兼容性。Amazon EFS 的失败用例无论从总数及类别均大大超出其它几种文件系统,无奈放入同一图表比照,前面将独自剖析。
JuiceFS
JuiceFS 在本次测试中通过了 8811 项用例中的绝大多数,仅在 utimensat 测试集上失败了 3 项。对应日志如下:
…
/root/pjdfstest/tests/utimensat/08.t ........
not ok 5 - tried 'lstat pjdfstest_bfaee1fc7f2c1f80768e30f203f41627 atime_ns', expected 100000000, got 0
not ok 6 - tried 'lstat pjdfstest_bfaee1fc7f2c1f80768e30f203f41627 mtime_ns', expected 200000000, got 0
Failed 2/9 subtests
/root/pjdfstest/tests/utimensat/09.t ........
not ok 5 - tried 'lstat pjdfstest_7911595d91adcf915009f551ac48e1f2 mtime', expected 4294967296, got 0
这几个测试用例出自 utimensat/08.t 和 utimensat/09.t。其中 08.t 是测试亚秒级的文件拜访工夫和批改工夫精度,09.t 则是要求反对 64 位工夫戳。
JuiceFS 目前只反对秒,工夫戳保留为 32 位整数,故无奈通过这三个测试(实际上本次测试波及的所有文件系统都无奈 100% 通过这个测试集)。如果您的利用场景要求秒以下的工夫精度或者更大范畴,欢送分割咱们切磋解决方案。
GCP Filestore
除了和 JuiceFS 一样在 utimesat 测试集上存在若干失败后果之外,GCP Filestore 还在 unlink 测试集中失败了 1 项。这一项在其余所有文件系统中也都是失败的。
/root/pjdfstest/tests/unlink/14.t ...........
not ok 4 - tried 'open pjdfstest_b03f52249a0c653a3f382dfe1237caa1 O_RDONLY : unlink pjdfstest_b03f52249a0c653a3f382dfe1237caa1 : fstat 0 nlink', expected 0, got 1
该测试集(unlink/14.t)用于验证一个文件在关上状态下被删除时的行为:
desc="An open file will not be immediately freed by unlink"
删除文件的操作在零碎层面理论对应于 unlink,即移除该文件名到对应 inode 的链接,对应 nlink 的值减 1,这个测试用例就是要验证这一点。
# A deleted file's link count should be 0
expect 0 open ${n0} O_RDONLY : unlink ${n0} : fstat 0 nlink
文件内容只有在链接数(nlink)缩小至 0 并且没有关上的文件描述符(fd)指向该文件时才会被真正删除。如果 nlink 没有被正确更新,可能会导致本该删除的文件依然残留在零碎里。
CFS
CFS 相比 Google Filestore,还未能通过 open 和 symlink 的几项测试。
open 失败用例
选取其中一部分失败日志如下:
/root/pjdfstest/tests/open/07.t .............
not ok 5 - tried '-u 65534 -g 65534 open pjdfstest_f24a42815d59c16a4bde54e6559d0390 O_RDONLY,O_TRUNC', expected EACCES, got 0
not ok 7 - tried '-u 65533 -g 65534 open pjdfstest_f24a42815d59c16a4bde54e6559d0390 O_RDONLY,O_TRUNC', expected EACCES, got 0
not ok 9 - tried '-u 65533 -g 65533 open pjdfstest_f24a42815d59c16a4bde54e6559d0390 O_RDONLY,O_TRUNC', expected EACCES, got 0
Failed 3/23 subtests
此测试集 open/07.t 用于验证不具备写权限时,应该对 O_TRUNC 模式返回 EACCES 谬误这一行为。
desc="open returns EACCES when O_TRUNC is specified and write permission is denied"
下面这三个失败日志须要联合测试代码来剖析,别离对应 owner,group 和 other 三种状况。不失一般性,咱们仅就 owner 状况进行剖析:
expect 0 -u 65534 -g 65534 chmod ${n1} 0477
expect EACCES -u 65534 -g 65534 open ${n1} O_RDONLY,O_TRUNC
首先设置文件 owner 权限为 4,即 r--
只读,而后尝试以 O_RDONLY,O_TRUNC 模式关上文件,预期应该返回 EACCES,理论返回了 0。
依据 The Single UNIX ® Specification, Version 2 中对 O_TRUNC 的阐明
O_TRUNC
If the file exists and is a regular file, and the file is successfully opened O_RDWR or O_WRONLY, its length is truncated to 0 and the mode and owner are unchanged. It will have no effect on FIFO special files or terminal device files. Its effect on other file types is implementation-dependent. The result of using O_TRUNC with O_RDONLY is undefined.
O_TRUNC 与 O_RDONLY 组合应用的后果是未知的,而且此用例的被测文件自身就是空文件,O_TRUNC 不会产生任何成果。
symlink 失败用例
对应测试日志如下:
/root/pjdfstest/tests/symlink/03.t ..........
not ok 1 - tried 'symlink 7ea12171c487d234bef89d9d77ac8dc2929ea8ce264150140f02a77fc6dcad7c3b2b36b5ed19666f8b57ad861861c69cb63a7b23bcc58ad68e132a94c0939d5/.../... pjdfstest_57517a47d0388e0c84fa1915bf11fe4a', expected 0, got EINVAL
not ok 2 - tried 'unlink pjdfstest_57517a47d0388e0c84fa1915bf11fe4a', expected 0, got ENOENT
Failed 2/6 subtests
该测试集(symlink/03.t)用于测试门路超出 PATH_MAX 长度时 symblink 的行为
desc="symlink returns ENAMETOOLONG if an entire length of either path name exceeded {PATH_MAX} characters"
失败的用例对应代码如下:
n0=`namegen`
nx=`dirgen_max`
nxx="${nx}x"
mkdir -p "${nx%/*}"
expect 0 symlink ${nx} ${n0}
expect 0 unlink ${n0}
该测试用例是要创立长度为 PATH_MAX (包含结尾的 0 在内)的符号链接,通不过表明无奈在 腾讯云 NAS 上创立长度为 PATH_MAX 的符号链接。
阿里云 NAS
相比腾讯云 NAS,阿里云 NAS 在 symlink 上体现失常,但未能通过 chmod 和 rename 上的几项测试用例。
chmod 失败用例
在这个测试集中,阿里云 NAS 失败了以下几个我的项目
/root/pjdfstest/tests/chmod/12.t ............
not ok 3 - tried '-u 65534 -g 65534 open pjdfstest_db85e6a66130518db172a8b6ce6d53da O_WRONLY : write 0 x : fstat 0 mode', expected 0777, got 04777
not ok 4 - tried 'stat pjdfstest_db85e6a66130518db172a8b6ce6d53da mode', expected 0777, got 04777
not ok 7 - tried '-u 65534 -g 65534 open pjdfstest_db85e6a66130518db172a8b6ce6d53da O_RDWR : write 0 x : fstat 0 mode', expected 0777, got 02777
not ok 8 - tried 'stat pjdfstest_db85e6a66130518db172a8b6ce6d53da mode', expected 0777, got 02777
not ok 11 - tried '-u 65534 -g 65534 open pjdfstest_db85e6a66130518db172a8b6ce6d53da O_RDWR : write 0 x : fstat 0 mode', expected 0777, got 06777
not ok 12 - tried 'stat pjdfstest_db85e6a66130518db172a8b6ce6d53da mode', expected 0777, got 06777
Failed 6/14 subtests
该测试集(chmod/12.t)用于测试 SUID/SGID 位的行为
desc="verify SUID/SGID bit behaviour"
咱们选取其中的第 11 和 12 个测试用例来具体解释一下,同时笼罩了这两个权限位
# Check whether writing to the file by non-owner clears the SUID+SGID.
expect 0 create ${n0} 06777
expect 0777 -u 65534 -g 65534 open ${n0} O_RDWR : write 0 x : fstat 0 mode
expect 0777 stat ${n0} mode
expect 0 unlink ${n0}
此处,咱们先以 06777 的权限创立指标文件,而后批改文件内容,查看 SUID 和 SGID 是否被正确革除。文件权限里的 777 大家会比拟相熟,别离对应 owner,group 和 other 的 rwx,即可读、可写、可执行。最后面的 0 示意八进制数。
第二位 6 须要着重解释下,这个八位元组(octet)代表非凡权限位,其中前两位别离对应 setuid/setgid(或称 SUID/SGID),能够利用于可执行文件及公共目录。该权限位被设置时,任何用户都会以 owner(或 group)身份来运行该文件。这个非凡的属性容许用户获取通常只对 owner 凋谢的文件和目录拜访权限。例如 passwd 命令就设置了 setuid 权限,这容许普通用户批改明码,因为保留明码的文件是只容许 root 拜访的,用户不可间接批改。
setuid/setgid 设计的出发点是提供一种办法,让用户以限定的形式(指定可执行文件)拜访受限文件(非以后用户所有)。因而,当文件被非 owner 批改时应主动革除此权限位,以防止用户通过这个路径获取其余权限。
从测试后果中咱们能够看到在阿里云 NAS 中,文件被非 owner 批改时,setuid/setgid 均未被革除,这样实际上用户能够通过批改文件内容以该 owner 身份进行任意操作,这将会是个安全隐患。
参考浏览:Special File Permissions (setuid, setgid and Sticky Bit) (System Administration Guide: Security Services)
rename 失败用例
阿里云 NAS 在这个测试集上失败数量较多,达到了 24 项,全副呈现在 rename/09.t 中:
desc="rename returns EACCES or EPERM if the directory containing'from'is marked sticky, and neither the containing directory nor'from'are owned by the effective user ID"
这个测试集用于测验 sticky 位被设置时 rename 的行为:当蕴含源对象的目录设置了 sticky 权限位的时候,并且源对象和蕴含目录的 owner 都与无效用户 ID(effective user ID)不同时,rename 应该返回 EACCES 或 EPERM。(这样的简单逻辑令人联想到三国杀的武将技能设定……)。
sticky 位的典型利用是 /tmp 目录,容许所有人创立内容,然而只有 owner 能力删除文件。FTP 外面的公共上传目录通常也是这种设置。
几个失败的测试用例表明阿里云 NAS 对 sticky 位的反对还不够欠缺,非 owner 的 rename 操作没有被回绝,并且产生了理论的成果——源文件被重命名。这种行为越过了文件系统的访问控制,对用户文件的安全性造成了威逼。
Amazon EFS 中的失败用例
Amazon Elastic File System (EFS) 在 pjdfstest 测试中的不仅失败比例极高(8811 个测试用例失败了 1533 个),而且简直笼罩了所有类别,这比拟令人意外。
EFS 反对以 NFS 形式挂载,但对 NFS 个性的反对并不残缺。比方 EFS 不反对块设施和字符设施,这间接导致了 pjdfstest 中大量测试用例的失败。排除这两类文件之后,依然有上百项不同类别的失败,所以在简单场景中利用 EFS 必须慎之又慎。
总结篇
通过下面的比照剖析,JuiceFS 在兼容性方面体现最好,像大多数网络文件系统一样,为了性能就义了秒以下的工夫精度和范畴(1970 – 2106 年)。Google Filestore 和腾讯云 CFS 次之,有几类未能通过。而阿里云 NAS 和 Amazon EFS 的兼容性最差,有大量的兼容性测试通不过,其中包含有重大安全隐患的若干个测试用例,应用前倡议做安全性评估。
JuiceFS 始终非常重视对 POSIX 规范的高度兼容,咱们把 pjdfstest 等兼容性测试工具同其余随机和并发测试工具(比方 fsracer、fstool 等)一起作为集成测试工具,在继续欠缺性能、进步性能的同时,尽力放弃最大水平的 POSIX 兼容性,防止用户在应用过程中落入各种陷阱,从而更加专一于本身业务的倒退。
如有帮忙的话欢送关注咱们我的项目 Juicedata/JuiceFS 哟!(0ᴗ0✿)