【linux3.10】【nfs】使文件系统可导出

原文链接:
Exporting

概述

  所有的文件系统操作都需要一个dentry(或者两个)作为起始点。本地应用程序通过打开的文件描述符或 cwd/root 对合适的 dentry 进行引用计数保留。然而,通过远程文件系统协议(如 NFS)访问文件系统的远程应用程序可能无法保存这样的引用,因此需要一种不同的方式来引用特定的 dentry。由于替代的引用形式需要在重命名、截断和服务器重启时保持稳定(除其他外,尽管这些往往是最有问题的),因此没有像“文件名”这样的简单答案。
  此处讨论的机制允许每个文件系统实现指定如何为任何 dentry 生成不透明(文件系统之外)字节字符串,以及如何为任何给定的不透明字节字符串找到合适的 dentry。
  这个字节串将被称为“文件句柄片段”,因为它对应于 NFS 文件句柄的一部分。
  支持文件句柄片段和 dentries 之间映射的文件系统将被称为“可导出”。

dcache问题

  dcache 通常包含任何给定文件系统树的适当前缀。 这意味着如果任何文件系统对象在 dcache 中,那么该文件系统对象的所有祖先也在 dcache 中。 由于正常访问是通过文件名,这个前缀是自然创建的并且很容易维护(通过每个对象在其父对象上维护一个引用计数)。

  但是,当通过解释文件句柄片段将对象包含到 dcache 中时,不会自动为对象创建路径前缀。 这导致了dcache两个相关但不同的功能,而这是正常访问文件系统所不需要的。

  1. dcache 有时必须包含不属于正确前缀的对象。 即没有连接到根。
  2. dcache 必须为新发现的(通过 ->lookup)目录准备好(未连接的)dentry,并且必须能够将该 dentry 移动到位(基于 ->lookup 中的父级和名称) . 这对于目录尤其需要,因为目录只有一个 dentry 是 dcache 不变的。

为了实现这额功能,dcache需要:

  1. 一个 dentry 标志 DCACHE_DISCONNECTED,它被设置在任何可能不是正确前缀的一部分的 dentry 上。这在创建匿名 dentry 时设置,并在知道 dentry 是正确前缀中的 dentry 的子项时清除。 如果设置了此标志的 dentry 上的 refcount 变为零,则立即丢弃该 dentry,而不是保留在 dcache 中。 如果文件句柄重复访问不在 dcache 中的 dentry(如 NFSD 可能会这样做),则将为每次访问分配一个新的 dentry,并在访问结束时丢弃。
    请注意,这样的 dentry 可以在不清除 DCACHE_DISCONNECTED 的情况下获取children、name、parent等 - 只有当子树成功重新连接到根时才会清除该标志。 在此之前,只有在存在引用时才会保留此类子树中的 dentry; refcount 达到零意味着立即清理,与未散列的 dentry 相同。 这保证了我们不需要在 umount 上定位它们。
  2. 用于创建次根的原语 - d_obtain_root(inode)。那些不设置DCACHE_DISCONNECTED。 它们被放置在 per-superblock 列表 (->s_roots) 中,因此它们可以在 umount 时定位以进行驱逐。
  3. 帮助程序分配匿名目录,并帮助在查找时附加松散的目录项。 他们是:
      d_obtain_alias(inode) 将返回给定 inode 的 dentry。 如果 inode 已经有一个 dentry,则返回其中一个。如果没有,则会分配并附加一个新的匿名(IS_ROOT 和 DCACHE_DISCONNECTED)dentry。如果是目录,注意只能附加一个 dentry。
      d_splice_alias(inode, dentry) 将在树中引入一个新的 dentry; 或是给定的 dentry ,或是给定 inode 的已经存在的别名(例如由 d_obtain_alias 创建的匿名别名)。 当使用给定的 dentry 时,它返回 NULL,遵循 ->lookup 的调用约定。

文件系统问题

对一个需要可导出的文件系统,它必须:

  1. 提供下方描述的文件句柄片段的程序
  2. 当调用lookup为一个给定的parent和name寻找inode时,需要保证使用d_splice_alias 而不是d_add。如果inode时NULL,d_splice_alias(inode, dentry) 等同于d_add(dentry, inode), NULL。类似地,d_splice_alias(ERR_PTR(err), dentry) = ERR_PTR(err)。通常,lookuop程序将简单地用return d_splice_alias(inode, dentry);来结束。

  文件系统实现通过在 struct super_block 中设置 s_export_op 字段来声明文件系统的实例是可导出的。 此字段必须指向具有以下成员的“struct export_operations”结构:
encode_fh (可选)
  获取一个 dentry 并创建一个文件句柄片段,稍后可用于为同一对象查找或创建一个 dentry。默认实现会创建一个文件句柄片段,该片段会根据 32 位 inode 和已编码的 inode 的生成编号进行编码,并在必要时为父级提供相同的信息。

fh_to_dentry (必选)
给定一个文件句柄片段,这应该找到隐含的对象并为其创建一个 dentry(可能使用 d_obtain_alias)。

fh_to_parent (可选但强烈推荐)
给定一个文件句柄片段,这应该找到隐含对象的父级并为其创建一个 dentry(可能使用 d_obtain_alias)。 如果文件句柄片段太小,可能会失败。

get_parent (可选但强烈推荐)
当给定一个目录的 dentry 时,这应该返回父目录的 dentry。 很可能父 dentry 已由 d_alloc_anon 分配。 默认的 get_parent 函数只返回一个错误,因此任何需要查找父级的文件句柄查找都将失败。
->lookup("…") 不用作默认值,因为它可以在 dcache 中留下“…”条目,这些条目太混乱而无法使用。

get_name (可选)
当给定一个父 dentry 和一个子 dentry 时,这应该在由父 dentry 标识的目录中找到一个名称,这会找到由子 dentry 标识的对象。 如果未提供 get_name 函数,则提供默认实现,该实现使用 vfs_readdir 查找潜在名称,并匹配 inode 编号以查找正确匹配项。

文件句柄片段由 1 个或多个 4 字节字的数组以及一个 1 字节的“类型”组成。
decode_fh 例程不应依赖于传递给它的规定大小。 这个大小可能比encode_fh 生成的原始文件句柄大,在这种情况下,它将用空值填充。 相反,encode_fh 例程应该选择一个“类型”,它指示 decode_fh 文件句柄有多少是有效的,以及应该如何解释它。

上一篇:kubernetes 部署持久化jenkins


下一篇:centos7.6 nfs