Linux内核中路径查找如何感知inode的并发变更?
路径查找中chmod如何通知lookup操作inode已变更?
Linux内核中路径名查找支持RCU或REF两种模式。相关文档提到:
No
inode->i_rwsemor evenrename_lock<...>. If some other thread does take `i_rwsem` and modifies the directory in a way that RCU-walk needs to notice, the result will be either that RCU-walk fails to find the dentry that it is looking for, or it will find a dentry which `read_seqretry()` won't validate. In either case it will drop down to REF-walk mode which can take whatever locks are needed.
从chmod的核心实现代码来看:
int chmod_common(const struct path *path, umode_t mode){ ... inode_lock(inode); error = security_path_chmod(path, mode); if (error) goto out_unlock; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; error = notify_change(mnt_idmap(path->mnt), path->dentry, &newattrs, &delegated_inode); out_unlock: inode_unlock(inode); ... }
chmod会通过inode_{lock|unlock}获取inode->i_rwsem。现在的疑问是:当一个线程执行chmod操作,另一个线程以RCU模式执行lookup(假设dentry已缓存),路径查找需要让dentry失效从而回退到REF模式,但chmod仅调用了fsnotify_dentry,并未从dcache中失效或移除dentry——那chmod究竟是怎么通知lookup操作inode已经变更的?
核心原理:依赖seqcount的版本校验而非dentry失效
chmod不需要主动失效dentry,而是通过**inode的seqcount(序列计数器)**实现RCU路径查找的自动降级,具体流程如下:
- RCU查找时记录版本:当lookup以RCU模式遍历dcache时,会先通过
read_seqbegin()记录目标inode的i_sequence值。 - chmod触发版本递增:chmod调用
notify_change()后,最终会进入inode_setattr()更新inode属性,这个过程中会调用inode_inc_iversion()(或直接操作i_sequence),让inode的序列计数器加1。 - RCU查找后校验版本:找到dentry后,RCU模式会调用
read_seqretry()对比之前记录的i_sequence和当前值:- 若两者不一致,说明inode在查找过程中被修改过,RCU查找直接失败,自动降级到REF模式;
- REF模式会获取
inode->i_rwsem锁,确保能看到最新的inode状态。
为什么不需要失效dentry?
RCU路径查找的设计逻辑是**“允许看到旧的dentry,但必须验证关联inode的一致性”**。dentry本身只是路径到inode的映射,chmod修改的是inode的属性而非映射关系,所以不需要从dcache中移除dentry。只要inode的seqcount发生变化,RCU查找的校验步骤就会发现不一致,从而切换到安全的REF模式。
内容的提问来源于stack exchange,提问作者k1r1t0
相关产品推荐
相关产品推荐

