跳到主要内容

6. 附录 II: Lock Manager 协议

6.0 附录 II: Lock Manager 协议

由于 NFS version 2 协议和 NFS version 3 协议都是无状态的, 因此需要一个额外的 Network Lock Manager (NLM, 网络锁管理器) 协议来支持对 NFS 挂载文件的加锁. 与 NFS version 2 协议一起使用的 NLM version 3 协议记录在 [X/OpenNFS] 中.

NFS version 3 协议中的一些变化要求一个新的 NLM 协议版本. 这个新协议是 NLM version 4 协议. 下表总结 NFS 协议版本和 NLM 协议版本之间的对应关系.

NFS and NLM protocol compatibility

+---------+---------+
| NFS | NLM |
| Version | Version |
+===================+
| 2 | 1,3 |
+---------+---------+
| 3 | 4 |
+---------+---------+

本附录只讨论 NLM version 3 协议和 NLM version 4 协议之间的差异. 与 NFS version 3 协议一样, NLM version 4 协议中几乎所有名称都已更改为包含版本号. 本附录不讨论仅由名称变化构成的变更.

6.1 RPC 信息

6.1.1 认证

NLM 服务在 NULL 过程中使用 AUTH_NONE. 所有其他过程使用 AUTH_UNIX、AUTH_SHORT、AUTH_DES 和 AUTH_KERB. 将来可能支持其他认证类型.

6.1.2 常量

这些是调用 NLM 服务所需的 RPC 常量, 以十进制给出.

PROGRAM    100021
VERSION 4

6.1.3 传输地址

NLM 服务通常支持 TCP 和 UDP 协议. 应查询 rpcbind 守护进程以获得正确的传输地址.

6.1.4 基本数据类型

uint64
typedef unsigned hyper uint64;

int64
typedef hyper int64;

uint32
typedef unsigned long uint32;

int32
typedef long int32;

这些类型是 NLM version 4 协议新增的. 它们与 NFS version 3 协议中的类型相同.

nlm4_stats

enum nlm4_stats {
NLM4_GRANTED = 0,
NLM4_DENIED = 1,
NLM4_DENIED_NOLOCKS = 2,
NLM4_BLOCKED = 3,
NLM4_DENIED_GRACE_PERIOD = 4,
NLM4_DEADLCK = 5,
NLM4_ROFS = 6,
NLM4_STALE_FH = 7,
NLM4_FBIG = 8,
NLM4_FAILED = 9
};

Nlm4_stats 表示调用成功或失败. 此版本包含若干新的错误码, 因而客户端可以向应用提供更精确的失败信息.

NLM4_GRANTED
调用成功完成.

NLM4_DENIED
调用失败. 对于设置锁的尝试, 此状态表示如果客户端稍后重试该调用, 可能会成功.

NLM4_DENIED_NOLOCKS
调用失败, 因为服务器无法分配必要资源.

NLM4_BLOCKED
表示阻塞请求无法立即授予. 当锁被授予时, 服务器会向客户端发出 NLMPROC4_GRANTED 回调.

NLM4_DENIED_GRACE_PERIOD
调用失败, 因为服务器正在重启后重新建立旧锁, 尚未准备好恢复正常服务.

NLM4_DEADLCK
请求无法授予, 且阻塞会导致死锁.

NLM4_ROFS
调用失败, 因为远程文件系统是只读的. 例如, 某些服务器实现可能不支持只读文件系统上的排他锁.

NLM4_STALE_FH
调用失败, 因为它使用了无效文件句柄. 如果文件已被移除, 或服务器已撤销对该文件的访问权, 可能出现这种情况.

NLM4_FBIG
调用失败, 因为它指定的长度或偏移超出服务器支持的范围.

NLM4_FAILED
调用因未在前面列出的某种原因失败. 客户端应将此状态视为不要重试请求的强烈提示.

nlm4_holder

struct nlm4_holder {
bool exclusive;
int32 svid;
netobj oh;
uint64 l_offset;
uint64 l_len;
};

此结构表示锁的持有者. exclusive 字段说明持有者拥有排他锁还是共享锁. svid 字段标识持有锁的进程. oh 字段是一个不透明对象, 标识持有锁的主机或进程. l_len 和 l_offset 字段标识被锁定的区域. NLM version 3 协议和 NLM version 4 协议之间的唯一区别是, 在 NLM version 3 协议中 l_len 和 l_offset 字段为 32 位宽, 而在 NLM version 4 协议中为 64 位宽.

nlm4_lock

struct nlm4_lock {
string caller_name<LM_MAXSTRLEN>;
netobj fh;
netobj oh;
int32 svid;
uint64 l_offset;
uint64 l_len;
};

此结构描述一个锁请求. caller_name 字段标识发出请求的主机. fh 字段标识要加锁的文件. oh 字段是不透明对象, 标识发出请求的主机或进程, svid 字段标识发出请求的进程. l_offset 和 l_len 字段标识锁控制的文件区域. l_len 为 0 表示 "到文件结尾".

此结构在 NLM version 3 协议和 NLM version 4 协议版本之间有两个差异. 第一, 在 NLM version 3 协议中, 长度和偏移为 32 位宽, 而在 NLM version 4 协议中为 64 位宽. 第二, 在 NLM version 3 协议中, 文件句柄是固定长度的 NFS version 2 协议文件句柄, 编码为一个字节计数后跟一个字节数组. 在 NFS version 3 协议中, 文件句柄已经是可变长度, 因此会直接复制到 fh 字段. 也就是说, fh 字段的前四个字节与 NFS version 3 协议 nfs_fh3 中的字节计数相同. fh 字段其余部分包含来自 NFS version 3 协议 nfs_fh3 的字节数组.

nlm4_share

struct nlm4_share {
string caller_name<LM_MAXSTRLEN>;
netobj fh;
netobj oh;
fsh4_mode mode;
fsh4_access access;
};

此结构用于支持 DOS 文件共享. caller_name 字段标识发出请求的主机. fh 字段标识要操作的文件. oh 字段是不透明对象, 标识发出请求的主机或进程. mode 和 access 字段指定文件共享和访问模式. fh 的编码是一个字节计数, 后跟文件句柄字节数组. 更多细节见 nlm4_lock 的说明.

6.2 NLM 过程

NLM version 4 协议中的过程在语义上与 NLM version 3 协议中的过程相同. 唯一的语义差异是新增了一个 NULL 过程, 可用于测试服务器响应能力. 带 _MSG 和 _RES 后缀的过程名称表示异步消息; 对这些过程而言, void 响应意味着没有回复. 语法上的变化是过程被重命名, 以避免与 nlm4_stats 的值发生名称冲突. 因此过程定义如下.

version NLM4_VERS {
void
NLMPROC4_NULL(void) = 0;

nlm4_testres
NLMPROC4_TEST(nlm4_testargs) = 1;

nlm4_res
NLMPROC4_LOCK(nlm4_lockargs) = 2;

nlm4_res
NLMPROC4_CANCEL(nlm4_cancargs) = 3;

nlm4_res
NLMPROC4_UNLOCK(nlm4_unlockargs) = 4;

nlm4_res
NLMPROC4_GRANTED(nlm4_testargs) = 5;

void
NLMPROC4_TEST_MSG(nlm4_testargs) = 6;

void
NLMPROC4_LOCK_MSG(nlm4_lockargs) = 7;

void
NLMPROC4_CANCEL_MSG(nlm4_cancargs) = 8;

void
NLMPROC4_UNLOCK_MSG(nlm4_unlockargs) = 9;

void
NLMPROC4_GRANTED_MSG(nlm4_testargs) = 10;

void
NLMPROC4_TEST_RES(nlm4_testres) = 11;

void
NLMPROC4_LOCK_RES(nlm4_res) = 12;

void
NLMPROC4_CANCEL_RES(nlm4_res) = 13;

void
NLMPROC4_UNLOCK_RES(nlm4_res) = 14;

void
NLMPROC4_GRANTED_RES(nlm4_res) = 15;

nlm4_shareres
NLMPROC4_SHARE(nlm4_shareargs) = 20;

nlm4_shareres
NLMPROC4_UNSHARE(nlm4_shareargs) = 21;

nlm4_res
NLMPROC4_NM_LOCK(nlm4_lockargs) = 22;

void
NLMPROC4_FREE_ALL(nlm4_notify) = 23;

} = 4;

6.2.0 过程 0: NULL - 不执行任何操作

SYNOPSIS

void NLMPROC4_NULL(void) = 0;

DESCRIPTION

NULL 过程不执行任何工作. 所有 RPC 服务都提供它, 以允许测试和计时服务器响应.

IMPLEMENTATION

该过程必须完全不做任何工作, 这样才能用于测量处理服务请求的开销. 按照惯例, NULL 过程不应要求任何认证.

ERRORS

某些服务器实现可能基于安全和认证要求返回 RPC 错误.

6.3 实现问题

6.3.1 64 位偏移和长度

某些 NFS version 3 协议服务器只能支持文件偏移或长度适合 32 位或更少位数的请求. 对这些服务器而言, lock manager 也会有相同限制. 如果这样的 lock manager 收到无法处理的请求 (因为偏移或长度使用超过 32 位), 它应返回错误 NLM4_FBIG.

6.3.2 文件句柄

从 NFS version 2 协议到 NFS version 3 协议的文件句柄格式变化使 lock manager 更复杂. 首先, lock manager 需要某种方式判断 NFS version 2 协议文件句柄何时与 NFS version 3 协议文件句柄引用同一文件. (这里假定 lock manager 同时支持 NLM version 3 协议客户端和 NLM version 4 协议客户端.) 第二, 如果 lock manager 将文件句柄传入哈希函数, 该哈希函数可能需要重新调优, 以同时适用于 NFS version 3 协议文件句柄和 NFS version 2 协议文件句柄.