1. 大小写折叠¶
bcachefs 支持使用常规的 chattr +F (S_CASEFOLD, FS_CASEFOLD_FL) 大小写折叠属性进行大小写不敏感的文件和目录查找。
大小写折叠的主要用例是与其他文件系统(例如 NTFS 和 Wine/Proton)编写的软件的兼容性,这些软件依赖于大小写折叠的查找。利用文件系统级别的大小写折叠可以大大提高许多应用程序和游戏的加载时间。
大小写折叠支持需要启用 CONFIG_UNICODE 的内核。一旦目录被标记为大小写折叠,超级块上就会启用一个功能位,该功能位将文件系统标记为使用大小写折叠。当启用大小写折叠的功能位时,如果没有启用 CONFIG_UNICODE,则无法在该内核上挂载该文件系统。
在查找/查询方面:大小写折叠是通过使用 utf8_casefold 函数分配一个 BCH_NAME_MAX 长度的新字符串来折叠查询字符串来实现的。
在目录项方面:大小写折叠是通过确保 bkey 的哈希值由大小写折叠的字符串生成,并将缓存的大小写折叠名称与目录项中的常规名称一起存储来实现的。
结构看起来像这样
常规:[目录项数据][常规名称][空][空]...
大小写折叠:[目录项数据][reg 长度][cf 长度][常规名称][大小写折叠名称][空][空]...
(请注意,此处的 NUL 的数量仅用于说明;它们的计数可能因键而异,如果键与 sizeof(u64) 对齐,它们甚至可能不存在。)
这是高效的,因为它意味着对于所有需要大小写折叠的文件查找,它具有与常规查找相同的性能:哈希比较和名称的 memcmp。
1.1. 原理¶
此系统考虑了几种设计:一种是引入 dirent_v2,但这会很痛苦,特别是当哈希系统仅支持单一键类型时。这也需要 BCH_NAME_MAX 在版本之间更改,以及一个新的功能位。
另一种选择是不存储两个长度,而只是取常规名称的长度和连续/2的大小写折叠名称的长度作为长度。这将假设常规长度 == 大小写折叠长度,但这可能不是真的,如果大写 Unicode 字形具有与小写 Unicode 字形不同的 UTF-8 编码。在这种情况下可能会忽略大小写折叠缓存,但决定简单地将两个字符串长度编码在键中,以避免如果遇到此极端情况时出现随机性能问题。
最终确定的选项是使用 d_type 中的一个空闲位将目录项标记为具有大小写折叠缓存,然后将名称块的前 4 个字节视为长度。您可以在 bch_dirent 中的联合的 d_cf_name_block 成员中看到这一点。
使用功能位是为了允许大多数用户启用大小写折叠支持,但也允许一些不需要该功能的用户仍然可以使用 bcachefs,因为 CONFIG_UNICODE 会因为使用的表而显着增加内核大小,这可能是决定是否使用 bcachefs(例如,对于嵌入式平台)的因素。
其他文件系统(如 ext4 和 f2fs)具有用于大小写折叠编码的超级块级别选项,但 bcachefs 目前不提供此选项。 ext4 和 f2fs 不公开任何编码,除了单一的 UTF-8 版本。当需要未来的编码时,可以使用 opts 机制轻松添加它们。
1.2. dentry/dcache 注意事项¶
目前,在大小写折叠目录中,bcachefs(与其他文件系统一样)不会缓存负 dentry。
这是因为目前这样做会在以下情况下出现问题
在大小写折叠目录中查找文件“blAH”
在大小写折叠目录中创建文件“BLAH”
在大小写折叠目录中查找文件“blAH”
如果缓存了负 dentry,这将失败。
这有点次优,但将来可以通过一些 vfs 工作来修复。
1.3. 参考¶
(来自 Peter Anvin,在邮件列表中)
值得注意的是,Microsoft 基本上已声明他们的“推荐”大小写折叠(大写)表将永久冻结(对于在格式化时创建磁盘上转换表的情况下,用于新的文件系统实例)。据我所知,他们从未支持 BMP 代码点的 1:1 转换以外的任何内容,也没有规范化。
exFAT 规范枚举了完整的推荐大写表,尽管格式有点烦人(基本上是压缩数据的十六进制转储)
https://learn.microsoft.com/en-us/windows/win32/fileio/exfat-specification