背景
io_uring
作者在 What’s new with io_uring (2022) 中提了一句打开文件优化:LOOKUP_CACHED support for opening files. 没听过这个 LOOKUP_CACHED
特性,看着像是缓存相关,简单了解一下。
代码
光是看代码是一头雾水的。
定义如下:
#define LOOKUP_CACHED 0x200000 /* Only do cached lookup */
调用如下:
/**
* try_to_unlazy - try to switch to ref-walk mode.
* @nd: nameidata pathwalk data
* Returns: true on success, false on failure
*
* try_to_unlazy attempts to legitimize the current nd->path and nd->root
* for ref-walk mode.
* Must be called from rcu-walk context.
* Nothing should touch nameidata between try_to_unlazy() failure and
* terminate_walk().
*/
static bool try_to_unlazy(struct nameidata *nd)
{
struct dentry *parent = nd->path.dentry;
BUG_ON(!(nd->flags & LOOKUP_RCU));
if (unlikely(!legitimize_links(nd))) // 这里⭐
goto out1;
if (unlikely(!legitimize_path(nd, &nd->path, nd->seq)))
goto out;
if (unlikely(!legitimize_root(nd)))
goto out;
leave_rcu(nd);
BUG_ON(nd->inode != parent->d_inode);
return true;
out1:
nd->path.mnt = NULL;
nd->path.dentry = NULL;
out:
leave_rcu(nd);
return false;
}
static bool legitimize_links(struct nameidata *nd)
{
int i;
if (unlikely(nd->flags & LOOKUP_CACHED)) { // 这里⭐
drop_links(nd);
nd->depth = 0;
return false;
}
for (i = 0; i < nd->depth; i++) {
struct saved *last = nd->stack + i;
if (unlikely(!legitimize_path(nd, &last->link, last->seq))) {
drop_links(nd);
nd->depth = i + 1;
return false;
}
}
return true;
}
这里看着像是 RCU-walk 切换到 REF-walk 的路径,为什么这么做?
注释
顺着网线找到了 fs: Support for LOOKUP_CACHED / RESOLVE_CACHED,里面提到:
io_uring always punts opens to async context, since there’s no control over whether the lookup blocks or not. Add LOOKUP_CACHED to support just doing the fast RCU based lookups, which we know will not block. If we can do a cached path resolution of the filename, then we don’t have to always punt lookups for a worker.
也就是说作者认为 RCU-walk 是不阻塞的,所以 lookup flags 里面加上 LOOKUP_CACHED
可以指定打开文件时只使用 RCU-walk 间接达成目的。估计是为了让 io_uring
支持内联的 open()
操作,不必为了一些不确定性而动用线程(worker)做异步 IO 处理。