虽说接触NFS也有两年多了,但对RFC协议也只是偶尔查阅,没有系统的看过。最近公司鼓励我多做一些社区特性开发,就想着借助ChatGPT边翻译边学习,顺便记录下来,方便后继查阅。
本文章翻译自文档rfc8881, August 2020, Network File System (NFS) Version 4 Minor Version 1 Protocol,大部分借助于ChatGPT翻译,仅作为我个人的参考,如果你想查阅,建议看英文文档,因为我不确定我记录的中文翻译是否完整和正确。
持续更新中。。。
本文描述了网络文件系统(NFS)版本4的次版本1,包括从基础协议(在RFC 7530中指定的NFS版本4的次版本0)保留的特性以及随后进行的协议扩展。后续的次版本不依赖于NFS版本4的次版本0,并被视为一个独立的协议。
本文废弃了RFC 5661。它在很大程度上修改了与多服务器命名空间相关的特性的处理,取代了在RFC 5661中出现的对这些特性的描述。
本文档是一份Internet标准跟踪文件。
本文是Internet工程任务组(IETF)的成果。它代表了IETF社区的共识。经过公开审查,并已获得Internet工程指导组(IESG)批准发布。有关Internet标准的更多信息,请参阅RFC 7841的第2节。
有关本文档当前状态、任何勘误以及如何提供反馈意见的信息,请访问https://www.rfc-editor.org/info/rfc8881。
版权(c)2020 IETF信托和被确认为文档作者的人。保留所有权利。
本文受到BCP 78和IETF信托的与IETF文档相关的法律规定(https://trustee.ietf.org/license-info)的约束,该法规在本文档发布日期生效。请仔细阅读这些文件,因为它们描述了您对本文档的权利和限制。从本文档中提取的代码组件必须包含简化的BSD许可证文本,如信托法规的第4.e节所述,并且按照简化的BSD许可证描述的无任何保证提供。
本文可能包含在2008年11月10日之前发布或公开提供的IETF文档或IETF贡献的材料。在一些此类材料的版权控制人可能未授予IETF信托修改此类材料的权利的情况下,本文可能无法在IETF标准过程之外进行修改,并且除了将其格式化为RFC的出版物或将其翻译成英语以外,可能无法在IETF标准过程之外创建其衍生作品。
在次版本0中先前定义但在次版本1中从未完全解决的两个重要特性是干线化(trunking)和透明状态迁移(Transparent State Migration)。干线化是指在客户端和服务器之间同时使用多个连接,可能连接到不同的网络地址;透明状态迁移允许以一种方式将文件系统传输到另一台服务器,从而使客户端能够在传输过程中保持其现有的锁定状态。
此更新中提供的对NFS版本4次版本1(NFSv4.1)协议的修订描述是为了允许与其他多服务器命名空间特性一起充分使用这些功能。本文以更新的形式呈现了先前在RFC 5661 [66]中定义的NFSv4.1协议的描述。RFC 5661被本文所废弃。然而,此更新的范围有限,重点是允许充分使用干线化和透明状态迁移。对这些更改的需求在附录A中进行了讨论。附录B描述了到达当前文本所做的具体更改。
这个有限范围的更新替换了当前的NFSv4.1 RFC,旨在提供一份权威且完整的规范,其动机在[36]中进行了讨论,解决了更新范围内的问题。但是,它将不解决已知但超出此有限范围的问题,正如可以预期的协议的完整更新。以下是已知需要在协议的将来更新中解决的一些领域:
需要就RFC 8178 [67]进行工作,该RFC建立了NFSv4的版本规则。由于RFC 5661目前与该文档不一致,因此需要进行更改,以便在不需要RFC 8178更新NFSv4.1规范的情况下达到一种情况。
需要对RFC 8434 [70]进行工作,该RFC建立了并行NFS(pNFS)布局类型的要求,而RFC 5661中没有明确定义。当完成该工作并获得批准的结果文件时,新的NFSv4.1规范文件将提供一组清晰的布局类型要求,并描述符合这些要求的文件布局类型。其他布局类型将有它们自己符合这些要求的规范文件。
需要进行工作以处理与RFC 5661相关的许多勘误报告,除了本文档中处理的勘误报告2006 [64]。由于所建议的更改与那里提出的更改的交互作用以及新描述的状态和会话迁移的处理,因此必须进行处理。
在稍后的文档中需要解决已推迟的并且将需要处理的勘误报告,其中包括在勘误报告系统中分配了一系列状态的报告,包括标记为“已接受”的报告和标记为“保留以进行文档更新”的报告,因为更改太小而无法立即解决。
此外,还有一组其他报告,其中至少有一个处于拒绝状态,将需要在稍后的文档中进行处理。这将涉及对RFC 5661中反映的共识决策进行更改,情况是工作组已决定RFC 5661中的处理不正确并需要修订以反映工作组的新共识,并确保与不遵循RFC 5661中描述的处理的现有实现兼容。
请注意,尽管此文档废弃了RFC 5661 [66],但预计所有这些勘误报告将始终与实施者和最终的rfc5661bis的作者相关,尽管此文档废弃了RFC 5661 [66]。
有必要对国际化的描述采取新方法,因为当前的国际化部分(第14节)从未被实施,并且不符合NFSv4协议的需求。可能的解决方案是创建一个基于[68]中的国际化部分的新国际化部分,或者创建一个描述所有NFSv4次版本的国际化的新文档,并在定义NFSv4.0和NFSv4.1的RFC时引用该文档。
需要对NFSv4.1中的安全性进行修订处理。有关现有处理的问题在附录C中进行了讨论。
在进行上述工作之前,将无法提供一致的文档集来描述NFSv4.1协议,并且任何全面的描述都将涉及在规范内更新其他文档。RFC 8434 [70]和RFC 8178 [67]对RFC 5661的更新也适用于此规范,并且将适用于任何随后的v4.1规范,直到完成这项工作。
NFS版本4 次版本1(NFSv4.1)协议是NFS版本4(NFSv4)协议的第二个次版本。第一个次版本,NFSv4.0,现在在RFC 7530 [68]中进行了描述。它通常遵循RFC 3530 [37]第10节中列出的次版本化指南。然而,它与指南11(“支持次版本X的客户端和服务器必须支持次版本0到X-1”)和指南12(“不得在次版本中引入新功能作为强制性要求”)有所偏离。这些偏离是由于引入了用于管理非幂等操作和RECLAIM_COMPLETE操作的会话模型。这两个新功能在性质上是基础性的,简化了现有功能和其他新功能的实现。将它们定义为除了REQUIRED之外的任何内容都会给协议定义和实现增加不必要的复杂性。因此,NFSv4.1更新了次版本化指南(第2.7节)。
作为一个次版本,NFSv4.1与NFSv4的总体目标一致,但通过根据对NFSv4.0的经验扩展协议以更好地实现这些目标。此外,NFSv4.1还采纳了一些额外的目标,这些目标激发了NFSv4.1中的一些重大扩展。
本文档中的关键词“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY”和“OPTIONAL”应按照RFC 2119 [1]中的描述进行解释。
本文档描述了NFSv4.1协议。与NFSv4.0相关的,本文档不包括:
NFSv4.1 客户端和服务器必须支持并必须使用本节描述的会话功能。
以前的 NFS 版本和次要版本存在以下问题:
通过引入会话,NFSv4.1通过实际的解决方案解决了上述不足之处:
一个会话是由客户端动态创建的,长时间存在的服务器对象,可在一段时间内从一个或多个传输连接中使用。其功能是维护相对于属于客户端实例的一个或多个连接的服务器状态。该状态完全独立于连接本身,实际上,该状态存在与连接存在与否无关。客户端可能与之关联一个或多个会话,以便可以使用与该客户端的客户端 ID 关联的任何会话来访问客户端相关状态,当连接与那些会话关联时。当任何客户端 ID 的会话在较长时间内未关联任何连接时,诸如锁定、打开、授权、布局等对象都可能过期。该会话充当一个对象,表示客户端访问服务器上关联客户端状态的一种手段,独立于访问该状态的物理手段。
一个客户端可以创建多个会话。一个会话不能为多个客户端提供服务。
会话是 NFSv4.1 的一部分,而不是 NFSv4.0 的一部分。通常,像会话这样的主要基础架构更改都需要对像 NFS 这样的 Open Network Computing (ONC) RPC 程序的主版本号进行更新。然而,由于 NFSv4 将其功能封装在单个过程 COMPOUND 中,并且因为 COMPOUND 可以支持任意数量的操作,因此很容易在 NFSv4.1 中添加会话。COMPOUND 包括一个次版本号字段,对于 NFSv4.1,此次版本设置为 1。当 NFSv4 服务器处理次版本设置为 1 的 COMPOUND 时,它期望与 NFSv4.0 不同的一组操作。NFSv4.1 定义了 SEQUENCE 操作,该操作对于在已建立的会话上运行的每个 COMPOUND 都是必需的,但对于某些会话管理操作(如 DESTROY_SESSION,见第 18.37 节)除外。
在 NFSv4.1 中,当 SEQUENCE 操作存在时,它必须是 COMPOUND 过程中的第一个操作。SEQUENCE 的主要目的是携带会话标识符。会话标识符将 COMPOUND 过程中的所有其他操作与特定会话关联起来。SEQUENCE 还包含用于维护 EOS(参见第 2.10.6 节)的必需信息。因此,启用会话的 NFSv4.1 COMPOUND 请求的形式如下:
+-----+--------------+-----------+------------+-----------+----
| tag | minorversion | numops |SEQUENCE op | op + args | ...
| | (== 1) | (limited) | + args | |
+-----+--------------+-----------+------------+-----------+----
而回复的形式如下:
+------------+-----+--------+-------------------------------+--//
|last status | tag | numres |status + SEQUENCE op + results | //
+------------+-----+--------+-------------------------------+--//
//-----------------------+----
// status + op + results | ...
//-----------------------+----
CB_COMPOUND 过程的请求和回复与 COMPOUND 类似,但是没有 SEQUENCE 操作,而是有一个 CB_SEQUENCE 操作。CB_COMPOUND 还有一个额外的字段称为 “callback_ident”,在 NFSv4.1 中是多余的,客户端必须忽略它。CB_SEQUENCE 具有与 SEQUENCE 相同的信息,还包括解决回调竞争所需的其他信息(参见第2.10.6.3节)。
每个客户端标识(第2.4节)可以有零个或多个活动会话。在 NFSv4.1 中,执行文件访问需要客户端标识和关联的会话。每次会话被使用(无论是客户端向服务器发送请求还是客户端回复来自服务器的回调请求),都会自动续订分配给其关联客户端标识的状态。
状态(可以包括共享预留、锁、委托和布局(第1.8.4节))与客户端标识相关联。客户端状态不与任何个体会话相关联。从给定状态所有者进行的连续状态更改操作可能经过不同的会话,前提是该会话与相同的客户端标识相关联。回调可以经过与最初获取与回调相关状态的请求不同的会话。例如,如果使用会话 A 获取委托,则请求回收委托的回调可以在会话 B 上到达,前提是这两个会话都与相同的客户端标识相关联。第2.10.8.1节和第2.10.8.2节讨论了回调周围的安全考虑。
通道并不是连接。通道表示发送 ONC RPC 请求的方向。
每个会话有一个或两个通道: 前向通道和反向通道。由于每个会话最多有两个通道,并且由于每个通道都有不同的目的,因此通道不分配标识符。
前向通道用于从客户端到服务器的普通请求,负责传输 COMPOUND 请求和响应。一个会话始终具有前向通道。
反向通道用于从服务器到客户端的回调请求,并传输 CB_COMPOUND 请求和响应。是否存在反向通道由客户端决定;然而,NFSv4.1 的许多特性都需要反向通道。NFSv4.1 服务器必须支持反向通道。
每个会话都有用于每个通道的资源,包括单独的回复缓存(参见第2.10.6.1节)。请注意,即使反向通道也需要一个回复缓存(或者至少需要一个插槽表以便检测重试),因为某些回调操作是非幂等的。
每个通道与零个或多个传输连接相关联(无论是相同的传输协议还是不同的传输协议)。连接可以与会话的一个通道或两个通道相关联;客户端和服务器通过 CREATE_SESSION(第18.36节)和 BIND_CONN_TO_SESSION(第18.34节)操作协商连接是否将流量传输到会话的一个通道或两个通道。通过 CREATE_SESSION 创建会话时,传输 CREATE_SESSION 请求的连接将自动与前向通道关联,并可选择与反向通道关联。如果客户端在创建会话时未指定状态保护(第18.35节),则当 SEQUENCE 在不同的连接上传输时,该连接将自动与 SEQUENCE 操作中指定的会话的前向通道关联。
连接与会话的关联不是排他的。与一个会话的通道相关联的连接可以同时与其他会话的通道相关联,包括与其他客户端 ID 关联的会话。
与同一个通道相关联的多种传输类型的连接是允许的。例如,TCP 和 RDMA 连接都可以与前向通道相关联。如果 RDMA 连接和非 RDMA 连接与同一个通道相关联,那么最大插槽数量应至少比总 RDMA 信用(credits)数量多一个(第2.10.6.1节)。这样,如果使用了所有 RDMA 信用,非 RDMA 连接可以有至少一个未完成的请求。如果服务器支持多种传输类型,它必须允许客户端将每种传输的连接关联到一个通道。
允许将一种传输类型的连接与前向通道关联,将另一种传输类型的连接与反向通道关联。
每个服务器在 EXCHANGE_ID 操作的结果中以不透明字符串形式指定服务器范围值,即 eir_server_scope。服务器范围的目的是允许一组服务器向客户端指示,共享相同服务器范围值的一组服务器已经安排使用不同的不透明标识符值,以便两个服务器永远不会将相同的值分配给两个不同的对象。因此,该集合中两个服务器生成的标识符可以被认为是兼容的,以便在某些重要情况下,该集合中一个服务器生成的标识符可以呈现给同一范围内的另一个服务器。
这种兼容值的使用并不意味着由一个服务器生成的值将始终被另一个服务器接受。在大多数情况下,它不会。但是,服务器不会无意中接受另一个服务器生成的值。当它接受时,这是因为它被认为是有效的,并且具有与同一范围内的另一台服务器上相同含义的含义。
当服务器具有相同的服务器范围时,这些值的兼容性适用于以下标识符:
提供这种兼容性所需的服务器之间的协调可能非常少,仅限于 ID 空间的简单分区。对常见值的识别需要额外的实现,但可以根据需要定制以适应期望进行该识别的特定情况。
在各种情况下,客户端都会有机会比较多个服务器的服务器范围值,每种情况都将在适当的功能部分讨论:
当两个来自 EXCHANGE_ID 的回复,每个回复来自两个不同的服务器网络地址时,具有相同的服务器范围时,客户端可以通过以下几种方式验证共同的服务器范围是由两个服务器在组中合作引起的。
陈孝松注: 网上很多中文资料将trunking翻译成“中继”,但我个人认为翻译成“并联”更加准确。
并联是在客户端和服务器之间使用多个连接以提高数据传输速度的方法。NFSv4.1支持两种类型的并联: 会话并联和客户端ID并联。
在单个服务器网络地址的情况下,可以假定所有连接都在访问同一台服务器,NFSv4.1服务器必须支持并联的两种形式。当多个连接使用一组网络地址访问同一台服务器时,服务器必须支持并联的两种形式。处于集群配置的NFSv4.1服务器可以允许属于不同服务器的网络地址使用客户端ID并联。
只要客户端在不违反服务器关于允许的并联类型的规定的情况下(见下文),就可以使用任一形式的并联。关于回调通道,客户端必须允许服务器在给定客户端ID有效的所有回调通道中进行选择,并且必须在支持后通道的连接允许用于回调时支持会话或客户端ID并联。
会话并联本质上是将多个连接关联到同一会话,每个连接可能具有不同的目标和/或源网络地址。当两个连接的目标网络地址(服务器地址)相同时,服务器必须支持这种会话并联。当目标网络地址不同时,服务器可以使用由EXCHANGE_ID操作返回的数据指示此类支持(见下文)。
客户端ID并联是将多个会话关联到同一客户端ID。服务器必须在它们允许对这两个网络地址进行会话并联时,支持两个目标网络地址的客户端ID并联。此外,服务器可以通过呈现相同的主服务器所有者ID(第2.5节)和服务器范围(第2.10.4节)来允许客户端ID并联的其他情况。当两个服务器返回相同的主服务器所有者和服务器范围时,这意味着这两个服务器正在协作管理锁定状态,这是客户端ID并联的先决条件。
区分客户端何时允许使用会话和客户端ID并联需要了解EXCHANGE_ID(第18.35节)操作的结果如何标识服务器。假设客户端通过两个不同的连接发送EXCHANGE_ID,每个连接可能具有不同的目标网络地址,但每个EXCHANGE_ID操作在eia_clientowner字段中具有相同的值。如果相同的NFSv4.1服务器在每个连接上监听,那么每个EXCHANGE_ID结果必须返回eir_clientid、eir_server_owner.so_major_id和eir_server_scope的相同值。然后,客户端可以将每个连接视为引用相同的服务器(经过验证;请参见下文的第2.10.5.1节),并且可以使用每个连接来进行请求和回复的并联。客户端的选择是会话并联还是客户端ID并联。
Session Trunking(会话并联):
如果在两个不同的EXCHANGE_ID请求中,eia_clientowner参数相同,并且在两个EXCHANGE_ID结果中eir_clientid、eir_server_owner.so_major_id、eir_server_owner.so_minor_id和eir_server_scope匹配,那么客户端被允许执行会话并联。如果客户端没有到eir_clientid、eir_server_owner.so_major_id、eir_server_scope和eir_server_owner.so_minor_id元组的会话映射,那么它通过其中一个连接创建会话,将连接与会话关联。如果存在与该元组关联的会话,则客户端可以发送BIND_CONN_TO_SESSION以将连接与会话关联。
当然,如果客户端不希望使用会话并联,则不必这样做。它可以在连接上调用CREATE_SESSION。这将导致像下面描述的客户端ID并联。
Client ID Trunking(客户端ID并联):
如果在两个不同的EXCHANGE_ID请求中,eia_clientowner参数相同,并且在两个EXCHANGE_ID结果中eir_clientid、eir_server_owner.so_major_id和eir_server_scope匹配(不管eir_server_owner.so_minor_id结果是否匹配),那么客户端被允许执行客户端ID并联。客户端可以将每个连接与不同的会话关联起来,其中每个会话与同一个服务器关联。
客户端通过在每个连接上调用CREATE_SESSION,使用在eir_clientid中返回的相同客户端ID,完成客户端ID并联的操作。这些调用创建两个会话,并将每个连接与其相应的会话关联起来。客户端可以在这一点上自由选择拒绝使用客户端ID并联,简单地放弃连接。
在进行客户端ID并联时,锁定状态在与同一客户端ID相关联的多个会话之间共享。这要求服务器在多个会话之间协调状态,并要求客户端能够将相同的锁定状态与多个会话关联起来。
由于各种重新配置事件可能导致eir_server_scope和eir_server_owner值在后续针对同一网络地址的EXCHANGE_ID请求中不同。
在大多数情况下,这些重新配置事件将具有破坏性,并指示先前连接到一个服务器的IP地址现在连接到一个完全不同的服务器。
以下是客户端处理此类情况的一些建议:
当eir_server_scope发生变化时,客户端无法确保先前获取的任何ID(例如文件句柄)可以在新服务器上有效使用,即使新服务器接受它们,也无法保证这不是偶然发生的。因此,最好将所有这些状态视为丢失或过时,尽管客户端可以假设意外接受的概率很低,并将此情况视为下一种情况之内。
当eir_server_scope保持不变而eir_server_owner.so_major_id发生变化时,客户端可以使用它拥有的文件句柄,将其锁定状态视为丢失,并尝试重新获取或以其他方式重新获取其锁定。它可能会发现其文件句柄现在已经过时。然而,如果未返回NFS4ERR_STALE,则可以继续重新获取或以其他方式重新获取其打开的锁定状态。
当eir_server_scope和eir_server_owner.so_major_id保持不变时,客户端必须使用eir_server_owner.so_minor_id的当前值来决定适当的并联形式。这可能导致连接被断开或创建新会话。
当服务器使用两个不同的连接响应并声明具有匹配或部分匹配的eir_server_owner、eir_server_scope和eir_clientid值时,客户端无需信任服务器的声明。在进行流量并联之前,客户端可以通过以下方式验证这些声明:
对于会话并联,客户端应在不同网络路径之间可靠地验证是否实际上与同一NFSv4.1服务器关联并可用于同一会话,服务器必须允许客户端执行可靠验证。创建客户端ID时,客户端应指定要根据SP4_SSV或SP4_MACH_CRED(第18.35节)状态保护选项验证BIND_CONN_TO_SESSION。对于SP4_SSV,可靠验证取决于通过SET_SSV(见第18.47节)操作建立的共享秘密(SSV)。
当新连接与会话关联时(通过BIND_CONN_TO_SESSION操作,见第18.34节),如果客户端为BIND_CONN_TO_SESSION操作指定了SP4_SSV状态保护,则客户端必须使用RPCSEC_GSS保护发送BIND_CONN_TO_SESSION,使用完整性或隐私,以及使用GSS SSV机制(见第2.10.9节)创建的RPCSEC_GSS句柄。
如果客户端错误地尝试将连接关联到错误服务器的会话,服务器将拒绝尝试,因为它不知道BIND_CONN_TO_SESSION参数的会话标识符,或者将拒绝尝试,因为RPCSEC_GSS身份验证失败。即使服务器错误或恶意接受了连接关联尝试,它在响应中计算的RPCSEC_GSS验证器将不会被客户端验证,因此客户端将知道它不能使用连接进行与指定会话的并联。
如果客户端指定了SP4_MACH_CRED状态保护,则BIND_CONN_TO_SESSION操作将使用RPCSEC_GSS完整性或隐私,使用在创建客户端ID时使用的相同凭据。通过RPCSEC_GSS的双向身份验证可确保客户端与正确服务器的正确会话关联。
对于客户端ID并联,客户端至少有两种验证两个不同EXCHANGE_ID操作获取的相同客户端ID是否来自同一服务器的选项。第一种选择是在发送每个EXCHANGE_ID操作时使用RPCSEC_GSS身份验证。每次使用RPCSEC_GSS身份验证发送EXCHANGE_ID时,客户端记录GSS目标的主体名称。如果EXCHANGE_ID的结果表明客户端ID并联是可能的,并且GSS目标的主体名称相同,则服务器是相同的,允许客户端ID并联。
验证的第二种选项是使用SP4_SSV保护。当客户端发送EXCHANGE_ID时,它指定SP4_SSV保护。客户端始终必须通过CREATE_SESSION调用来确认首次发送的EXCHANGE_ID。然后,客户端发送SET_SSV。稍后,客户端将EXCHANGE_ID发送到与第一个EXCHANGE_ID发送到的目标网络地址不同的第二个目标网络地址。客户端检查每个EXCHANGE_ID回复是否具有相同的eir_clientid、eir_server_owner.so_major_id和eir_server_scope。如果是这样,客户端通过使用由第二个EXCHANGE_ID返回的RPCSEC_GSS句柄保护的RPCSEC_GSS完整性向第二个目标地址发送CREATE_SESSION操作来验证声明。如果服务器接受CREATE_SESSION请求,并且客户端验证RPCSEC_GSS验证程序和完整性代码,则客户端有证据表明第二个服务器知道SSV,因此这两个服务器正在合作以指定服务器范围和客户端ID并联。
通过会话,NFSv4.1为在通道上传输的请求提供了精确一次语义(EOS)。EOS在前通道和后通道上都受支持。
每个带有前导SEQUENCE或CB_SEQUENCE操作的COMPOUND或CB_COMPOUND请求必须由接收方执行一次。无论请求是否使用指定的回复缓存(参见第2.10.6.1.3节),都必须满足此要求。即使请求方正在通过在pNFS数据客户端和pNFS数据服务器之间创建的会话发送请求,此要求仍然有效。为了理解此要求的基本原理,将请求分为三类:
不可变请求的示例是 RENAME。显然,如果响应者执行相同的 RENAME 请求两次,并且第一次执行成功,那么重新执行将失败。如果响应者返回重新执行的结果,这个结果是不正确的。因此,对于不可变请求,需要使用 EOS。
幂等修改请求的示例是包含 WRITE 操作的 COMPOUND 请求。重复执行相同的 WRITE 具有与执行该 WRITE 一次相同的效果。然而,强制对 WRITE 和其他幂等修改请求使用 EOS 是必要的,以避免数据损坏。
假设客户端向一个不符合规范、不执行 EOS 的服务器发送 WRITE A,并且由于网络分区等原因未收到响应。客户端重新连接到服务器并重新发送 WRITE A。现在,服务器有两个未完成的 A。服务器可能处于这样一种情况,即它执行并回复 A 的重试,而第一个 A 仍在服务器的内部 I/O 系统中等待某个资源。在接收到 WRITE A 的第二次尝试的回复时,客户端认为其 WRITE 已完成,因此可以自由地发送 WRITE B,这与 A 的字节范围重叠。当原始的 A 从服务器的 I/O 系统中调度并执行时(因此第二次 A 将被写入),B 写入的内容可能会被覆盖,从而导致数据损坏。
幂等非修改请求的示例是包含 SEQUENCE、PUTFH、READLINK 操作且没有其他操作的 COMPOUND。重新执行这样的请求不会导致数据损坏或产生不正确的结果。尽管如此,为了保持实现的简单性,响应者必须对所有请求(无论是否幂等且非修改)强制使用 EOS。
请注意,除非服务器将回复缓存持久保存在稳定存储中,并且除非服务器以某种方式实现为永不需要重启(实际上,如果存在这样的服务器,持久保存在稳定存储中的回复缓存与不是如此的回复缓存之间的区别是没有意义的)。有关在回复缓存中持久保存的讨论,请参见第 2.10.6.5 节。不管怎样,即使服务器不将回复缓存持久保存,EOS 也比 NFS 的先前版本改进了鲁棒性和正确性,因为旧的重复请求/回复缓存是基于 ONC RPC 事务标识符(XID)的。第 2.10.6.1 节解释了将 XID 用作回复缓存基础的不足之处,并描述了 NFSv4.1 会话如何改进 XID。
todo: 2.10.6.1. Slot Identifiers and Reply Cache