美文网首页
Linux Lock - flock and fcntl

Linux Lock - flock and fcntl

作者: 帆子_8c3a | 来源:发表于2019-08-20 16:28 被阅读0次

FD vs OFD

  • FD (File Descriptor) :在进程内打开一个文件,返回一个FD,用户态的概念。
  • OFD(Open File Descriptor) :第一次打开文件时候,在内核创建一个OFD。如果不同进程打开同一个文件,不同的fd会对应同一个内核态的open fd。


    image.png
  1. 调用dup(),dup2(), or fcntl()会导致同一个进程的不同fd指向同一个内核态中的open fd。
  2. 调用folk()会导致不同进程的fd,对应同一个内核态open fd。
  3. 如果不是上述两种情况,进程1和进程2打开同一个文件,会在内核态中有两个open fd。

flock API (语意来自BSD,早期Linux不支持)

flock提供了文件粒度的的lock,以下是操作方式:

  1. LOCK_SH : shared lock
  2. LOCK_EX : exclusive lock
  3. LOCK_UN : unlock
  4. LOCK_NB : nonblocking lock,可以用|操作符和前两个联合使用

需要注意的:
flock的owner是内核态open fd,而不是用户态fd,也不是inode。所以dup(),dup2(), or fcntl(),or folk()调用后,虽然返回不同的fd,但本质还是同一个内核open fd。假设进程1的fd3和进程2的fd4指向同一个内核open fd,对fd3加EX锁后,fd4依然可以获得EX锁。
例子1:
下面的fd和newfd对应同一个内核open fd,所以代表同一个owner。

flock(fd, LOCK_EX);               /* Gain lock via 'fd' */
newfd = dup(fd);                  /* 'newfd' refers to same lock as 'fd' */
flock(newfd, LOCK_UN);            /* Frees lock acquired via 'fd' */

例子2:
虽然打开同一个文件,但对应两个不同内核open fd,所以fd1和fd2对应不同的owner。

fd1 = open("a.txt", O_RDWR);
fd2 = open("a.txt", O_RDWR);
flock(fd1, LOCK_EX);
flock(fd2, LOCK_EX);             /* Locked out by lock on 'fd1' */

例子3:
子进程把父进程获得的lock关掉了。

flock(fd, LOCK_EX);              /* Parent obtains lock */
if (fork() == 0)                 /* If child... */    
    flock(fd, LOCK_UN);          /* Release lock shared with parent */

flock command

linux提供了这个命令,本质是调用了flock API。
一般是通过它创建排他锁,来保证某进程是系统内唯一的。

flock -xn /tmp/test.lock -c '/bin/sh /tmp/test.sh'

fcntl API (POSIX语意的lock)

  • fcntl提供了字节范围粒度的lock,又称为record lock
  • 使用fcntl需要提供fd,cmd和flock结构体。
  • fcntl的owner是进程,不是fd,也不是inode
fcntl(fd, cmd, &flock); 

The flock structure

struct flock {    
    short l_type;      /* Lock type: F_RDLCK, F_WRLCK, F_UNLCK */    
    short l_whence;    /* How to interpret 'l_start': SEEK_SET, SEEK_CUR, SEEK_END */    
    off_t l_start;     /* Offset where the lock begins */    
    off_t l_len;       /* Number of bytes to lock; 0 means "until EOF" */    
    pid_t l_pid;       /* Process preventing our lock (F_GETLK only) */
};

cmd

  1. F_SETLK : accquire nonblock lock ,如果被lock立刻返回EACCES or EAGAIN
  2. F_SETLKW : accquire blocking lock
  3. F_GETLK : check lock

内核中的实现

flock和fcntl在内核中都用struct file_lock实现。其主要差别就在于owner的不同。如果lock的owner相同,conflict的检测就会跳过,即相同owner的lock可以递归申请。

flock在内核中的实现

flock转换成struct file_lock

static struct file_lock *
flock_make_lock(struct file *filp, unsigned int cmd)
{
    struct file_lock *fl;
      //...
    fl->fl_file = filp;
    fl->fl_owner = filp; 
    fl->fl_flags = FL_FLOCK;
      //... 
    return fl;
}

判断lock是否来自同一个owner

static int flock_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
{
    /* FLOCK locks referring to the same filp do not conflict with
     * each other.
     */
//对于flock来说,内核态中的open fd相同owner即相同
    if (caller_fl->fl_file == sys_fl->fl_file)
        return (0);
//...
}

fcntl在内核中的实现

fcntl转换成struct file_lock

static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl,
                 struct flock64 *l)
{
      //...
//对于posix lock来说,进程相同,owner即相同
    fl->fl_owner = current->files; //
    fl->fl_file = filp;
    fl->fl_flags = FL_POSIX;
      //...
    return assign_type(fl, l->l_type);
}

判断lock是否来自同一个owner

static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2)
{
//...
    return fl1->fl_owner == fl2->fl_owner;
}

Advisory Lock vs Mandatory Lock

Linux对Mandatory Lock支持不好,很多文件系统不支持。例如

int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
{
//...
    /*
     * The NFSv4 protocol doesn't support LOCK_MAND, which is not part of
     * any standard. In principle we might be able to support LOCK_MAND
     * on NFSv2/3 since NLMv3/4 support DOS share modes, but for now the
     * NFS code is not set up for it.
     */
    if (fl->fl_type & LOCK_MAND)
        return -EINVAL;
//...
}

参考

  1. The Linux Programming Interface中的Chapter 4和Chapter 55
  2. Advanced Programming in the UNIX® Environment, Third Edition中的Chapter 14.3

相关文章

  • Linux Lock - flock and fcntl

    FD vs OFD FD (File Descriptor) :在进程内打开一个文件,返回一个FD,用户态的概念。...

  • 2020-08-31 Python中给文件加锁解锁

    fcntl模块:flock() : flock(f, operation)operation : 包括:fcntl...

  • NFS Client in Linux Kernel - Loc

    1. System Call flock fcntl 2. 内核中的Lock 分为两种lock,但在内核中统一成f...

  • flock v.s. fcntl

    共同点 都支持阻塞和非阻塞模式 只能操作于文件,而不是目录 当进程结束或者终止的时候,锁都会被自动释放 flock...

  • PHP flock()文件锁定函数

    flock 参数 LOCK_SH取得共享锁定(读取的程序) LOCK_EX 取得独占锁定(写入的程序) LOCK_...

  • Linux文件锁-flock

    背景:在使用crontab管理定时脚本时,如果设定的脚本执行时间间隔较短,例如5分钟执行一次,正常情况下,脚本执行...

  • linux下fcntl的使用

    本文根据众多互联网博客内容整理后形成,引用内容的版权归原始作者所有,仅限于学习研究使用,不得用于任何商业用途。 功...

  • nfs-ganesha - Lock

    Lock Owner Lock owner是Linux Kernel Client分配的大小20Byte,表示ow...

  • Linux的文件锁flock

    今天看腾讯云服务器的脚本时,发现在root用户的crontab定时任务里面有个函数flock。在每五分钟执行脚...

  • linux c文件锁flock

    1.源码实现 2.编译源码 3.运行及其结果

网友评论

      本文标题:Linux Lock - flock and fcntl

      本文链接:https://www.haomeiwen.com/subject/orspsctx.html