3. dentry数据结构:struct dentry的定义、关键字段、dentry状态(DCACHE_*标志)

dentry(目录项)是VFS层中用于路径名解析的核心数据结构。它不直接代表磁盘上的文件,而是代表路径名与inode之间的内存映射关系。理解struct dentry的布局、关键字段以及状态标志,是进行dentry缓存调优的前提。

3.1 struct dentry 核心定义

在Linux内核源码 include/linux/dcache.h 中,struct dentry 的定义如下(精简关键字段):

struct dentry {
    /* 引用计数与锁 */
    unsigned int d_flags;           /* DCACHE_* 状态标志位 */
    seqcount_spinlock_t d_seq;      /* 用于RCU查找的序列锁 */
    spinlock_t d_lock;              /* 保护dentry字段的自旋锁 */

    /* 路径名相关 */
    struct qstr d_name;             /* 目录项名称(hash+len+name指针) */

    /* 树形结构链接 */
    struct dentry *d_parent;        /* 父目录项 */
    struct list_head d_child;       /* 父目录的d_subdirs链表节点 */
    struct list_head d_subdirs;     /* 子目录项链表头 */

    /* 与inode的关联 */
    struct inode *d_inode;          /* 指向关联的inode(NULL表示负dentry) */

    /* 哈希表与LRU */
    struct hlist_bl_node d_hash;    /* 用于dentry哈希表 */
    struct list_head d_lru;         /* LRU链表节点(未使用且可回收) */

    /* 文件系统操作 */
    const struct dentry_operations *d_op; /* 文件系统特定的dentry操作 */

    /* 超级块与别名 */
    struct super_block *d_sb;       /* 所属超级块 */
    union {
        struct list_head d_alias;   /* 与inode关联的别名链表 */
    } __d_alias;
};
关键设计思想: dentry是纯内存对象,不直接对应磁盘结构。它通过 d_inode 指针与inode关联,通过 d_parent 和 d_subdirs 构建路径树。这种设计使得路径名解析可以完全在内存中完成,避免重复的磁盘I/O。

3.2 关键字段详解

字段 类型 作用与调优意义
d_flags unsigned int 存储DCACHE_*状态标志,决定dentry是否有效、是否被删除、是否在LRU中。
d_name struct qstr 包含文件名哈希值(hash)、长度(len)和名称指针(name)。哈希值用于快速查找。
d_parent struct dentry * 指向父目录项。根目录的d_parent指向自身。
d_inode struct inode * 核心关联指针。NULL表示负dentry(路径存在但文件不存在);非NULL表示正dentry。
d_lru struct list_head LRU链表节点。当dentry引用计数降为0且未被pin时,加入LRU等待回收。这是缓存调优的直接操作对象。
d_op const struct dentry_operations * 文件系统自定义操作(如d_hash、d_compare、d_delete)。影响缓存行为。
调优关注点: d_inode 和 d_lru 是缓存调优的核心。正dentry越多,缓存命中率越高;LRU链表长度决定了可回收的dentry数量,直接影响内存压力。

3.3 dentry状态:DCACHE_* 标志

d_flags 字段使用位掩码表示dentry的当前状态。以下是关键的DCACHE_*标志:

标志 值 含义 对缓存的影响
DCACHE_DISCONNECTED 0x0001 dentry未连接到全局dentry树(如根目录挂载点) 不可被路径查找命中,通常临时存在
DCACHE_REFERENCED 0x0002 最近被访问过(用于LRU二次机会算法) 防止被立即回收,延长缓存寿命
DCACHE_LRU_LIST 0x0004 dentry当前在全局LRU链表上 可被内存回收扫描到
DCACHE_DENTRY_KILLED 0x0008 dentry已被标记为死亡,即将释放 不再参与任何缓存操作
DCACHE_MISS_TYPE 0x0010 查找时未命中(负dentry) 缓存“文件不存在”的结果,减少重复查找
DCACHE_NFSFS_RENAMED 0x0020 NFS文件系统重命名专用标志 影响NFS缓存一致性
DCACHE_COOKIE 0x0040 用于dcache cookie机制 调试与统计用
DCACHE_FSNOTIFY_PARENT_WATCHED 0x0080 父目录被文件系统通知监控 影响inotify/fanotify性能
DCACHE_DENTRY_CURSOR 0x0100 用于遍历目录时的临时游标 不参与常规缓存
DCACHE_NORCU 0x0200 禁止RCU方式访问该dentry 降低并发查找性能
状态转换陷阱: 一个dentry可以同时设置多个标志。例如,一个正dentry被访问后会同时设置 DCACHE_REFERENCED 和 DCACHE_LRU_LIST。当它被删除时,会先设置 DCACHE_DENTRY_KILLED,然后从LRU移除。调优时需注意标志的组合状态,避免误判。

3.4 dentry状态机与生命周期

dentry的生命周期由状态标志驱动,从创建到回收经历多个阶段。下图展示了核心状态转换:

dentry 生命周期状态机 创建 (d_alloc) 正dentry (d_inode != NULL) 负dentry (d_inode == NULL) LRU链表 (DCACHE_LRU_LIST) 回收释放 (d_free) d_inode 赋值 d_inode = NULL 引用计数归零 引用计数归零 内存回收或超时 路径查找命中 说明: DCACHE_REFERENCED 标志在LRU扫描时提供二次机会;DCACHE_DENTRY_KILLED 在回收前设置,防止并发访问。 负dentry同样占用内存,大量负dentry可能导致缓存膨胀,需通过调优参数控制。

3.5 正dentry与负dentry的缓存策略差异

  • 正dentry(Positive Dentry): d_inode 指向有效的inode。缓存命中后可直接获取inode,完全避免磁盘I/O。是缓存调优的主要目标。
  • 负dentry(Negative Dentry): d_inode 为NULL。缓存“文件或目录不存在”的查找结果。虽然不能直接提供数据,但避免了重复的磁盘查找(如多次访问不存在的路径)。
调优权衡: 负dentry在防止“查无此文件”的I/O风暴时非常有用,但过多负dentry会浪费内存。内核通过 dentry_negative_limit 参数(或全局内存压力)控制其数量。在文件频繁创建/删除的场景(如临时目录),负dentry的快速回收尤为重要。

3.6 dentry操作表:dentry_operations

d_op 字段指向文件系统自定义的操作函数,直接影响缓存行为:

操作 函数原型 对缓存的影响
d_hash int (*d_hash)(const struct dentry *, struct qstr *) 自定义哈希函数,影响dentry在哈希表中的分布,间接影响查找性能
d_compare int (*d_compare)(const struct dentry *, unsigned int, const char *, const struct qstr *) 自定义名称比较函数(如大小写不敏感文件系统),影响缓存命中逻辑
d_delete int (*d_delete)(const struct dentry *) 决定dentry是否可被缓存。返回1表示立即删除,返回0表示可缓存
d_release void (*d_release)(struct dentry *) dentry释放前的清理回调,用于释放文件系统私有数据
d_prune void (*d_prune)(struct dentry *) 当dentry从缓存中剪除时调用,用于维护文件系统内部状态
实战案例: 在NFS文件系统中,d_delete 通常返回1(不缓存),因为NFS需要保证缓存一致性。而在ext4中,d_delete 返回0,允许dentry被长期缓存。调优时需检查文件系统的 d_op 实现,确认缓存策略是否与业务负载匹配。

3.7 本章小结

  • struct dentry 是VFS路径名解析的内存缓存单元,通过 d_inode 关联磁盘文件。
  • 关键字段 d_flags、d_name、d_parent、d_lru 决定了dentry的查找、链接和回收行为。
  • DCACHE_* 标志(如 DCACHE_REFERENCED、DCACHE_LRU_LIST、DCACHE_MISS_TYPE)精确控制dentry的缓存状态。
  • 正dentry和负dentry有不同的缓存价值,调优时需要平衡内存占用与I/O减少效果。
  • 文件系统通过 dentry_operations 自定义缓存策略,影响全局调优效果。