NFS协议端到端实例解析之文件锁流程
NFS文件系统也实现了对文件锁的支持,关于文件锁的原理和用法请参考本号之前的文章,本文不再赘述。本文主要介绍一下NFS中文件锁的代码实现。
对于内核实现的NFS,在NFSv3及之前的版本中,文件锁相关的特性在客户端有个独立的内核模块,NFSv4及之后的版本则直接集成在文件系统当中。服务端的文件锁相关的功能与其它特性在一起,都在nfsd目录中。
本节以NFSv3对应的文件锁协议为例介绍一下内核代码是如何实现文件锁的。文件锁的实现与NFS的读写等操作类似,其主要原理是将客户端的请求透传到服务端。由于NFSv3协议中文件没有状态,因此在服务端需要一个专门的锁服务来记录这些状态。
1客户端逻辑
客户端的逻辑与本地文件系统没有本质的区别,首先要经过VFS,VFS会调用具体文件系统的锁接口。从API到VFS的调用流程如下所示:
其中vfs_lock_file函数的具体实现如下所示。可以看出,这里主要是调用一个函数指针,对于NFS而言就是nfs_lock函数。
然后我们看一下nfs_lock的代码实现,可以看出对于加锁和解锁会走不同的分支,分别是do_getlk和do_unlk函数。
以加锁为例,在NFSv3中会调用nfs3_proc_lock函数,主流程如下所示。
可以看出,这里最终调用的nlmclnt_call函数,该函数会构造RPC调用必要的参数,然后调用RPC库的API将请求通过网络发送到服务端。
2服务端流程
锁服务的主要作用就是记录文件的加锁情况。在NFSv3中,每个文件的加锁情况通过nlm_block数据结构来记录。同时为了记录文件系统中所有文件的加锁情况,在锁服务中有一个全局变量(nlm_blocked)来记录所有的nlm_block信息。
当有来自客户端的加锁请求时,RPC服务端会将请求解析为服务端注册的加锁接口,整个调用流程如下所示。
锁服务通过从nlm_blocked查找来确定该文件是否已经被某个客户端加锁了。最终,在锁服务中调用VFS的vfs_lock_file函数来完成加锁的操作,这与本地文件系统加锁就没有什么差异了。如下是nlm_blocked函数的核心代码。
至此,再往下就与本地文件系统加锁的流程一致了,大家可以阅读本号之前的文章。
3整体流程总结
最后,我们将从客户端发起锁文件的调用开始,到经过VFS,NFS后到服务端的流程统一的展示在下图中。大家可以按照该流程理解相关代码。
由于篇幅有限,本文不可能涉及函数的所有细节,主要是展示了主线流程。关于代码的其它实现细节,大家可以自行阅读Linux内核的相关代码。
文章后期可能会进行错误更正和内容更新,关注我们更方便了解内容变化。