https://lwn.net/Articles/707602/ 

齐江

某些开发到取得成果耗费了很长时间。这在提议的statx()系统调用上得到了验证——至少,很长时间是肯定的,尽管我们依旧需要等待其开花结果。不过从大部分描述来看,这个stat()系统调用扩展将接近ready。近期的补丁显示出当前statx()的状态以及遗留的阻塞点(sticking point)。

stat()系统调用用于返回文件的元数据。它有着悠久的历史,早在1971年的Unix发行版第一版就首次登场。在接下来的45年里stat()很少变更,甚至操作系统其余部分围绕它变更。因此,它毫无疑问趋向不符合当前的需求。现在,它无法表示文件的关联信息,包括generation和版本号,文件创建时间,加密状态,是否存储在远程服务器上,等等。它使得调用者无法选择获取何种具体信息,甚至可能强制耗时的操作获取应用并不需要的数据。同时,时间戳域又有着year-2038问题。等等。

David Howells自2010开始零星地致力于替换stat()的工作,他的第3版Patch(算上他今年早些时候重启该项努力)于11月23日发布。而提议的statx()系统调用看上去和5月份的基本一样,存在少许变更。

statx()的原型依旧是:

int statx(int dfd, const char *filename, unsigned atflag, unsigned mask, struct statx *buffer);

通常地,dfd表示一个目录的文件描述符,filename表示对应的文件名;该文件可通过给定目录的相对路径查找到。如果filename传入为空,则dfd被解释成需要查询的文件。因此,statx()替代了stat()和fstat()的功能。

atflag参数修饰该系统调用的行为。它处理了几个当前内核已存在的标记:AT_SYMLINK_NOFOLLOW,用于返回符号连接信息而不是进一步跟踪它;AT_NO_AUTOMOUNT,用于阻止远程文件系统自动挂载。一组statx()专用的新标记控制着与远程服务器的数据同步,允许应用程序调节IO和精确结果之间的平衡。AT_STATX_FORCE_SYNC将强制与远程服务器的同步,即使本地内核认为其信息是最新的;而AT_STATX_DONT_SYNC则隐含着快速获取远程服务器的查询结果,但可能已过时甚至完全不可用。

因此,atflag参数控制着statx()将如何获数据;而mask则控制着获取何种数据。可用的标记允许应用程序请求文件权限,类型,连接数,所有权,时间戳等。特别值STATX_BASIC_STATS返回stat()将返回的所有信息,而STATX_ALL则返回所有可用的信息。降低请求的信息量可能减少执行该系统调用的IO数,但一些检视者担心开发者将直接用STATX_ALL以避免需要更多的思考。

最后的参数buffer包含需要填充关联信息的结构体;该补丁版本中结构体如下:

struct statx { __u32 stx_mask; /* What results were written [uncond] / __u32 stx_blksize; / Preferred general I/O size [uncond] / __u64 stx_attributes; / Flags conveying information about the file [uncond] / __u32 stx_nlink; / Number of hard links / __u32 stx_uid; / User ID of owner / __u32 stx_gid; / Group ID of owner / __u16 stx_mode; / File mode / __u16 __spare0[1]; __u64 stx_ino; / Inode number / __u64 stx_size; / File size / __u64 stx_blocks; / Number of 512-byte blocks allocated / __u64 __spare1[1]; struct statx_timestamp stx_atime; / Last access time / struct statx_timestamp stx_btime; / File creation time / struct statx_timestamp stx_ctime; / Last attribute change time / struct statx_timestamp stx_mtime; / Last data modification time / __u32 stx_rdev_major; / Device ID of special file [if bdev/cdev] / __u32 stx_rdev_minor; __u32 stx_dev_major; / ID of device containing file [uncond] / __u32 stx_dev_minor; __u64 __spare2[14]; / Spare space for future expansion */ };

这里stx_mask表示实际有效的域,它将是应用程序请求的信息与文件系统实际能提供的信息之间的交集。stx_attributes包含描述文件状态的标记,他们表示文件是否被压缩,加密,不可变,只允许追加,不包含在备份中,或者自动挂载点等。

时间戳域结构体:

struct statx_timestamp { __s64 tv_sec; __s32 tv_nsec; __s32 __reserved; };

__reserved是第3版基于近期讨论针对statx()的一个强烈反对观点加进来的。Dave Chinner建议,在将来的某个时间点,纳秒精度将不再适用,他指出该接口应当能够处理飞秒时间戳。几乎只有他一个人持有该观点,而其余参与者,如Alan Cox,指出光速将保证我们永远不需要纳秒精度以下的时间戳。但Chinner坚持自己的观点,因此Howells新增__reserved以备将来所需。

Chinner针对该接口还有若干其他反对意见,其中一部分尚未处理。这些包括STATX_ATTR_标记的定义通过FS_IOC_GETFLAGS和FS_IOC_SETFLAGS ioctl()系统调用屏蔽了对一组现有标记的使用。重用这些标记给予statx()代码的微小优化,但将继续保持过去造成的部分接口错误,Chinner说。Ted Ts‘o在检视2015版补丁集时提供过类似的建议,但第3版保持着同样的标记定义。

Chinner的最大反对意见在于,statx()缺少综合测试用例。他认为这些代码在测试用例提供之前不能进入主干。

非常坦白地说,我认为综合测试用例对这样一个通用、可扩展的新系统调用功能来说是无条件的。要么我们在合入前做到测试覆盖,要么我们不合入。我们一次又一次地证明没有经过测试的垃圾是无法工作的(shit doesn’t work if it’s not tested),并且无法被独立的文件系统开发者广泛验证。

该态度近期也被其他人所回应,如Michael Kerrisk。内核确有一段很长的历史合入过无法像其宣称那样工作的新系统调用,并得到了应有的惩罚。Howells将提供类似的测试用例,但目前没有。

在此之上发生的众多有争议的话题(bikeshedding),我很庆幸我目前*还没有*完成这个测试套件,它将至少有着两倍以上的工作。我*仍然*不知道最终的形式将会是什么。

该补丁集的变更看上去慢下来了,也许最终的版本开始成为焦点。但是,该项工作的历史暗示我们预期它在近期合入是不明智的。stat()系统调用伴随了我们很长时间,因此期望statx()将持续同样长时间也是合理的。一些额外做好该接口的“具有争议的话题(bikeshedding)”,也是可以理解的