NFS中的文件锁

原创 2013年03月09日 15:26:16

    文件锁是保持文件同步的一种手段,当多个用户同时操作同一个文件时,文件锁可以保证数据不发生冲突。NFSv2和NFSv3依靠NLM协议实现文件锁,NFSv4本身实现了文件锁,不需要NLM协同工作了。NFS中的文件锁既可以加在客户端,也可以加在服务器端。如果客户端挂载NFS文件系统时使用了选项nolock,表示在客户端加锁。这种情况下可以保证同一个客户端的多个进程访问同一个文件的过程不发生冲突,但是不同客户端访问同一个文件时还可能发生冲突,因为文件锁加在了客户端,其他客户端不知道这个文件锁的存在。如果客户端挂载NFS文件系统时使用了选项lock,表示在服务器端加锁,这样所有的客户端都可以检查服务器端是否存在文件锁,因此所有客户端访问同一个文件时都不会发生冲突。客户端加锁时和其他文件系统的加锁过程没有什么区别,因此我们只讲解服务器端加锁的情况。

1.NFS中文件锁操作

NFSV4中,服务器端锁处理函数的入口点是nfs4_proc_lock(),这个函数处理了NFSv4中所有关于文件锁的操作,函数代码如下:

参数filp:这是一个文件对象指针,表示对哪个文件进行锁处理

参数cmd:这是文件锁操作的方法,取值为:F_GETLK、F_SETLK、F_SETLKW

参数request:这里包含了文件锁信息

static int
nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
{
        struct nfs_open_context *ctx;
        struct nfs4_state *state;
        unsigned long timeout = NFS4_LOCK_MINTIMEOUT;
        int status;

        /* verify open state */
        // ctx是打开文件时设置的数据结构,其中包含了nfs4_state指针.
        ctx = nfs_file_open_context(filp);      // return filp->private_data
        state = ctx->state;     // 取出nfs4_state结构

        // 检查文件锁的起始位置和结束位置是否非法
        if (request->fl_start < 0 || request->fl_end < 0)
                return -EINVAL;

        // 文件锁包含三种操作:F_GETLK、F_SETLK、F_SETLKW
        if (IS_GETLK(cmd)) {            // 查询文件锁的信息
                if (state != NULL)
                        return nfs4_proc_getlk(state, F_GETLK, request);
                return 0;
        }
        // 检查操作类型是否合法
        if (!(IS_SETLK(cmd) || IS_SETLKW(cmd)))
                return -EINVAL;

        if (request->fl_type == F_UNLCK) {      // 这是解锁操作
                if (state != NULL)
                        return nfs4_proc_unlck(state, cmd, request);    // 删除文件锁
                return 0;
        }

        if (state == NULL)
                return -ENOLCK;
        /*
         * Don't rely on the VFS having checked the file open mode,
         * since it won't do this for flock() locks.
         */
        // 检查是否有权限创建文件锁
        switch (request->fl_type) {
        case F_RDLCK:           // 创建一个读锁
                if (!(filp->f_mode & FMODE_READ))       // 只有读打开的情况下才能创建读锁
                        return -EBADF;
                break;
        case F_WRLCK:           // 创建一个写锁
                if (!(filp->f_mode & FMODE_WRITE))      // 只有写打开的情况下才能创建写锁
                        return -EBADF;
        }
        do {
                status = nfs4_proc_setlk(state, cmd, request);  // 创建一个文件锁
                if ((status != -EAGAIN) || IS_SETLK(cmd))
                        break;
                timeout = nfs4_set_lock_task_retry(timeout);
                status = -ERESTARTSYS;
                if (signalled())
                        break;
        } while(status < 0);
        return status;
}


Linux定义了三种文件锁操作方法:

F_GETLK:查询指定文件锁的信息,参数request中包含了待查找文件锁的信息

F_SETLK:设置文件锁,包括加锁和解锁两种操作,参数request中包含了锁信息。加锁过程中如果和其他的文件锁发生了冲突,则直接出错退出。

F_SETLKW:设置文件锁,包括加锁和解锁两种操作,参数request中包含了锁信息。加锁过程中如果和其他的文件锁发生了冲突,则一直等待直到加锁成功为止。


2.文件锁相关的请求

NFSv4中有四个与文件锁相关的请求,分别是:

LOCK:给文件加锁,nfs4_proc_setlk()会发起这个请求

LOCKT:查询文件锁的信息,nfs4_proc_getlk()会发起这个请求。

LOCKU:解锁,nfs4_proc_unlck()会发起这个请求。

RELEASE_LOCKOWNER:释放文件锁所有者,nfs4_proc_unlck()会发起这个请求。


2.1LOCK请求报文和应答报文结构

LOCK操作也分为几种情况,下面先说说最常见的情况:创建一个新的文件锁。这种情况下LOCK请求报文应该包含下列数据:

     struct LOCK4args {
             /* CURRENT_FH: file */
             nfs_lock_type4  locktype;
             bool            reclaim;
             offset4         offset;
             length4         length;
             locker4         locker;
     };

locktype表示文件锁类型,取值如下:

    READ_LT:创建一个读锁,如果与其他的文件锁发生了冲突,则马上退出。

    WRITE_LT:创建一个写锁,如果与其他的文件锁发生了冲突,则马上退出。

    READW_LT:创建一个读锁,如果与其他的文件锁发生了冲突,则等待,直到成功加锁。

    WRITEW_LK:创建一个写锁,如果与其他的文件锁发生了冲突,则等待,直到成功加锁。

reclaim:这是锁状态回复标志位。如果服务器宕机重启了,这种情况下客户端需要恢复以前申请的文件锁,这时LOCK请求报文中的reclaim设置为1,其他情况下这个值为0。

offset:这是文件锁锁定的数据段在文件中的起始偏移量。

length:这是文件锁锁定的数据端的长度。

locker:这是标识本次LOCK操作的数据结构,如果是第一次加锁,这个数据结构如下:

     struct open_to_lock_owner4 {
             seqid4          open_seqid;
             stateid4        open_stateid;
             seqid4          lock_seqid;
             lock_owner4     lock_owner;
     };
    open_seqid:加锁前需要先打开文件,因此需要先执行OPEN操作,这是OPEN操作中的seqid顺序号。

    open_stateid:这是OPEN操作中返回的stateid。

    lock_seqid:这是为LOCK操作准备的顺序号

    lock_owner:相当于是LOCK操作的名称,包含下列信息:

   struct lock_owner4 {
           clientid4       clientid;
           opaque          owner<NFS4_OPAQUE_LIMIT>;
   };
    clientid:这是客户端的clientid。

    owner:这是一个字符串,客户端随便定义,但是需要保证能够唯一确定文件锁的所有者。

如果加锁成功,LOCK应答报文中包含下列数据:

     struct LOCK4resok {
             stateid4        lock_stateid;
     };

应答报文很简单,只包含了为这个文件锁生成的stateid。

如果与文件中其他的文件锁发生了冲突,加锁失败了,LOCK应答报文包含下列数据:

     struct LOCK4denied {
             offset4         offset;
             length4         length;
             nfs_lock_type4  locktype;
             lock_owner4     owner;
     };
这个数据结构中包含了与我们冲突的文件锁的信息。

    offset:冲突的文件锁在文件中的偏移量。

    length:冲突的文件锁的长度。

    locktye:冲突的文件锁的长度。

    owner:冲突的文件锁的名称。

2.2LOCKT请求报文和应答报文结构

LOCKT请求报文包含下列数据:

     struct LOCKT4args {
             /* CURRENT_FH: file */
             nfs_lock_type4  locktype;
             offset4         offset;
             length4         length;
             lock_owner4     owner;
     };
    locktype:文件锁类型,取值如下:READ_LT、WRITE_LK、READW_LT、WRITEW_LK。

    offset:这是文件锁锁定的数据段在文件中的起始偏移量。

    length:这是文件锁锁定的数据端的长度。

    owner:相当于是LOCKT操作的名称。

如锁没有文件锁跟我们测试的文件锁发生冲突,LOCKT应答报文只返回错误码:NFS_OK。

如果文件中有文件锁跟我们测试的文件锁发生了冲突,则返回发生冲突的文件锁的信息,应答报文如下:

     struct LOCK4denied {
             offset4         offset;
             length4         length;
             nfs_lock_type4  locktype;
             lock_owner4     owner;
     };

2.3LOCKU请求报文和应答报文结构

LOCKU请求报文包含了用户请求删除的文件锁的信息,数据如下:

     struct LOCKU4args {
             /* CURRENT_FH: file */
             nfs_lock_type4  locktype;
             seqid4          seqid;
             stateid4        stateid;
             offset4         offset;
             length4         length;
     };
如果服务器正确删除了这个文件锁,则返回stateid。否则,什么都不返回。

2.4RELEASE_LOCKOWNER请求报文和应答报文结构

RELEASE_LOCKOWNER请求报文包含下列数据:

     struct RELEASE_LOCKOWNER4args {
             lock_owner4     lock_owner;
     };

RELEASE_LOCKOWNER应答报文只包含服务器返回的错误码。


相关文章推荐

NFS 服务器配置说明

NFS 服务器配置说明 测试环境OS:CentOS5.5 一、NFS 简介 NFS是Network File System的简写(网络文件系统).   NFS允许一个系统在网络上与他人共享...

linux配置nfs步骤及心得

这节我们介绍NFS的相关概念,以及如何配置NFS和在客户端中查看NFS。   NFS的配置过程很简单。在服务器端中编辑/etc/exports文件,添加如下内容:     /home/nf...

文件锁与NFS文件锁

原文:http://www.cnblogs.com/zhenjing/archive/2011/07/04/filelock.html 缘起 因项目需要,自行设计一套通用的文件读写锁,...

NFS客户端mount挂载优化

NFS客户端mount挂载优化 NFS作用 NFS服务可以让不同的客户端挂载使用同一个上目录,作为共享存储使用,这样可以保证不同节点的客户端数据的一致性,在集群环境中经常用到 NFS的优点...

目标板挂载NFS时 需要nolock参数的网摘

nfs方式共享主机文件 作者:qtopia2009-7-3 10:00:00一.   检查nfs状态:#service nfs status二.   在主机创建nfs共享文件夹:#mkdir /nfs...

关于mount nfs时-o nolock的问题

需要将在linux里交叉编译好的程序放在arm上运行,所以首先要将程序copy至arm上,选择了nfs。        但在arm上mount nfs的时候遇到了失败的情况:        在...
  • alex_xhl
  • alex_xhl
  • 2012年01月31日 17:04
  • 11074

关于mount nfs时-o nolock的问题

需要将在linux里交叉编译好的程序放在arm上运行,所以首先要将程序copy至arm上,选择了nfs。        但在arm上mount nfs的时候遇到了失败的情况:        在...

oracle数据库使用nfs数据文件异常时加锁的删除

以前曾经遇到过这个问题,当时解决后没有记录下来, 结果今天又遇到了. 同事调整网络,结果数据库机器无法访问NAS,导致许多数据库异常, 重新启动后, 也提示一些文件被别人使用. 实际上与NFS的锁...

NFS各个版本之间的比较

NFS是一种网络文件系统,从1985年推出至今,共发布了3个版本:NFSv2、NFSv3、NFSv4,NFSv4包含两个次版本NFSv4.0和NFSv4.1。经过20多年发展,NFS发生了非常大的变化...
  • ycnian
  • ycnian
  • 2013年01月17日 23:11
  • 21871

文件锁 flock及fcntl flock

原文地址:http://blog.chinaunix.net/uid-24774106-id-3488649.html  提到了flock,不提fcntl这个锁有点不想话,毕竟fcn...
  • Mr_MuMu
  • Mr_MuMu
  • 2016年03月08日 17:24
  • 594
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:NFS中的文件锁
举报原因:
原因补充:

(最多只允许输入30个字)