pnfs 中的引用计数¶
存在多个相互关联的缓存。我们有布局(layout),它们可以引用多个设备,每个设备又可以引用多个数据服务器。每个数据服务器可以被多个设备引用。每个设备可以被多个布局引用。为了理清这些关系,我们需要进行引用计数。
struct pnfs_layout_hdr¶
网络命令 LAYOUTGET 对应于 `struct pnfs_layout_segment`,通常通过变量名 `lseg` 来引用。每个 `nfs_inode` 可以在 `nfsi->layout` 中持有一个指向这些布局段缓存的指针,其类型为 `struct pnfs_layout_hdr`。
我们为指向它的 inode 的头进行引用,跨每个引用它的未完成的 RPC 调用(LAYOUTGET, LAYOUTRETURN, LAYOUTCOMMIT),以及其中持有的每个 `lseg`。
每个头(非空时)也会被放入与 `struct nfs_client` (即 `cl_layouts`) 关联的列表中。被放入此列表不会增加引用计数,因为布局是由将其保留在列表中的 `lseg` 维持的。
deviceid_cache¶
`lseg` 引用设备 ID,这些 ID 根据 `nfs_client` 和布局驱动程序类型进行解析。设备 ID 保存在 RCU 缓存 (`struct nfs4_deviceid_cache`) 中。缓存本身在每次挂载时被引用。条目 (`struct nfs4_deviceid`) 本身在引用它们的每个 `lseg` 的生命周期内被持有。
使用 RCU 是因为设备 ID 本质上是一种写一次、读多次的数据结构。32 个桶的 `hlist` 大小需要更好的理由,但考虑到每个文件系统可以有多个设备 ID,并且每个 `nfs_client` 可以有多个文件系统,这个大小似乎是合理的。
哈希代码从 `nfsd` 代码库中复制而来。关于哈希算法及其变体的讨论可以在此处找到。
数据服务器缓存¶
文件驱动设备引用数据服务器,这些数据服务器保存在模块级别的缓存中。其引用在指向它的设备 ID 的生命周期内被持有。
lseg¶
`lseg` 维护一个额外的引用,对应于 `NFS_LSEG_VALID` 位,该位将其保持在 `pnfs_layout_hdr` 的列表中。当最后一个 `lseg` 从 `pnfs_layout_hdr` 的列表中移除时,`NFS_LAYOUT_DESTROYED` 位被设置,阻止任何新的 `lseg` 被添加。
布局驱动程序¶
PNFS 利用所谓的布局驱动程序。STD 定义了 4 种基本布局类型:“文件”、“对象”、“块”和“弹性文件”。对于每种类型,都有一个布局驱动程序,带有一个公共的函数向量表,由 `nfs-client` `pnfs-core` 调用以实现不同的布局类型。
Files 布局驱动代码位于:fs/nfs/filelayout/.. 目录下 Blocks 布局驱动代码位于:fs/nfs/blocklayout/.. 目录下 Flexfiles 布局驱动代码位于:fs/nfs/flexfilelayout/.. 目录下
块布局设置¶
待办:文档化块布局驱动程序的设置需求