免费注册 查看新帖 |

Chinaunix

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

[内核同步] file,dentry,inode 释放时都要rcu释放? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-04-27 18:49 |只看该作者 |倒序浏览
struct file {
        union {
                struct list_head        fu_list;  //node of super_block->s_files list
                struct rcu_head         fu_rcuhead;
        } f_u;
}

struct dentry {
        union {
                struct list_head d_child;        //child node of parent list(dentry->d_subdirs)
                 struct rcu_head d_rcu;
        } d_u;
}

struct inode {
        union {
                struct list_head        i_dentry;   //list of alias dentries(dentry->d_alias)
                struct rcu_head                i_rcu;
        };
}

file,dentry,inode释放时都通过rcu释放的。
比如:
static inline void file_free(struct file *f)
{
        percpu_counter_dec(&nr_files);
        file_check_state(f);
        call_rcu(&f->f_u.fu_rcuhead, file_free_rcu);
}

file_free_rcu将会把filp释放到slab。

为什么要延迟释放呢,难道有其他地方还在引用filp,但是我实在想不出来有哪些情况还会用到它啊。

还请高手解释下。




论坛徽章:
0
2 [报告]
发表于 2012-04-28 09:54 |只看该作者
为什么发帖都没人理呢?
好多贴都是十层大海了,伤心了。

论坛徽章:
0
3 [报告]
发表于 2012-04-28 11:57 |只看该作者
RCU是一种无锁机制。

就拿flip来说,肯定是可以共享的啊。多线程可以拥有同一个文件表吧,父进程,子进程有时也可以共享。
那么释放的时候是用RCU可以避免锁的使用

论坛徽章:
0
4 [报告]
发表于 2012-04-28 14:34 |只看该作者
本帖最后由 blake326 于 2012-04-28 14:36 编辑

回复 3# GFree_Wind


   void fput(struct file *file)
{
        if (atomic_long_dec_and_test(&file->f_count))
                __fput(file);
}
static void __fput(struct file *file)
{
        file_free(file);
}
static inline void file_free_rcu(struct rcu_head *head)
{
        struct file *f = container_of(head, struct file, f_u.fu_rcuhead);

        put_cred(f->f_cred);
        kmem_cache_free(filp_cachep, f);
}

static inline void file_free(struct file *f)
{
        percpu_counter_dec(&nr_files);
        file_check_state(f);
        call_rcu(&f->f_u.fu_rcuhead, file_free_rcu);
}

一般一个内核路径打开一个file初始化f_count=1,close的时候f_count=0,然后释放,这个时候管它什么共享的子进程,父进程的时候,f_count=0,了,大家都不用它了,谁还会访问它.这个时候直接释放到slab cache有何不可呢?


并且,我也没有看出file变量是rcu变量,因为本身修改file的某个属性时,并没有先去拷贝它然后再修改什么的。

论坛徽章:
0
5 [报告]
发表于 2012-04-28 15:07 |只看该作者
难道是为了归避有人在fput(file)之后,还继续使用file这个野指针,导致莫名其妙的错误或者oops?

论坛徽章:
0
6 [报告]
发表于 2012-04-28 15:22 |只看该作者
这个改动大概是2.6.14加进来的。

同struct files_struct ->        struct fdtable __rcu *fdt 的改动一起过来的。
http://git.kernel.org/?p=linux/k ... 30f09cce577b03f43ef

大概理解了一下:
1. 首先打开了一个tempfile文件。f_count=1
2. 然后打开x个文件。
3. 内核路径A  通过rcu 读取了fdt结构,遍历其所有file结构体,并且很磨蹭需要持续一段时间。。。
4. 又打开y个文件,fdt需要expand_fdtable,rcu设置了新的fdt指针(所有旧的file指针被拷贝到新的fdt中了)。(旧的fdt通过call_rcu延迟释放)
5. 通过新的fdt指针,close tempfile,f_count=0,释放file!!!! 此时内核路径A仍然在访问该file,所以此时必须rcu延迟释放。
6. 内核路径A,终于磨蹭结束了。
7. 等待时机最终rcu释放file。

看来我对rcu的理解还是很差啊。

论坛徽章:
0
7 [报告]
发表于 2012-06-04 17:18 |只看该作者
回复 6# blake326

大概理解了一下:
1. 首先打开了一个tempfile文件。f_count=1
2. 然后打开x个文件。
3. 内核路径A  通过rcu 读取了fdt结构,遍历其所有file结构体,并且很磨蹭需要持续一段时间。。。
4. 又打开y个文件,fdt需要expand_fdtable,rcu设置了新的fdt指针(所有旧的file指针被拷贝到新的fdt中了)。(旧的fdt通过call_rcu延迟释放)
5. 通过新的fdt指针,close tempfile,f_count=0,释放file!!!! 此时内核路径A仍然在访问该file,所以此时必须rcu延迟释放。
6. 内核路径A,终于磨蹭结束了。
7. 等待时机最终rcu释放file。




看来我对rcu的理解还是很差啊。



理解不差啊。延迟释放就是担心别的 cpu还在读访问被释放对象。所以必须等别的所有cpu都经历一次进程切换确保完成读临界区的工作(因为读完后才能抢占使能)才能释放。
   

论坛徽章:
0
8 [报告]
发表于 2012-06-04 18:29 |只看该作者
VFS有一种搜索叫RCU_LOOKUP, 相对于传统的ref-walk模式路径搜索,它的特点就是路径搜寻的时候不需要边跑边加引用计数,而是用rcu机制加seq lock... 到了最后一刻,如果世界还是那个世界(依赖于seq),才加上计数, 结束。。。

所以在还没有拿到对象的引用计数之前,依靠的是RCU机制。拿到之后就是ref-count机制控制生命期了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP