linux dentry cache

Linux dentry cache学习

每个dentry对象都属于下列几种状态之一:

 

(1)未使用(unused)状态:该dentry对象的引用计数d_count的值为0,但其d_inode指针仍然指向相关的的索引节点。该目录项仍然包含有效的信息,只是当前没有人引用他。这种dentry对象在回收内存时可能会被释放。

 

(2)正在使用(inuse)状态:处于该状态下的dentry对象的引用计数d_count大于0,且其d_inode指向相关的inode对象。这种dentry对象不能被释放。

 

3)负(negative)状态:与目录项相关的inode对象不复存在(相应的磁盘索引节点可能已经被删除),dentry对象的d_inode指针为NULL。但这种dentry对象仍然保存在dcache中,以便后续对同一文件名的查找能够快速完成。这种dentry对象在回收内存时将首先被释放。

 

Linux为了提高目录项对象的处理效率,设计与实现了目录项高速缓存(dentry cache,简称dcache),它主要由两个数据结构组成:

1. 哈希链表dentry_hashtabledcache中的所有dentry对象都通过d_hash指针域链到相应的dentry哈希链表中。

 

2. 未使用的dentry对象链表dentry_unuseddcache中所有处于“unused”状态和“negative”状态的dentry对象都通过其d_lru指针域链入dentry_unused链表中。该链表也称为LRU链表。

 

目录项高速缓存dcache是索引节点缓存icache的主控器(master),也即dcache中的dentry对象控制着icache中的inode对象的生命期转换。无论何时,只要一个目录项对象存在于dcache中(非 negative状态),则相应的inode就将总是存在,因为inode的引用计数i_count总是大于0。当dcache中的一个dentry被释放时,针对相应inode对象的iput()方法就会被调用。

struct dentry {

       atomic_t d_count;

       unsigned int d_flags;             /* protected by d_lock */

       spinlock_t d_lock;         /* per dentry lock */

       struct inode *d_inode;           /* Where the name belongs to - NULL is * negative */

       /*

        * The next three fields are touched by __d_lookup.  Place them here

        * so they all fit in a cache line.

        */

       struct hlist_node d_hash;       /* lookup hash list */

       struct dentry *d_parent; /* parent directory */

       struct qstr d_name;//contain the name,length,hash value of this dentry

 

       struct list_head d_lru;           /* LRU list */

       /*

        * d_child and d_rcu can share memory

        */

       union {

              struct list_head d_child; /* child of parent list */

             struct rcu_head d_rcu;

       } d_u;

       struct list_head d_subdirs;     /* our children ,all the children are linked together*/

       struct list_head d_alias;  /* inode alias list ,list of all the dentry share the same inode*/

       unsigned long d_time;           /* used by d_revalidate */

       struct dentry_operations *d_op;

       struct super_block *d_sb;      /* The root of the dentry tree */

       void *d_fsdata;                    /* fs-specific data */

#ifdef CONFIG_PROFILING

       struct dcookie_struct *d_cookie; /* cookie, if any */

#endif

       int d_mounted;

       unsigned char d_iname[DNAME_INLINE_LEN_MIN];     /* small names */

};

11 分配接口

dcachekmem_cache_alloc()的基础上定义两个高层分配接口:d_alloc()函数和d_alloc_root()函数,用来从dentry_cache slab分配器缓存中为一般的目录项和根目录分配一个dentry对象。

Dentry本身是一个树形结构,d_allocd_alloc_root用于build这棵树:

struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)

函数d_alloc_root()用来为fs的根目录(并不一定是系统全局文件系统的根“/”)分配dentry对象。它以根目录的inode对象指针为参数,如下所示:

struct dentry * d_alloc_root(struct inode * root_inode)

{

       struct dentry *res = NULL;

 

       if (root_inode) {

              static const struct qstr name = { .name = "/", .len = 1 };

 

              res = d_alloc(NULL, &name);

              if (res) {

                     res->d_sb = root_inode->i_sb;

                     res->d_parent = res;//将所分配的dentry对象的d_parent指针设置为指向自身。NOTE!这一点是判断一个dentry对象是否是一个fs的根目录的唯一准则(includelinuxdcache.h):#define IS_ROOTx)((x)==(x)->d_parent

                     d_instantiate(res, root_inode);

              }

       }

       return res;

}

 

函数d_instantiate用于向dentry结构中填写inode信息,因此该函数会将一个dentry对象从negative状态转变为inuse状态。如下所示:

void d_instantiate(struct dentry *entry, struct inode * inode) {

spin_lock(&dcache_lock);

if (inode)

list_add(&entry->d_alias, &inode->i_dentry);

entry->d_inode = inode;

spin_unlock(&dcache_lock);

}

NOTE! 函数d_instantiate()假定在被调用之前,调用者已经增加了inode的引用计数。

 

struct dentry *d_alloc_name(struct dentry *parent, const char *name)

{

       struct qstr q;

 

       q.name = name;

       q.len = strlen(name);

       q.hash = full_name_hash(q.name, q.len);

       return d_alloc(parent, &q);

}

 

12 释放接口

目录项缓存dcache定义了两个高层释放接口:d_free()函数和 dentry_iput()函数。其中,d_free函数用来将dcache中不使用的dentry对象释放回dentry_cache slab分配器缓存;而dentry_iput()函数则用来释放一个dentry对象对一个inode对象的引用关联。

函数d_free()首先调用dentry对象操作方法中的d_release ()函数(如果定义了的话),通常在d_release()函数中释放dentry->fsdata数据。然后,用dname_external ()函数判断是否已经为目录项名字d_name分配了内存,如果是,则调用kfree()函数释放d_name所占用的内存。接下来,调用 kmem_cache_free()函数释放这个dentry对象。最后,修改dcache统计信息中的dentry对象总数(减1)。其源码如下:

D_free__d_free主要用于Dentry内存释放
/*

 * no dcache_lock, please.  The caller must decrement dentry_stat.nr_dentry

 * inside dcache_lock.

 */

static void d_free(struct dentry *dentry)

{

       if (dentry->d_op && dentry->d_op->d_release)

              dentry->d_op->d_release(dentry);//主要用于释放dentry->fsdata数据

       /* if dentry was never inserted into hash, immediate free is OK */

       if (hlist_unhashed(&dentry->d_hash))

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值