免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2630 | 回复: 4
打印 上一主题 下一主题

谁对文件锁熟悉一些啊?求教一下。 [复制链接]

论坛徽章:
4
戌狗
日期:2013-08-15 18:22:43技术图书徽章
日期:2013-08-21 13:48:45巨蟹座
日期:2013-09-26 17:06:39处女座
日期:2013-12-25 11:26:10
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-08-21 14:58 |只看该作者 |倒序浏览
我的版本是2.4.32。相关代码附加在最后边.



inode上的三种锁FL_FLOCK,F_LEASE,FL_POSIX:

1)FL_FLOCK,由sys_flock ->flock_lock_file实现,我有两个问题:
   
    a)同一个file,可否反复对一个inode加FL_FLOCK?
   
        假设兄弟进程A, B, C分别使用files_structA, files_structB, files_structC。
        其中,files_structA->fd[a]==files_structB->fd[ b]==files_structC->fd[c]==file,既3个进程共享file。
        那么,3个进程分别sys_flock(fd, LOCK_EX),于是,inode上对应于同一file,出现了3个FL_FLOCK,而且均为LOCK_EX。
     
        这种情况可否发生?
        从代码中看,我认为是可以发生的。但是这种情况既然发生,何来LOCK_EX及LOCK_SH这种区别?



    b)是否用户不恰当的使用sys_flock时,完全可能导致进程挂掉,睡眠后再也无法唤醒?而kernel并不纠正这种错误?

         假设当前进程的files_struct中,fd[a]及fd[ b]分别对应fileA及fileB,而fileA及fileB对应同一inode。
         当前进程首先sys_flock(fd[a], LOCK_EX),返回后,再sys_flock(fd[ b ], LOCK_SH)。
         kernel未检验这种情况,而是直接产生死锁。是否这样?


2)FL_LEASE,由sys_fcntl(fd, F_SETLEASE, F_WRLCK/F_RDLCK)来设置,而sys_fcntl调用fcntl_setlease来实现。

         fcntl_setlease中,在lock_kernel中,进行了一些必要的检测后,会从slab分配file_lock结构,并且标志为GFP_KERNEL,由此可能进入睡眠,并且unlock_kernel。
        在分配file_lock结构成功后,fcntl_setlease不再进行任何检测,而是直接将file_lock结构链入FL_LEASE锁的链中。

        我非常非常想不通为什么是GFP_KERNEL标志,而不是GFP_ATOMIC;或者在lock_kernel之前就分配好file_lock结构。一旦进入睡眠,以前在lock_kernel中所做的一切检测又有何意义?
         而以前的检测又比较重要,当检测时的状态发生变化,条件已不满足时,还要将file_lock挂入FL_LEASE链,我觉得会产生很多很多诡异的错误。




3)FL_POSIX, 由sys_fcntl(fd, F_SETLKW, flock )来设置,而sys_fcntl调用fcntl_setlk来实现。
  
  fcntl_setlk对所有的FL_POSIX锁,先按照( pid,files_struct)排序,这样FL_POSIX锁的链会分成几截;在每截的内部,又按照每个FL_POSIX锁所锁住的区间在文件中的偏移地址大小进行排序。我们假设如下例子:
第一截: 60 ~ 70,    100~120,    200~250
第二截: 1000~1500,2000~2500
第三截: 150~180,   400~500
这种情况完全可能。

在sys_read或者sys_write时,调用rw_verify_area,检验要读写的区间是否被FL_POSIX锁住。

但是rw_verify_area的逻辑非常奇怪,比如说要验证150~180是否被锁住,rw_verify_area会丛第一截的第一区间开始验证,第一截的前两个区间60 ~ 70,100~120都不与150~180冲突,于是开始验证第一截的第三个区间200~250,发现第三个区间是200~250,落在了目的区间150~180后边。于是rw_verify_area就返回,并且认为FL_POSIX链的所有截都不与150~180冲突。完全不顾后边第三截锁住了150~180。

怎么会有这样的逻辑?

[ 本帖最后由 塑料袋 于 2007-8-21 15:01 编辑 ]

论坛徽章:
4
戌狗
日期:2013-08-15 18:22:43技术图书徽章
日期:2013-08-21 13:48:45巨蟹座
日期:2013-09-26 17:06:39处女座
日期:2013-12-25 11:26:10
2 [报告]
发表于 2007-08-21 15:03 |只看该作者
先贴一个fcntl_setlease的代码吧,这个我最搞不明白。



int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
{
        struct file_lock *fl, **before, **my_before = NULL;
        struct dentry *dentry;
        struct inode *inode;
        int error, rdlease_count = 0, wrlease_count = 0;

        dentry = filp->f_dentry;
        inode = dentry->d_inode;

        if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))
                return -EACCES;
        if (!S_ISREG(inode->i_mode))
                return -EINVAL;

        lock_kernel();

        time_out_leases(inode);

        /*
         * FIXME: What about F_RDLCK and files open for writing?
         */
        error = -EAGAIN;
        if ((arg == F_WRLCK)
            && ((atomic_read(&dentry->d_count) > 1)
                || (atomic_read(&inode->i_count) > 1)))
                goto out_unlock;

        /*
         * At this point, we know that if there is an exclusive
         * lease on this file, then we hold it on this filp
         * (otherwise our open of this file would have blocked).
         * And if we are trying to acquire an exclusive lease,
         * then the file is not open by anyone (including us)
         * except for this filp.
         */

        for (before = &inode->i_flock;
                        ((fl = *before) != NULL) && (fl->fl_flags & FL_LEASE);
                        before = &fl->fl_next) {
                if (fl->fl_file == filp)
                        my_before = before;

                else if (fl->fl_type == (F_INPROGRESS | F_UNLCK))
                        /*
                         * Someone is in the process of opening this
                         * file for writing so we may not take an
                         * exclusive lease on it.
                         */
                        wrlease_count++;
                else
                        rdlease_count++;
        }

        if ((arg == F_RDLCK && (wrlease_count > 0)) ||
            (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0)))
                goto out_unlock;

        if (my_before != NULL) {
                error = lease_modify(my_before, arg);
                goto out_unlock;
        }

        error = 0;
        if (arg == F_UNLCK)
                goto out_unlock;


        error = -EINVAL;
        if (!leases_enable)
                goto out_unlock;
       
        error = lease_alloc(filp, arg, &fl);
        if (error)
                goto out_unlock;

        error = fasync_helper(fd, filp, 1, &fl->fl_fasync);
        if (error < 0) {
                locks_free_lock(fl);
                goto out_unlock;
        }
        fl->fl_next = *before;
        *before = fl;
        list_add(&fl->fl_link, &file_lock_list);

       
        filp->f_owner.pid = current->pid;
        filp->f_owner.uid = current->uid;
        filp->f_owner.euid = current->euid;
out_unlock:
        unlock_kernel();
        return error;
}

论坛徽章:
4
戌狗
日期:2013-08-15 18:22:43技术图书徽章
日期:2013-08-21 13:48:45巨蟹座
日期:2013-09-26 17:06:39处女座
日期:2013-12-25 11:26:10
3 [报告]
发表于 2007-08-21 15:15 |只看该作者
lock_kernel中,做了几个判断
1)
     if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))
                return -EACCES;
        if (!S_ISREG(inode->i_mode))
                return -EINVAL;
  这个没什么说的


2)  if ((arg == F_WRLCK)
            && ((atomic_read(&dentry->d_count) > 1)
                || (atomic_read(&inode->i_count) > 1)))
                goto out_unlock;

这个判断有用么?只能保证在unlock_kernel之前,无其他file对本inode添加FL_LEASE而已,保证不了别的。
open_namei不需要lock_kernel,dentry->d_count和inode->i_count随时可能改变,inode随时都能被再次打开。
并且随后的rdlease_count及wrlease_count也统计了lock_kernel中,有无其他file添加的FL_LEASE,与这个判断重复。



3)  for (before = &inode->i_flock;
                        ((fl = *before) != NULL) && (fl->fl_flags & FL_LEASE);
                        before = &fl->fl_next) {
                if (fl->fl_file == filp)
                        my_before = before;

                else if (fl->fl_type == (F_INPROGRESS | F_UNLCK))
                        /*
                         * Someone is in the process of opening this
                         * file for writing so we may not take an
                         * exclusive lease on it.
                         */
                        wrlease_count++;
                else
                        rdlease_count++;
        }

这里before记录了file是否已经设置了FL_LEASE,如果file已经使用了FL_LEASE,则file将不能再次添加一个新的FL_LEASE,而只能修改原有的FL_LEASE。
但是,这是假设一直lock_kernel的话。




做完这三个判断后,函数中出现这样几句

     error = lease_alloc(filp, arg, &fl);
        if (error)
                goto out_unlock;

        error = fasync_helper(fd, filp, 1, &fl->fl_fasync);

其中,lease_alloc及fasync_helper都可能导致睡眠,unlock_kernel

论坛徽章:
0
4 [报告]
发表于 2007-08-22 10:09 |只看该作者
if ((arg == F_WRLCK)
            && ((atomic_read(&dentry->d_count) > 1)
                || (atomic_read(&inode->i_count) > 1)))
                goto out_unlock;

这个判断有用么?

how about dentry represents libc6.so?
/* linux-2.6.20.7/fs/dcache.c
*
* Notes on the allocation strategy:
*
* The dcache is a master of the icache - whenever a dcache entry
* exists, the inode will always exist. "iput()" is done either when
* the dcache entry is deleted or garbage collected.
*/

[ 本帖最后由 sisi8408 于 2007-8-22 10:57 编辑 ]

论坛徽章:
4
戌狗
日期:2013-08-15 18:22:43技术图书徽章
日期:2013-08-21 13:48:45巨蟹座
日期:2013-09-26 17:06:39处女座
日期:2013-12-25 11:26:10
5 [报告]
发表于 2007-08-22 11:45 |只看该作者
libc6.so是什么?

if ((arg == F_WRLCK)
            && ((atomic_read(&dentry->d_count) > 1)
                || (atomic_read(&inode->i_count) > 1)))
                goto out_unlock;

这个语句的本意,是用户只能通过唯一的file来访问到这个inode。
因既无其他file结构引用dentry,也无其他dentry引用inode。保证了file -> dentry -> inode之间对应关系是一对一,非一对多或多对多。

但是这个判断似乎无用,namei中查找dentry,并增加d_count根本不用lock_kernel。
而且fcntl_setlease曾发生睡眠,睡眠时无任何手段保证仍然d_count == 1  &&  i_count == 1
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP