* [RFC PATCH 1/5] 9p: Cache negative dentries for lookup performance
2025-08-31 19:03 [RFC PATCH 0/5] 9p: Performance improvements for build workloads Remi Pommarel
@ 2025-08-31 19:03 ` Remi Pommarel
2025-08-31 19:03 ` [RFC PATCH 2/5] 9p: Introduce option for negative dentry cache retention time Remi Pommarel
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Remi Pommarel @ 2025-08-31 19:03 UTC (permalink / raw)
To: v9fs
Cc: linux-fsdevel, linux-kernel, Eric Van Hensbergen,
Latchesar Ionkov, Dominique Martinet, Christian Schoenebeck,
Remi Pommarel
Not caching negative dentries can result in poor performance for
workloads that repeatedly look up non-existent paths. Each such
lookup triggers a full 9P transaction with the server, adding
unnecessary overhead.
A typical example is source compilation, where multiple cc1 processes
are spawned and repeatedly search for the same missing header files
over and over again.
This change enables caching of negative dentries, so that lookups for
known non-existent paths do not require a full 9P transaction. The
cached negative dentries are retained for a configurable duration
(expressed in milliseconds), as specified by the ndentry_timeout
field in struct v9fs_session_info. If set to -1, negative dentries
are cached indefinitely.
This optimization reduces lookup overhead and improves performance for
workloads involving frequent access to non-existent paths.
Signed-off-by: Remi Pommarel <repk@triplefau.lt>
---
fs/9p/fid.c | 11 ++---
fs/9p/v9fs.c | 1 +
fs/9p/v9fs.h | 2 +
fs/9p/v9fs_vfs.h | 15 +++++++
fs/9p/vfs_dentry.c | 109 +++++++++++++++++++++++++++++++++++++++------
fs/9p/vfs_inode.c | 7 +--
6 files changed, 123 insertions(+), 22 deletions(-)
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index f84412290a30..76242d450aa7 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -20,7 +20,9 @@
static inline void __add_fid(struct dentry *dentry, struct p9_fid *fid)
{
- hlist_add_head(&fid->dlist, (struct hlist_head *)&dentry->d_fsdata);
+ struct v9fs_dentry *v9fs_dentry = to_v9fs_dentry(dentry);
+
+ hlist_add_head(&fid->dlist, &v9fs_dentry->head);
}
@@ -112,6 +114,7 @@ void v9fs_open_fid_add(struct inode *inode, struct p9_fid **pfid)
static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)
{
+ struct v9fs_dentry *v9fs_dentry = to_v9fs_dentry(dentry);
struct p9_fid *fid, *ret;
p9_debug(P9_DEBUG_VFS, " dentry: %pd (%p) uid %d any %d\n",
@@ -119,11 +122,9 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)
any);
ret = NULL;
/* we'll recheck under lock if there's anything to look in */
- if (dentry->d_fsdata) {
- struct hlist_head *h = (struct hlist_head *)&dentry->d_fsdata;
-
+ if (!hlist_empty(&v9fs_dentry->head)) {
spin_lock(&dentry->d_lock);
- hlist_for_each_entry(fid, h, dlist) {
+ hlist_for_each_entry(fid, &v9fs_dentry->head, dlist) {
if (any || uid_eq(fid->uid, uid)) {
ret = fid;
p9_fid_get(ret);
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 77e9c4387c1d..422bd720d165 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -171,6 +171,7 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
/* setup defaults */
v9ses->afid = ~0;
+ v9ses->ndentry_timeout = 0;
v9ses->debug = 0;
v9ses->cache = CACHE_NONE;
#ifdef CONFIG_9P_FSCACHE
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index f28bc763847a..8c5fa0f7ba71 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -88,6 +88,7 @@ enum p9_cache_bits {
* @debug: debug level
* @afid: authentication handle
* @cache: cache mode of type &p9_cache_bits
+ * @ndentry_timeout: Negative dentry lookup cache retention time in ms
* @cachetag: the tag of the cache associated with this session
* @fscache: session cookie associated with FS-Cache
* @uname: string user name to mount hierarchy as
@@ -113,6 +114,7 @@ struct v9fs_session_info {
unsigned short debug;
unsigned int afid;
unsigned int cache;
+ unsigned int ndentry_timeout;
#ifdef CONFIG_9P_FSCACHE
char *cachetag;
struct fscache_volume *fscache;
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index d3aefbec4de6..7e6e8881081c 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -28,6 +28,19 @@
/* flags for v9fs_stat2inode() & v9fs_stat2inode_dotl() */
#define V9FS_STAT2INODE_KEEP_ISIZE 1
+/**
+ * struct v9fs_dentry - v9fs specific dentry data
+ * @head: List of fid associated with this dentry
+ * @expire_time: Lookup cache expiration time for negative dentries
+ * @rcu: used by kfree_rcu to schedule clean up job
+ */
+struct v9fs_dentry {
+ struct hlist_head head;
+ u64 expire_time;
+ struct rcu_head rcu;
+};
+#define to_v9fs_dentry(d) ((struct v9fs_dentry *)((d)->d_fsdata))
+
extern struct file_system_type v9fs_fs_type;
extern const struct address_space_operations v9fs_addr_operations;
extern const struct file_operations v9fs_file_operations;
@@ -35,6 +48,8 @@ extern const struct file_operations v9fs_file_operations_dotl;
extern const struct file_operations v9fs_dir_operations;
extern const struct file_operations v9fs_dir_operations_dotl;
extern const struct dentry_operations v9fs_dentry_operations;
+extern void v9fs_dentry_refresh(struct dentry *dentry);
+extern void v9fs_dentry_fid_remove(struct dentry *dentry);
extern const struct dentry_operations v9fs_cached_dentry_operations;
extern struct kmem_cache *v9fs_inode_cache;
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c
index 04795508a795..5035b8c749e2 100644
--- a/fs/9p/vfs_dentry.c
+++ b/fs/9p/vfs_dentry.c
@@ -23,6 +23,46 @@
#include "v9fs_vfs.h"
#include "fid.h"
+/**
+ * v9fs_dentry_is_expired - Check if dentry lookup has expired
+ *
+ * This should be called to know if a negative dentry should be removed from
+ * cache.
+ *
+ * @dentry: dentry in question
+ *
+ */
+static bool v9fs_dentry_is_expired(struct dentry const *dentry)
+{
+ struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
+ struct v9fs_dentry *v9fs_dentry = to_v9fs_dentry(dentry);
+
+ if (v9ses->ndentry_timeout == -1)
+ return false;
+
+ return time_before_eq64(v9fs_dentry->expire_time, get_jiffies_64());
+}
+
+/**
+ * v9fs_dentry_refresh - Refresh dentry lookup cache timeout
+ *
+ * This should be called when a look up yields a negative entry.
+ *
+ * @dentry: dentry in question
+ *
+ */
+void v9fs_dentry_refresh(struct dentry *dentry)
+{
+ struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
+ struct v9fs_dentry *v9fs_dentry = to_v9fs_dentry(dentry);
+
+ if (v9ses->ndentry_timeout == -1)
+ return;
+
+ v9fs_dentry->expire_time = get_jiffies_64() +
+ msecs_to_jiffies(v9ses->ndentry_timeout);
+}
+
/**
* v9fs_cached_dentry_delete - called when dentry refcount equals 0
* @dentry: dentry in question
@@ -33,20 +73,15 @@ static int v9fs_cached_dentry_delete(const struct dentry *dentry)
p9_debug(P9_DEBUG_VFS, " dentry: %pd (%p)\n",
dentry, dentry);
- /* Don't cache negative dentries */
- if (d_really_is_negative(dentry))
- return 1;
- return 0;
-}
+ if (!d_really_is_negative(dentry))
+ return 0;
-/**
- * v9fs_dentry_release - called when dentry is going to be freed
- * @dentry: dentry that is being release
- *
- */
+ return v9fs_dentry_is_expired(dentry);
+}
-static void v9fs_dentry_release(struct dentry *dentry)
+static void __v9fs_dentry_fid_remove(struct dentry *dentry)
{
+ struct v9fs_dentry *v9fs_dentry = to_v9fs_dentry(dentry);
struct hlist_node *p, *n;
struct hlist_head head;
@@ -54,15 +89,57 @@ static void v9fs_dentry_release(struct dentry *dentry)
dentry, dentry);
spin_lock(&dentry->d_lock);
- hlist_move_list((struct hlist_head *)&dentry->d_fsdata, &head);
+ hlist_move_list(&v9fs_dentry->head, &head);
spin_unlock(&dentry->d_lock);
hlist_for_each_safe(p, n, &head)
p9_fid_put(hlist_entry(p, struct p9_fid, dlist));
}
+/**
+ * v9fs_dentry_fid_remove - Release all dentry's fid
+ * @dentry: dentry in question
+ *
+ */
+void v9fs_dentry_fid_remove(struct dentry *dentry)
+{
+ __v9fs_dentry_fid_remove(dentry);
+}
+
+/**
+ * v9fs_dentry_init - Initialize v9fs dentry data
+ * @dentry: dentry in question
+ *
+ */
+static int v9fs_dentry_init(struct dentry *dentry)
+{
+ struct v9fs_dentry *v9fs_dentry = kzalloc(sizeof(*v9fs_dentry),
+ GFP_KERNEL);
+
+ if (!v9fs_dentry)
+ return -ENOMEM;
+
+ INIT_HLIST_HEAD(&v9fs_dentry->head);
+ dentry->d_fsdata = (void *)v9fs_dentry;
+ return 0;
+}
+
+/**
+ * v9fs_dentry_release - called when dentry is going to be freed
+ * @dentry: dentry that is being release
+ *
+ */
+static void v9fs_dentry_release(struct dentry *dentry)
+{
+ struct v9fs_dentry *v9fs_dentry = to_v9fs_dentry(dentry);
+
+ __v9fs_dentry_fid_remove(dentry);
+ kfree_rcu(v9fs_dentry, rcu);
+}
+
static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
{
+ struct v9fs_session_info *v9ses;
struct p9_fid *fid;
struct inode *inode;
struct v9fs_inode *v9inode;
@@ -70,9 +147,11 @@ static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
if (flags & LOOKUP_RCU)
return -ECHILD;
+ v9ses = v9fs_dentry2v9ses(dentry);
+
inode = d_inode(dentry);
if (!inode)
- goto out_valid;
+ return !v9fs_dentry_is_expired(dentry);
v9inode = V9FS_I(inode);
if (v9inode->cache_validity & V9FS_INO_INVALID_ATTR) {
@@ -95,7 +174,7 @@ static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
if (retval < 0)
return retval;
}
-out_valid:
+
return 1;
}
@@ -121,12 +200,14 @@ const struct dentry_operations v9fs_cached_dentry_operations = {
.d_revalidate = v9fs_lookup_revalidate,
.d_weak_revalidate = __v9fs_lookup_revalidate,
.d_delete = v9fs_cached_dentry_delete,
+ .d_init = v9fs_dentry_init,
.d_release = v9fs_dentry_release,
.d_unalias_trylock = v9fs_dentry_unalias_trylock,
.d_unalias_unlock = v9fs_dentry_unalias_unlock,
};
const struct dentry_operations v9fs_dentry_operations = {
+ .d_init = v9fs_dentry_init,
.d_release = v9fs_dentry_release,
.d_unalias_trylock = v9fs_dentry_unalias_trylock,
.d_unalias_unlock = v9fs_dentry_unalias_unlock,
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 399d455d50d6..89eeb2b3ba43 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -549,7 +549,7 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags)
/* invalidate all fids associated with dentry */
/* NOTE: This will not include open fids */
- dentry->d_op->d_release(dentry);
+ v9fs_dentry_fid_remove(dentry);
}
return retval;
}
@@ -732,9 +732,10 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
name = dentry->d_name.name;
fid = p9_client_walk(dfid, 1, &name, 1);
p9_fid_put(dfid);
- if (fid == ERR_PTR(-ENOENT))
+ if (fid == ERR_PTR(-ENOENT)) {
inode = NULL;
- else if (IS_ERR(fid))
+ v9fs_dentry_refresh(dentry);
+ } else if (IS_ERR(fid))
inode = ERR_CAST(fid);
else if (v9ses->cache & (CACHE_META|CACHE_LOOSE))
inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
--
2.50.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [RFC PATCH 2/5] 9p: Introduce option for negative dentry cache retention time
2025-08-31 19:03 [RFC PATCH 0/5] 9p: Performance improvements for build workloads Remi Pommarel
2025-08-31 19:03 ` [RFC PATCH 1/5] 9p: Cache negative dentries for lookup performance Remi Pommarel
@ 2025-08-31 19:03 ` Remi Pommarel
2025-08-31 19:03 ` [RFC PATCH 3/5] 9p: Enable symlink caching in page cache Remi Pommarel
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Remi Pommarel @ 2025-08-31 19:03 UTC (permalink / raw)
To: v9fs
Cc: linux-fsdevel, linux-kernel, Eric Van Hensbergen,
Latchesar Ionkov, Dominique Martinet, Christian Schoenebeck,
Remi Pommarel
Add support for a new mount option in v9fs that allows users to specify
the duration for which negative dentries are retained in the cache. The
retention time can be set in milliseconds using the ndentrytmo option.
For the same consistency reasons, this option should only be used in
exclusive or read-only mount scenarios, aligning with the cache=loose
usage.
Signed-off-by: Remi Pommarel <repk@triplefau.lt>
---
fs/9p/v9fs.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 422bd720d165..7c0c2201b151 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -34,7 +34,7 @@ struct kmem_cache *v9fs_inode_cache;
enum {
/* Options that take integer arguments */
- Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid,
+ Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid, Opt_ndentrytmo,
/* String options */
Opt_uname, Opt_remotename, Opt_cache, Opt_cachetag,
/* Options that take no arguments */
@@ -52,6 +52,7 @@ static const match_table_t tokens = {
{Opt_dfltuid, "dfltuid=%u"},
{Opt_dfltgid, "dfltgid=%u"},
{Opt_afid, "afid=%u"},
+ {Opt_ndentrytmo, "ndentrytmo=%d"},
{Opt_uname, "uname=%s"},
{Opt_remotename, "aname=%s"},
{Opt_nodevmap, "nodevmap"},
@@ -110,6 +111,8 @@ int v9fs_show_options(struct seq_file *m, struct dentry *root)
from_kgid_munged(&init_user_ns, v9ses->dfltgid));
if (v9ses->afid != ~0)
seq_printf(m, ",afid=%u", v9ses->afid);
+ if (v9ses->ndentry_timeout != 0)
+ seq_printf(m, ",ndentrytmo=%d", v9ses->ndentry_timeout);
if (strcmp(v9ses->uname, V9FS_DEFUSER) != 0)
seq_printf(m, ",uname=%s", v9ses->uname);
if (strcmp(v9ses->aname, V9FS_DEFANAME) != 0)
@@ -251,6 +254,16 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
v9ses->afid = option;
}
break;
+ case Opt_ndentrytmo:
+ r = match_int(&args[0], &option);
+ if (r < 0) {
+ p9_debug(P9_DEBUG_ERROR,
+ "integer field, but no integer?\n");
+ ret = r;
+ } else {
+ v9ses->ndentry_timeout = option;
+ }
+ break;
case Opt_uname:
kfree(v9ses->uname);
v9ses->uname = match_strdup(&args[0]);
--
2.50.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [RFC PATCH 3/5] 9p: Enable symlink caching in page cache
2025-08-31 19:03 [RFC PATCH 0/5] 9p: Performance improvements for build workloads Remi Pommarel
2025-08-31 19:03 ` [RFC PATCH 1/5] 9p: Cache negative dentries for lookup performance Remi Pommarel
2025-08-31 19:03 ` [RFC PATCH 2/5] 9p: Introduce option for negative dentry cache retention time Remi Pommarel
@ 2025-08-31 19:03 ` Remi Pommarel
2025-08-31 19:03 ` [RFC PATCH 4/5] wait: Introduce io_wait_event_killable() Remi Pommarel
2025-08-31 19:03 ` [RFC PATCH 5/5] 9p: Track 9P RPC waiting time as IO Remi Pommarel
4 siblings, 0 replies; 6+ messages in thread
From: Remi Pommarel @ 2025-08-31 19:03 UTC (permalink / raw)
To: v9fs
Cc: linux-fsdevel, linux-kernel, Eric Van Hensbergen,
Latchesar Ionkov, Dominique Martinet, Christian Schoenebeck,
Remi Pommarel
Currently, when cache=loose is enabled, file reads are cached in the
page cache, but symlink reads are not. This patch allows the results
of p9_client_readlink() to be stored in the page cache, eliminating
the need for repeated 9P transactions on subsequent symlink accesses.
This change improves performance for workloads that involve frequent
symlink resolution.
Signed-off-by: Remi Pommarel <repk@triplefau.lt>
---
fs/9p/v9fs.h | 1 +
fs/9p/vfs_inode.c | 7 +++-
fs/9p/vfs_inode_dotl.c | 94 +++++++++++++++++++++++++++++++++++++-----
3 files changed, 90 insertions(+), 12 deletions(-)
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index 8c5fa0f7ba71..f48a85b610e3 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -186,6 +186,7 @@ extern struct inode *v9fs_inode_from_fid(struct v9fs_session_info *v9ses,
struct super_block *sb, int new);
extern const struct inode_operations v9fs_dir_inode_operations_dotl;
extern const struct inode_operations v9fs_file_inode_operations_dotl;
+extern const struct address_space_operations v9fs_symlink_aops_dotl;
extern const struct inode_operations v9fs_symlink_inode_operations_dotl;
extern const struct netfs_request_ops v9fs_req_ops;
extern struct inode *v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses,
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 89eeb2b3ba43..362e39b3e7eb 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -302,10 +302,13 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses,
goto error;
}
- if (v9fs_proto_dotl(v9ses))
+ if (v9fs_proto_dotl(v9ses)) {
inode->i_op = &v9fs_symlink_inode_operations_dotl;
- else
+ inode->i_mapping->a_ops = &v9fs_symlink_aops_dotl;
+ inode_nohighmem(inode);
+ } else {
inode->i_op = &v9fs_symlink_inode_operations;
+ }
break;
case S_IFDIR:
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index 5b5fda617b80..2e2119be1d49 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -126,8 +126,10 @@ static struct inode *v9fs_qid_iget_dotl(struct super_block *sb,
goto error;
v9fs_stat2inode_dotl(st, inode, 0);
- v9fs_set_netfs_context(inode);
- v9fs_cache_inode_get_cookie(inode);
+ if (inode->i_mapping->a_ops == &v9fs_addr_operations) {
+ v9fs_set_netfs_context(inode);
+ v9fs_cache_inode_get_cookie(inode);
+ }
retval = v9fs_get_acl(inode, fid);
if (retval)
goto error;
@@ -858,24 +860,23 @@ v9fs_vfs_mknod_dotl(struct mnt_idmap *idmap, struct inode *dir,
}
/**
- * v9fs_vfs_get_link_dotl - follow a symlink path
+ * v9fs_vfs_get_link_nocache_dotl - Resolve a symlink directly.
+ *
+ * To be used when symlink caching is not enabled.
+ *
* @dentry: dentry for symlink
* @inode: inode for symlink
* @done: destructor for return value
*/
-
static const char *
-v9fs_vfs_get_link_dotl(struct dentry *dentry,
- struct inode *inode,
- struct delayed_call *done)
+v9fs_vfs_get_link_nocache_dotl(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
struct p9_fid *fid;
char *target;
int retval;
- if (!dentry)
- return ERR_PTR(-ECHILD);
-
p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
fid = v9fs_fid_lookup(dentry);
@@ -889,6 +890,75 @@ v9fs_vfs_get_link_dotl(struct dentry *dentry,
return target;
}
+/**
+ * v9fs_symlink_read_folio_dotl - Fetch a symlink path and store it in buffer
+ * cache.
+ * @file: file associated to symlink (NULL)
+ * @folio: folio where to store the symlink resolve result
+ */
+static int v9fs_symlink_read_folio_dotl(struct file *file,
+ struct folio *folio)
+{
+ struct inode *inode = folio->mapping->host;
+ struct dentry *dentry;
+ struct p9_fid *fid;
+ char *target;
+ size_t len;
+ int ret = -EIO;
+
+ /* Does not expect symlink inode to have a fid as it as not been
+ * opened>
+ */
+ dentry = d_find_alias(inode);
+ if (!dentry)
+ goto out;
+
+ fid = v9fs_fid_lookup(dentry);
+ dput(dentry);
+ if (IS_ERR(fid)) {
+ ret = PTR_ERR(fid);
+ goto out;
+ }
+
+ ret = p9_client_readlink(fid, &target);
+ p9_fid_put(fid);
+ if (ret)
+ goto out;
+
+ len = strnlen(target, PAGE_SIZE - 1);
+ target[len] = '\0';
+ memcpy_to_folio(folio, 0, target, len);
+ kfree(target);
+
+ ret = 0;
+out:
+ folio_end_read(folio, ret == 0);
+ return ret;
+}
+
+/**
+ * v9fs_vfs_get_link_dotl - follow a symlink path
+ * @dentry: dentry for symlink
+ * @inode: inode for symlink
+ * @done: destructor for return value
+ */
+static const char *
+v9fs_vfs_get_link_dotl(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
+{
+ struct v9fs_session_info *v9ses;
+
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+
+ v9ses = v9fs_inode2v9ses(inode);
+ if (v9ses->cache & (CACHE_META|CACHE_LOOSE))
+ return page_get_link(dentry, inode, done);
+
+ return v9fs_vfs_get_link_nocache_dotl(dentry, inode, done);
+}
+
int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
{
struct p9_stat_dotl *st;
@@ -945,6 +1015,10 @@ const struct inode_operations v9fs_file_inode_operations_dotl = {
.set_acl = v9fs_iop_set_acl,
};
+const struct address_space_operations v9fs_symlink_aops_dotl = {
+ .read_folio = v9fs_symlink_read_folio_dotl,
+};
+
const struct inode_operations v9fs_symlink_inode_operations_dotl = {
.get_link = v9fs_vfs_get_link_dotl,
.getattr = v9fs_vfs_getattr_dotl,
--
2.50.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [RFC PATCH 4/5] wait: Introduce io_wait_event_killable()
2025-08-31 19:03 [RFC PATCH 0/5] 9p: Performance improvements for build workloads Remi Pommarel
` (2 preceding siblings ...)
2025-08-31 19:03 ` [RFC PATCH 3/5] 9p: Enable symlink caching in page cache Remi Pommarel
@ 2025-08-31 19:03 ` Remi Pommarel
2025-08-31 19:03 ` [RFC PATCH 5/5] 9p: Track 9P RPC waiting time as IO Remi Pommarel
4 siblings, 0 replies; 6+ messages in thread
From: Remi Pommarel @ 2025-08-31 19:03 UTC (permalink / raw)
To: v9fs
Cc: linux-fsdevel, linux-kernel, Eric Van Hensbergen,
Latchesar Ionkov, Dominique Martinet, Christian Schoenebeck,
Remi Pommarel
Add io_wait_event_killable(), a variant of wait_event_killable() that
uses io_schedule() instead of schedule(). This is to be used in
situation where waiting time is to be accounted as IO wait time.
Signed-off-by: Remi Pommarel <repk@triplefau.lt>
---
include/linux/wait.h | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/include/linux/wait.h b/include/linux/wait.h
index 09855d819418..cfeb1adee973 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -937,6 +937,21 @@ extern int do_wait_intr_irq(wait_queue_head_t *, wait_queue_entry_t *);
__ret; \
})
+#define __io_wait_event_killable(wq, condition) \
+ ___wait_event(wq, condition, TASK_KILLABLE, 0, 0, io_schedule())
+
+/*
+ * wait_event_killable() - link wait_event_killable but with io_schedule()
+ */
+#define io_wait_event_killable(wq_head, condition) \
+({ \
+ int __ret = 0; \
+ might_sleep(); \
+ if (!(condition)) \
+ __ret = __io_wait_event_killable(wq_head, condition); \
+ __ret; \
+})
+
#define __wait_event_state(wq, condition, state) \
___wait_event(wq, condition, state, 0, 0, schedule())
--
2.50.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [RFC PATCH 5/5] 9p: Track 9P RPC waiting time as IO
2025-08-31 19:03 [RFC PATCH 0/5] 9p: Performance improvements for build workloads Remi Pommarel
` (3 preceding siblings ...)
2025-08-31 19:03 ` [RFC PATCH 4/5] wait: Introduce io_wait_event_killable() Remi Pommarel
@ 2025-08-31 19:03 ` Remi Pommarel
4 siblings, 0 replies; 6+ messages in thread
From: Remi Pommarel @ 2025-08-31 19:03 UTC (permalink / raw)
To: v9fs
Cc: linux-fsdevel, linux-kernel, Eric Van Hensbergen,
Latchesar Ionkov, Dominique Martinet, Christian Schoenebeck,
Remi Pommarel
Use io_wait_event_killable() to ensure that time spent waiting for 9P
RPC transactions is accounted as IO wait time.
Signed-off-by: Remi Pommarel <repk@triplefau.lt>
---
net/9p/client.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/9p/client.c b/net/9p/client.c
index 5c1ca57ccd28..3f0f4d6efc00 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -713,8 +713,8 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
}
again:
/* Wait for the response */
- err = wait_event_killable(req->wq,
- READ_ONCE(req->status) >= REQ_STATUS_RCVD);
+ err = io_wait_event_killable(req->wq,
+ READ_ONCE(req->status) >= REQ_STATUS_RCVD);
/* Make sure our req is coherent with regard to updates in other
* threads - echoes to wmb() in the callback
--
2.50.1
^ permalink raw reply related [flat|nested] 6+ messages in thread