「所有皆文件」是 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✿)
发表回复