1.客户端处理程序
这篇文章中我们讲讲文件锁的加锁过程,首先说说与文件锁相关的数据结构
struct nfs4_lock_state {
// nfs4_state结构中包含多个nfs4_lock_state结构,这些结构构成了一个链表,
// ls_locks指向链表中相邻的元素.
struct list_head ls_locks; /* Other lock stateids */
// 这个nfs4_lock_state结构所属的nfs4_state结构
struct nfs4_state * ls_state; /* Pointer to open state */
// nfs4_lock_state已经初始化完毕了.
#define NFS_LOCK_INITIALIZED 1
int ls_flags;
// 这个结构保证文件锁操作按顺序进行.
struct nfs_seqid_counter ls_seqid;
nfs4_stateid ls_stateid; // 这是服务器返回来的stateid.
atomic_t ls_count; // 这个数据结构的计数.
struct nfs4_lock_owner ls_owner; // 这是这个nfs4_lock_state的名称.
};
这个数据结构跟LOCK操作相关,Linux中文件锁跟进程有关,不同进程之间的文件锁不能发生冲突,同一个进程可以对文件加多个锁。nfs4_lock_state记录了一个进程中加的所有文件锁的信息。如果用户在同一个进程中调用LOCK多文件加了多个锁,那么每次LOCK结果后都会更新这个数据结构中的值,最主要的是这个数据结构中记录了一个stateid,服务器可以根据这个stateid检查用户对文件的访问权限。
上一遍文章中讲过,当客户端创建文件锁时会调用nfs4_proc_setlk(),这个函数最终调用了_nfs4_do_setlk(),这个函数也很简单,就是创建了一个RPC任务,根据参数信息填充了RPC请求报文,然后向服务器发起了LOCK请求。所以就不讲解这个函数的处理流程了,我们对比RFC的规定,Linux是如何填充LOCK请求报文的。
static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args, struct compound_hdr *hdr)
{
__be32 *p;
encode_op_hdr(xdr, OP_LOCK, decode_lock_maxsz, hdr); // 这是LOCK请求编号, 12
p = reserve_space(xdr, 28);
// 这是文件锁类型 4字节
*p++ = cpu_to_be32(nfs4_lock_type(args->fl, args->block));
// 是否是reclaim文件锁,当服务器重启后客户端需要重新获取文件锁信息,称为reclaim. 4字节
*p++ = cpu_to_be32(args->reclaim);
// 这是文件锁在文件中的偏移位置 8字节
p = xdr_encode_hyper(p, args->fl->fl_start);
// 这是文件锁长度 8字节
p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
*p = cpu_to_be32(args->new_lock_owner); // 1 4字节
// 如果这是进程中第一个文件锁
if (args->new_lock_owner){
// 这是OPEN操作的seqid编号
encode_nfs4_seqid(xdr, args->open_seqid); // 这是open --> lock --> unlock -->close 这个过程中的编号
// 这是OPEN操作中的stateid
encode_nfs4_stateid(xdr, args->open_stateid); // 文件的stateid.
// 这是LOCK操作中的seqid编号
encode_nfs4_seqid(xdr, args->lock_seqid);
// 这相当于是为这个nfs4_lock_state起的名称
encode_lockowner(xdr, &args->lock_owner); // owner
}
else { // 如果不是进程中第一个文件锁
// 首先编码上次文件锁操作返回的stateid
encode