Linux内核-文件系统之目录项高速缓存(dentry cache)简介

本文介绍了Linux内核中的目录项高速缓存(dentry cache)及其工作原理,包括dentry对象的状态管理、数据结构、分配与释放接口,以及与inode的关系。dentry cache通过哈希链表、LRU链表和别名链表等数据结构进行高效管理,确保快速查找和释放目录项。此外,文章还详细讲解了dentry的生命周期、分配与释放函数,以及VFS操作接口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

每个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),它主要由两个数据结构组成:

哈希链表dentry_hashtable:dcache中的所有dentry对象都通过d_hash指针域链到相应的dentry哈希链表中。

未使用的dentry对象链表dentry_unused:dcache中所有处于“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 */
};

1.1 分配接口

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

Dentry本身是一个树形结构,d_alloc和d_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;
            /*
               将所分配的dentry对象的d_parent指针设置为指向自身。
               NOTE!这一点是判断一个dentry对象是否是一个fs的根目录的唯一准则
               (include/linux/dcache.h):#define IS_ROOT(x)((x)==(x)->d_parent)
             */
            res->d_parent = res;
            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);
}

1.2 释放接口

目录项缓存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对象总数(

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值