From nobody Sun May 24 22:35:50 2026 Received: from e3i421.smtp2go.com (e3i421.smtp2go.com [158.120.85.165]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D1F7633F594 for ; Wed, 20 May 2026 19:19:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=158.120.85.165 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779304745; cv=none; b=KXVVeIXNIDfnen8QJjFt80H8KUWuXIgJ63w3SLbO80eftlPF1gyAXLVSYgmWqnjKOHherCXek6X4phor0hrHz9xd71sqXn4R27FQfWh6R/teNBSmZhx/Wi9RFUSyZ3bMqqkjvGyA6lbHlT8Xr8YR34BHtU9fz1fKxnjzpkXmOiw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779304745; c=relaxed/simple; bh=K5ODYb+lCZr9CsKAh8f2lBd2ovJulBoqmGCKQwOvMUw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=HA5UlbDu8SQqY300cuniS3JX8LiTpntPVRDI5Iez2VjH1uufTM2fo0AJdS3gd6jImI8B7Ba3eJbFiIwhlB/MogWkZFXukrzstphz3kNbucsqq0Qzt0M9WX/IwG9B8jf4XDDjyN1FAgd9v2YCy9KGeiXVd1+H+o2lHFvytNBIsxE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=triplefau.lt; spf=pass smtp.mailfrom=em510616.triplefau.lt; dkim=pass (2048-bit key) header.d=triplefau.lt header.i=@triplefau.lt header.b=JQLLQ+yI; arc=none smtp.client-ip=158.120.85.165 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=triplefau.lt Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=em510616.triplefau.lt Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=triplefau.lt header.i=@triplefau.lt header.b="JQLLQ+yI" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=triplefau.lt; i=@triplefau.lt; q=dns/txt; s=s510616; t=1779303834; h=from : subject : to : message-id : date; bh=gvhlhWo0fj/91Xw4zvBxPEpT76wIaP1E9xbcLqWvsE0=; b=JQLLQ+yI5AJKNwHTtnaVMbez8Sshbr3rPF04tYo3CjZ0+pFOFxW20xWxnp5x9ZcgY+hxR UZpZO1/acej3gkFUniPUKp9G/m8W68cYBhx22wnK5a9EZkX13mqgI3q6ihHFFTLtoOTvrrw aEK2DfhCIgBnXuaxJWjYIt9onMXaIg++ghaAAO7KGJNz0gz1RoUDGCWI8SR9Mz/PU2zC5Ab rNPr47lnifVtlw+QvMCWEiQdHIttOUk7S2SPQzLXXmN5dYOKRJ5YSb5DNws5ciMMk5ZuJRP fFBJMehOpgjqbdUB6vsBnRgFBoQmv7I5ORoq7Jb0d1Qw/2EvQFEzUp2UMIIw== Received: from [10.12.239.196] (helo=localhost) by smtpcorp.com with esmtpsa (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.99.2) (envelope-from ) id 1wPmCr-4o5NDgrlNjX-oDly; Wed, 20 May 2026 19:03:50 +0000 From: Remi Pommarel To: v9fs@lists.linux.dev Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, Eric Van Hensbergen , Latchesar Ionkov , Dominique Martinet , Christian Schoenebeck , Remi Pommarel Subject: [PATCH v6 1/4] 9p: Cache negative dentries for lookup performance Date: Wed, 20 May 2026 20:41:37 +0200 Message-ID: <25eae9e611d7ed5a83059f83c73b53c47545d901.1779302002.git.repk@triplefau.lt> X-Mailer: git-send-email 2.52.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Report-Abuse: Please forward a copy of this message, including all headers, to Feedback-ID: 510616m:510616apGKSTK:510616sQdWuhQ0oo X-smtpcorp-track: a8PUrWkZY-Qk.YYNPjepitpRu.T5RcwAnumte Content-Type: text/plain; charset="utf-8" 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 --- fs/9p/fid.c | 11 +++-- fs/9p/v9fs.c | 1 + fs/9p/v9fs.h | 5 ++ fs/9p/v9fs_vfs.h | 15 ++++++ fs/9p/vfs_dentry.c | 105 ++++++++++++++++++++++++++++++++++------ fs/9p/vfs_inode.c | 12 +++-- fs/9p/vfs_super.c | 1 + include/net/9p/client.h | 2 + 8 files changed, 128 insertions(+), 24 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 @@ =20 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 =3D to_v9fs_dentry(dentry); + + hlist_add_head(&fid->dlist, &v9fs_dentry->head); } =20 =20 @@ -112,6 +114,7 @@ void v9fs_open_fid_add(struct inode *inode, struct p9_f= id **pfid) =20 static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int= any) { + struct v9fs_dentry *v9fs_dentry =3D to_v9fs_dentry(dentry); struct p9_fid *fid, *ret; =20 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 *den= try, kuid_t uid, int any) any); ret =3D NULL; /* we'll recheck under lock if there's anything to look in */ - if (dentry->d_fsdata) { - struct hlist_head *h =3D (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 =3D fid; p9_fid_get(ret); diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index acda42499ca9..be83744b75b2 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -426,6 +426,7 @@ static void v9fs_apply_options(struct v9fs_session_info= *v9ses, v9ses->cache =3D ctx->session_opts.cache; v9ses->uid =3D ctx->session_opts.uid; v9ses->session_lock_timeout =3D ctx->session_opts.session_lock_timeout; + v9ses->ndentry_timeout_ms =3D ctx->session_opts.ndentry_timeout_ms; } =20 /** diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index 6a12445d3858..e630c5111d74 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h @@ -91,6 +91,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 @@ -101,6 +102,7 @@ enum p9_cache_bits { * @uid: if %V9FS_ACCESS_SINGLE, the numeric uid which mounted the hierarc= hy * @clnt: reference to 9P network client instantiated for this session * @slist: reference to list of registered 9p sessions + * @ndentry_timeout_ms: Negative dentry caching retention time * * This structure holds state for each session instance established during * a sys_mount() . @@ -116,6 +118,7 @@ struct v9fs_session_info { unsigned short debug; unsigned int afid; unsigned int cache; + unsigned int ndentry_timeout_ms; #ifdef CONFIG_9P_FSCACHE char *cachetag; struct fscache_volume *fscache; @@ -133,6 +136,8 @@ struct v9fs_session_info { long session_lock_timeout; /* retry interval for blocking locks */ }; =20 +#define NDENTRY_TIMEOUT_NEVER (-1U) + /* cache_validity flags */ #define V9FS_INO_INVALID_ATTR 0x01 =20 diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index 34c115d7c250..1856d91f8703 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 =20 +/** + * 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_ndentry_refresh_timeout(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; =20 diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index c5bf74d547e8..e549e222602e 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c @@ -23,6 +23,46 @@ #include "v9fs_vfs.h" #include "fid.h" =20 +/** + * v9fs_ndentry_is_expired - Check if negative dentry lookup has expired + * + * This should be called to know if a negative dentry should be removed fr= om + * cache. + * + * @dentry: dentry in question + * + */ +static bool v9fs_ndentry_is_expired(struct dentry const *dentry) +{ + struct v9fs_session_info *v9ses =3D v9fs_dentry2v9ses(dentry); + struct v9fs_dentry *v9fs_dentry =3D to_v9fs_dentry(dentry); + + if (v9ses->ndentry_timeout_ms =3D=3D NDENTRY_TIMEOUT_NEVER) + return false; + + return time_before_eq64(v9fs_dentry->expire_time, get_jiffies_64()); +} + +/** + * v9fs_ndentry_refresh_timeout - Refresh negative dentry lookup cache tim= eout + * + * This should be called when a look up yields a negative entry. + * + * @dentry: dentry in question + * + */ +void v9fs_ndentry_refresh_timeout(struct dentry *dentry) +{ + struct v9fs_session_info *v9ses =3D v9fs_dentry2v9ses(dentry); + struct v9fs_dentry *v9fs_dentry =3D to_v9fs_dentry(dentry); + + if (v9ses->ndentry_timeout_ms =3D=3D NDENTRY_TIMEOUT_NEVER) + return; + + v9fs_dentry->expire_time =3D get_jiffies_64() + + msecs_to_jiffies(v9ses->ndentry_timeout_ms); +} + /** * 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 dentr= y *dentry) p9_debug(P9_DEBUG_VFS, " dentry: %pd (%p)\n", dentry, dentry); =20 - /* Don't cache negative dentries */ - if (d_really_is_negative(dentry)) - return 1; - return 0; -} + if (!d_really_is_negative(dentry)) + return 0; =20 -/** - * v9fs_dentry_release - called when dentry is going to be freed - * @dentry: dentry that is being release - * - */ + return v9fs_ndentry_is_expired(dentry); +} =20 -static void v9fs_dentry_release(struct dentry *dentry) +static void __v9fs_dentry_fid_remove(struct dentry *dentry) { + struct v9fs_dentry *v9fs_dentry =3D to_v9fs_dentry(dentry); struct hlist_node *p, *n; struct hlist_head head; =20 @@ -54,13 +89,54 @@ static void v9fs_dentry_release(struct dentry *dentry) dentry, dentry); =20 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); =20 hlist_for_each_safe(p, n, &head) p9_fid_put(hlist_entry(p, struct p9_fid, dlist)); } =20 +/** + * v9fs_dentry_fid_remove - Release all dentry's fids + * @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 =3D kzalloc(sizeof(*v9fs_dentry), + GFP_KERNEL); + + if (!v9fs_dentry) + return -ENOMEM; + + INIT_HLIST_HEAD(&v9fs_dentry->head); + dentry->d_fsdata =3D (void *)v9fs_dentry; + return 0; +} + +/** + * v9fs_dentry_release - called when dentry is going to be freed + * @dentry: dentry that is being released + * + */ +static void v9fs_dentry_release(struct dentry *dentry) +{ + struct v9fs_dentry *v9fs_dentry =3D to_v9fs_dentry(dentry); + + __v9fs_dentry_fid_remove(dentry); + kfree_rcu(v9fs_dentry, rcu); +} + static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int fl= ags) { struct p9_fid *fid; @@ -72,7 +148,7 @@ static int __v9fs_lookup_revalidate(struct dentry *dentr= y, unsigned int flags) =20 inode =3D d_inode(dentry); if (!inode) - goto out_valid; + return !v9fs_ndentry_is_expired(dentry); =20 v9inode =3D V9FS_I(inode); if (v9inode->cache_validity & V9FS_INO_INVALID_ATTR) { @@ -112,7 +188,6 @@ static int __v9fs_lookup_revalidate(struct dentry *dent= ry, unsigned int flags) return retval; } } -out_valid: p9_debug(P9_DEBUG_VFS, "dentry: %pd (%p) is valid\n", dentry, dentry); return 1; } @@ -139,12 +214,14 @@ const struct dentry_operations v9fs_cached_dentry_ope= rations =3D { .d_revalidate =3D v9fs_lookup_revalidate, .d_weak_revalidate =3D __v9fs_lookup_revalidate, .d_delete =3D v9fs_cached_dentry_delete, + .d_init =3D v9fs_dentry_init, .d_release =3D v9fs_dentry_release, .d_unalias_trylock =3D v9fs_dentry_unalias_trylock, .d_unalias_unlock =3D v9fs_dentry_unalias_unlock, }; =20 const struct dentry_operations v9fs_dentry_operations =3D { + .d_init =3D v9fs_dentry_init, .d_release =3D v9fs_dentry_release, .d_unalias_trylock =3D v9fs_dentry_unalias_trylock, .d_unalias_unlock =3D v9fs_dentry_unalias_unlock, diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index f468acb8ee7d..5cbbebafc24e 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) =20 /* 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,14 +732,16 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, str= uct dentry *dentry, name =3D dentry->d_name.name; fid =3D p9_client_walk(dfid, 1, &name, 1); p9_fid_put(dfid); - if (fid =3D=3D ERR_PTR(-ENOENT)) + if (fid =3D=3D ERR_PTR(-ENOENT)) { inode =3D NULL; - else if (IS_ERR(fid)) + v9fs_ndentry_refresh_timeout(dentry); + } else if (IS_ERR(fid)) { inode =3D ERR_CAST(fid); - else if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) + } else if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) { inode =3D v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); - else + } else { inode =3D v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); + } /* * If we had a rename on the server and a parallel lookup * for the new name, then make sure we instantiate with diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 431f24938a1d..94d6b02c221b 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -330,6 +330,7 @@ static int v9fs_init_fs_context(struct fs_context *fc) ctx->session_opts.uid =3D INVALID_UID; ctx->session_opts.dfltuid =3D V9FS_DEFUID; ctx->session_opts.dfltgid =3D V9FS_DEFGID; + ctx->session_opts.ndentry_timeout_ms =3D 0; =20 /* initialize client options */ ctx->client_opts.proto_version =3D p9_proto_2000L; diff --git a/include/net/9p/client.h b/include/net/9p/client.h index 838a94218b59..55c6cb54bd25 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -192,6 +192,7 @@ struct p9_rdma_opts { * @dfltgid: default numeric groupid to mount hierarchy as * @uid: if %V9FS_ACCESS_SINGLE, the numeric uid which mounted the hierarc= hy * @session_lock_timeout: retry interval for blocking locks + * @ndentry_timeout_ms: Negative dentry lookup cache retention time in ms * * This strucure holds options which are parsed and will be transferred * to the v9fs_session_info structure when mounted, and therefore largely @@ -203,6 +204,7 @@ struct p9_session_opts { unsigned short debug; unsigned int afid; unsigned int cache; + unsigned int ndentry_timeout_ms; #ifdef CONFIG_9P_FSCACHE char *cachetag; #endif --=20 2.52.0 From nobody Sun May 24 22:35:50 2026 Received: from e3i421.smtp2go.com (e3i421.smtp2go.com [158.120.85.165]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C16B8314A98 for ; Wed, 20 May 2026 19:14:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=158.120.85.165 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779304452; cv=none; b=tGK3wE7dkm8QlNiKcQP4XV6XjgwxlYYXzuQM+c+PZfg8Aidvc576lEY8RDQ8fZxBV2s6W13BfehgYgIVjUiVWK75HHXFJCWB5vamKT003DeW+SNKKAbPe1qZvCsRxijCXJp1Phx0DHQRlJfuL3LiJTr1uW0Is8yxrN/RBRXuVA4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779304452; c=relaxed/simple; bh=AAN255HdM3uZ4+It0uI52zgspk3PlnjRuFJ5Vkbr2uQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=taBbA7gDTH0TAzjSzP8HdKXdoUnFXS+1gpqgFNJ7rmA52hH8aHO2nCzf5Omc0qgw7eG1bIf44Kxmw/x5K0P6cfU5xmCA9iCDYS9d/W9ICOhzyl8i7CMkktFgrDs4XaHAHXTxsh+a1lrDp0YDi8H2H8rJJk+lwQotOlZlMulxD50= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=triplefau.lt; spf=pass smtp.mailfrom=em510616.triplefau.lt; dkim=pass (2048-bit key) header.d=triplefau.lt header.i=@triplefau.lt header.b=PzJZ6JP5; arc=none smtp.client-ip=158.120.85.165 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=triplefau.lt Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=em510616.triplefau.lt Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=triplefau.lt header.i=@triplefau.lt header.b="PzJZ6JP5" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=triplefau.lt; i=@triplefau.lt; q=dns/txt; s=s510616; t=1779303828; h=from : subject : to : message-id : date; bh=Hc1ZS8wBS8cUwmC29S6NYs+RegvTzxi9h3if/SxiDqk=; b=PzJZ6JP5vNbCT2tkP1tF1TkzHsPEKNGSdnIzpNmK7+EsDQOJvg+LdTTAiD/OTgnF3k9QA UtjHajAGv5HNZEpcaLh5vo7WlrBL1ohK4f3b2B6NH8T4W34Rd2nIYO+KnR3/B9VonqUWG0X /tM4xyVy6Wq02N0c6CSyroGx5bzxuBpMFipihpVtI+s+7CoB7brL67XdbQsEIJfUXxqKrfO QXP5+qom5fGwqDTPSfdIoVH94RORmF58psXhvUtIJDV5/Og7gAjTt3brqnUftk5Pnmhxd+m IRdVoSgmaAT8xIWKhgM5K+hg4BLP6z7ISFGVVTqFX+EI8ADf84Ffgdc7QQ9w== Received: from [10.12.239.196] (helo=localhost) by smtpcorp.com with esmtpsa (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.99.2) (envelope-from ) id 1wPmCt-4o5NDgrk2Nn-sXOx; Wed, 20 May 2026 19:03:52 +0000 From: Remi Pommarel To: v9fs@lists.linux.dev Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, Eric Van Hensbergen , Latchesar Ionkov , Dominique Martinet , Christian Schoenebeck , Remi Pommarel Subject: [PATCH v6 2/4] 9p: Add mount option for negative dentry cache retention Date: Wed, 20 May 2026 20:41:38 +0200 Message-ID: <789d65c8cd114b9af9061b821d645990972ef443.1779302002.git.repk@triplefau.lt> X-Mailer: git-send-email 2.52.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Report-Abuse: Please forward a copy of this message, including all headers, to Feedback-ID: 510616m:510616apGKSTK:510616swS8dw1lx_ X-smtpcorp-track: u2geHmDnHQ2g.kwauNJxxU5WN.ztFw2wvLDKg Content-Type: text/plain; charset="utf-8" Introduce a new mount option, negtimeout, for v9fs that allows users to specify how long negative dentries are retained in the cache. The retention time can be set in milliseconds (e.g. negtimeout=3D10000 for a 10secs retention time) or a negative value (e.g. negtimeout=3D-1) to keep negative entries until the buffer cache management removes them. For consistency reasons, this option should only be used in exclusive or read-only mount scenarios, aligning with the cache=3Dloose usage. Signed-off-by: Remi Pommarel --- Documentation/filesystems/9p.rst | 5 +++++ fs/9p/v9fs.c | 16 +++++++++++++++- fs/9p/v9fs.h | 23 +++++++++++++---------- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/Documentation/filesystems/9p.rst b/Documentation/filesystems/9= p.rst index be3504ca034a..b014c7aabba4 100644 --- a/Documentation/filesystems/9p.rst +++ b/Documentation/filesystems/9p.rst @@ -238,6 +238,11 @@ Options cachetag cache tag to use the specified persistent cache. cache tags for existing cache sessions can be listed at /sys/fs/9p/caches. (applies only to cache=3Dfscache) + + negtimeout the duration (in milliseconds) that negative dentries (pat= hs + that do not actually exist) are retained in the cache. If + set to a negative value, those entries are kept indefinite= ly + until evicted by the buffer cache management system =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D =20 Behavior diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index be83744b75b2..3e758b66fefa 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -39,7 +39,7 @@ enum { * source if we rejected it as EINVAL */ Opt_source, /* Options that take integer arguments */ - Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid, + Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid, Opt_negtimeout, /* String options */ Opt_uname, Opt_remotename, Opt_cache, Opt_cachetag, /* Options that take no arguments */ @@ -93,6 +93,7 @@ const struct fs_parameter_spec v9fs_param_spec[] =3D { fsparam_string ("access", Opt_access), fsparam_flag ("posixacl", Opt_posixacl), fsparam_u32 ("locktimeout", Opt_locktimeout), + fsparam_s32 ("negtimeout", Opt_negtimeout), =20 /* client options */ fsparam_u32 ("msize", Opt_msize), @@ -159,6 +160,9 @@ int v9fs_show_options(struct seq_file *m, struct dentry= *root) from_kgid_munged(&init_user_ns, v9ses->dfltgid)); if (v9ses->afid !=3D ~0) seq_printf(m, ",afid=3D%u", v9ses->afid); + if (v9ses->flags & V9FS_NDENTRY_TIMEOUT_SET) + seq_printf(m, ",negtimeout=3D%d", + (int)v9ses->ndentry_timeout_ms); if (strcmp(v9ses->uname, V9FS_DEFUSER) !=3D 0) seq_printf(m, ",uname=3D%s", v9ses->uname); if (strcmp(v9ses->aname, V9FS_DEFANAME) !=3D 0) @@ -337,6 +341,16 @@ int v9fs_parse_param(struct fs_context *fc, struct fs_= parameter *param) session_opts->session_lock_timeout =3D (long)result.uint_32 * HZ; break; =20 + case Opt_negtimeout: + session_opts->flags |=3D V9FS_NDENTRY_TIMEOUT_SET; + if (result.int_32 < 0) { + session_opts->ndentry_timeout_ms =3D + NDENTRY_TIMEOUT_NEVER; + } else { + session_opts->ndentry_timeout_ms =3D result.int_32; + } + break; + /* Options for client */ case Opt_msize: if (result.uint_32 < 4096) { diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index e630c5111d74..a462bcbfc7da 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h @@ -24,6 +24,8 @@ * @V9FS_ACCESS_ANY: use a single attach for all users * @V9FS_ACCESS_MASK: bit mask of different ACCESS options * @V9FS_POSIX_ACL: POSIX ACLs are enforced + * @V9FS_NDENTRY_TIMEOUT_SET: Has negative dentry timeout retention time b= een + * overridden by negtimeout mount option * * Session flags reflect options selected by users at mount time */ @@ -34,16 +36,17 @@ #define V9FS_ACL_MASK V9FS_POSIX_ACL =20 enum p9_session_flags { - V9FS_PROTO_2000U =3D 0x01, - V9FS_PROTO_2000L =3D 0x02, - V9FS_ACCESS_SINGLE =3D 0x04, - V9FS_ACCESS_USER =3D 0x08, - V9FS_ACCESS_CLIENT =3D 0x10, - V9FS_POSIX_ACL =3D 0x20, - V9FS_NO_XATTR =3D 0x40, - V9FS_IGNORE_QV =3D 0x80, /* ignore qid.version for cache hints */ - V9FS_DIRECT_IO =3D 0x100, - V9FS_SYNC =3D 0x200 + V9FS_PROTO_2000U =3D 0x01, + V9FS_PROTO_2000L =3D 0x02, + V9FS_ACCESS_SINGLE =3D 0x04, + V9FS_ACCESS_USER =3D 0x08, + V9FS_ACCESS_CLIENT =3D 0x10, + V9FS_POSIX_ACL =3D 0x20, + V9FS_NO_XATTR =3D 0x40, + V9FS_IGNORE_QV =3D 0x80, /* ignore qid.version for cache hints = */ + V9FS_DIRECT_IO =3D 0x100, + V9FS_SYNC =3D 0x200, + V9FS_NDENTRY_TIMEOUT_SET =3D 0x400, }; =20 /** --=20 2.52.0 From nobody Sun May 24 22:35:50 2026 Received: from e3i421.smtp2go.com (e3i421.smtp2go.com [158.120.85.165]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EC3C62F8E9E for ; Wed, 20 May 2026 19:09:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=158.120.85.165 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779304145; cv=none; b=KX1ejZ0pp8MEbo4TYrC/qxb87QcGfV7zFKP/Ildpg0cGDaoNV7KjZefwSykWa5aMadtGsxttLK7E6wxiU4bMBh5Of1R3vIa5ZWbx8eqFl+JhK8BRDGpE+jssEKtzHatyoKPWb2FfJTV6kfJdsNEPw2zIJdh1PTLxjAaV6ufE3GI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779304145; c=relaxed/simple; bh=vodvvcswZRlbDFXfFUiY4r5AdgWfA3xto6hrwuObiOo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CMO0NSv3jK05L6jDFx6YC61nUXFPO72sTpata2rUzjVVh+YH7WL59piAa7ffJiGadc7rKJOY9o7++M64B5y17zSWSX+cF0HPqtfrLnqBxKm5a/35FHMlihTMaKY/FblpeW+J36mTL0k55xFUn6TjfK1ExQulRtfO8yUldrFyADE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=triplefau.lt; spf=pass smtp.mailfrom=em510616.triplefau.lt; dkim=pass (2048-bit key) header.d=triplefau.lt header.i=@triplefau.lt header.b=E9vQrnFj; arc=none smtp.client-ip=158.120.85.165 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=triplefau.lt Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=em510616.triplefau.lt Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=triplefau.lt header.i=@triplefau.lt header.b="E9vQrnFj" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=triplefau.lt; i=@triplefau.lt; q=dns/txt; s=s510616; t=1779303837; h=from : subject : to : message-id : date; bh=uCNwpibAseSDNQ68UeAV3DI4drw37VIBam9jpljEa7M=; b=E9vQrnFjYq9krtzwqkrsC5hJdLErVIKwUKp2dqxr2ATSm0FPvUI+2avaxs3P9zLInj/55 OSNjdbBrTBNcLKdasvmiD9Zut+bim0TTuaQ8ZTzCbACUd4gnAyElU0XQ3snsygMJU4O19o2 XvhsFOJ6jnoZIMl7JRiSEyAdgynXmvsBBsg9wMHU97bIzD4ZWo7IGcqRJJVzI/Bp/Odjjj9 KNNWMzBokPDOaHkaoFJDfTnwtlxHRy4dKJAXpaX0p/S3NuYSSYfsvdoIqKZqiH2C5WcHv6i XvzeORmfLU55+ZIZQCehD2WufVN0j4qSlRs2+MAJjuDp24YErcorVK3krJEA== Received: from [10.12.239.196] (helo=localhost) by smtpcorp.com with esmtpsa (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.99.2) (envelope-from ) id 1wPmCw-AIkwcC8nAYK-KwqD; Wed, 20 May 2026 19:03:55 +0000 From: Remi Pommarel To: v9fs@lists.linux.dev Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, Eric Van Hensbergen , Latchesar Ionkov , Dominique Martinet , Christian Schoenebeck , Remi Pommarel Subject: [PATCH v6 3/4] 9p: Set default negative dentry retention time for cache=loose Date: Wed, 20 May 2026 20:41:39 +0200 Message-ID: X-Mailer: git-send-email 2.52.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Report-Abuse: Please forward a copy of this message, including all headers, to Feedback-ID: 510616m:510616apGKSTK:510616sfrOXB0SBC X-smtpcorp-track: 3rMSdeuBUhIz.yM7mZgCyZCRv.3ghuaQXIcl1 Content-Type: text/plain; charset="utf-8" For cache=3Dloose mounts, set the default negative dentry cache retention time to 24 hours. Signed-off-by: Remi Pommarel --- fs/9p/v9fs.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 3e758b66fefa..274c5157135d 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -24,6 +24,9 @@ #include "v9fs_vfs.h" #include "cache.h" =20 +/* cache=3Dloose default negative dentry retention time is 24hours */ +#define CACHE_LOOSE_NDENTRY_TIMEOUT_DEFAULT (24 * 60 * 60 * 1000) + static DEFINE_SPINLOCK(v9fs_sessionlist_lock); static LIST_HEAD(v9fs_sessionlist); struct kmem_cache *v9fs_inode_cache; @@ -441,6 +444,13 @@ static void v9fs_apply_options(struct v9fs_session_inf= o *v9ses, v9ses->uid =3D ctx->session_opts.uid; v9ses->session_lock_timeout =3D ctx->session_opts.session_lock_timeout; v9ses->ndentry_timeout_ms =3D ctx->session_opts.ndentry_timeout_ms; + + /* If negative dentry timeout has not been overridden set default for + * cache=3Dloose + */ + if (!(v9ses->flags & V9FS_NDENTRY_TIMEOUT_SET) && + (v9ses->cache & CACHE_LOOSE)) + v9ses->ndentry_timeout_ms =3D CACHE_LOOSE_NDENTRY_TIMEOUT_DEFAULT; } =20 /** --=20 2.52.0 From nobody Sun May 24 22:35:50 2026 Received: from e3i421.smtp2go.com (e3i421.smtp2go.com [158.120.85.165]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2A33633A9DD for ; Wed, 20 May 2026 19:09:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=158.120.85.165 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779304149; cv=none; b=dySk7erMbkUaBLYofBbFoCMUe1Wmh77z5GjeBbhfiZ4FAUBDfxZTWERtHl4XHlFWVRz2xqURJtBzrEH0cebh5ynmD4MGjUYUP+XUXZpwG7zKiFGlJ4JsiKYfO58ARDOVBuSPnufv5l9xG0Tilv3yVbax0xqXh3h2S0AZEUn1kGQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779304149; c=relaxed/simple; bh=UV7IAB9xw0IT0Y0c5rqonZ3tZvtOYfqWYwTSukX+A4g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=EPEBPhFr3mOG8ulA+xbC+aQIzxIACJoF6nlo7UeCAlri02O87d85kfzvdYljAtNYUIwhrizOFxPrVzXejKo6mBgyuFPrrUiTP/pH5ZAXho3lmrv9kPj0zUKwRCyjmIH/gybzPZsrqe9Q4dwvVIqZMoArgY7DGWov7+5MQ83gRSY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=triplefau.lt; spf=pass smtp.mailfrom=em510616.triplefau.lt; dkim=pass (2048-bit key) header.d=triplefau.lt header.i=@triplefau.lt header.b=ITnOOZ/l; arc=none smtp.client-ip=158.120.85.165 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=triplefau.lt Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=em510616.triplefau.lt Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=triplefau.lt header.i=@triplefau.lt header.b="ITnOOZ/l" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=triplefau.lt; i=@triplefau.lt; q=dns/txt; s=s510616; t=1779303844; h=from : subject : to : message-id : date; bh=ql7nWTfzUIDStj06O1nkeiwwAtG7EpyS9ahPlx1cxpc=; b=ITnOOZ/lzJ4mZuccpzV3qtV51U1mVjEr5wtU5oIFzmHBYv9AFs5Ff0IxVYB0mSVRX+qKr PMK5ePORDeyyCpgqsaEiWx0Qa8+N4V9xYE6crWEVbzFeSJ5nqmEQGT7lHo/yrLwvWKi5LbO UttEOU7e85ldnWj9YMpS9kDtlFerdSUmUis6w8CUCuivYfXWVBygVWLsYxRNbXyyf7bQcBo 4fT9fPu2vW2lNG6onE3BIu8jcotenqHZfsFDeS86pyyROCgjVXHdBY5LrCN3zJfQ2A4gGBh CN+JGDCm842ei5im3jvl9tkZGz3ECV5fTyQoyDCoZiG/Azv1ZrHMonTrqdSA== Received: from [10.12.239.196] (helo=localhost) by smtpcorp.com with esmtpsa (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.99.2-S2G) (envelope-from ) id 1wPmCy-FnQW0hPyp0D-nFNU; Wed, 20 May 2026 19:03:56 +0000 From: Remi Pommarel To: v9fs@lists.linux.dev Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, Eric Van Hensbergen , Latchesar Ionkov , Dominique Martinet , Christian Schoenebeck , Remi Pommarel Subject: [PATCH v6 4/4] 9p: Enable symlink caching in page cache Date: Wed, 20 May 2026 20:41:40 +0200 Message-ID: <0044c3cbf5c3f1b4734e8b98992e17b54e9044b4.1779302002.git.repk@triplefau.lt> X-Mailer: git-send-email 2.52.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Report-Abuse: Please forward a copy of this message, including all headers, to Feedback-ID: 510616m:510616apGKSTK:510616sydEGVA3J3 X-smtpcorp-track: 7iVVJVCEISco.fRTzRhGALsQr.V5M1bAbA4Zw Content-Type: text/plain; charset="utf-8" Currently, when cache=3Dloose 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 --- fs/9p/vfs_addr.c | 47 ++++++++++++++++++++++++++++++--- fs/9p/vfs_inode.c | 6 +++-- fs/9p/vfs_inode_dotl.c | 60 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 100 insertions(+), 13 deletions(-) diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index c21d33830f5f..bc840614bfaf 100644 --- a/fs/9p/vfs_addr.c +++ b/fs/9p/vfs_addr.c @@ -70,11 +70,43 @@ static void v9fs_issue_read(struct netfs_io_subrequest = *subreq) { struct netfs_io_request *rreq =3D subreq->rreq; struct p9_fid *fid =3D rreq->netfs_priv; + char *target; unsigned long long pos =3D subreq->start + subreq->transferred; - int total, err; - - total =3D p9_client_read(fid, pos, &subreq->io_iter, &err); + int total =3D 0, err, len, n; + + if (S_ISLNK(rreq->inode->i_mode)) { + /* p9_client_readlink() must not be called for legacy protocols + * 9p2000 or 9p2000.u. + */ + BUG_ON(!p9_is_proto_dotl(fid->clnt)); + if (WARN_ON_ONCE(pos)) { + /* reading a link at a non null offset should + * not happen + */ + err =3D -EIO; + goto fill_subreq; + } + err =3D p9_client_readlink(fid, &target); + if (err !=3D 0) + goto fill_subreq; + len =3D strlen(target); + if (len !=3D i_size_read(rreq->inode)) { + kfree(target); + err =3D -EIO; + goto fill_subreq; + } + n =3D copy_to_iter(target, len, &subreq->io_iter); + kfree(target); + if (n !=3D len) { + err =3D -EFAULT; + goto fill_subreq; + } + total =3D n; + } else { + total =3D p9_client_read(fid, pos, &subreq->io_iter, &err); + } =20 +fill_subreq: /* if we just extended the file size, any portion not in * cache won't be on server and is zeroes */ if (subreq->rreq->origin !=3D NETFS_UNBUFFERED_READ && @@ -99,6 +131,7 @@ static void v9fs_issue_read(struct netfs_io_subrequest *= subreq) static int v9fs_init_request(struct netfs_io_request *rreq, struct file *f= ile) { struct p9_fid *fid; + struct dentry *dentry; bool writing =3D (rreq->origin =3D=3D NETFS_READ_FOR_WRITE || rreq->origin =3D=3D NETFS_WRITETHROUGH || rreq->origin =3D=3D NETFS_UNBUFFERED_WRITE || @@ -115,6 +148,14 @@ static int v9fs_init_request(struct netfs_io_request *= rreq, struct file *file) if (!fid) goto no_fid; p9_fid_get(fid); + } else if (S_ISLNK(rreq->inode->i_mode)) { + dentry =3D d_find_any_alias(rreq->inode); + if (!dentry) + goto no_fid; + fid =3D v9fs_fid_lookup(dentry); + dput(dentry); + if (IS_ERR(fid)) + goto no_fid; } else { fid =3D v9fs_fid_find_inode(rreq->inode, writing, INVALID_UID, true); if (!fid) diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 5cbbebafc24e..d29df0b2e89c 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -302,10 +302,12 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses, goto error; } =20 - if (v9fs_proto_dotl(v9ses)) + if (v9fs_proto_dotl(v9ses)) { inode->i_op =3D &v9fs_symlink_inode_operations_dotl; - else + inode_nohighmem(inode); + } else { inode->i_op =3D &v9fs_symlink_inode_operations; + } =20 break; case S_IFDIR: diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 141fb54db65d..19260de64a1d 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -690,9 +690,11 @@ v9fs_vfs_symlink_dotl(struct mnt_idmap *idmap, struct = inode *dir, int err; kgid_t gid; const unsigned char *name; + struct v9fs_session_info *v9ses; struct p9_qid qid; struct p9_fid *dfid; struct p9_fid *fid =3D NULL; + struct inode *inode; =20 name =3D dentry->d_name.name; p9_debug(P9_DEBUG_VFS, "%llu,%s,%s\n", dir->i_ino, name, symname); @@ -716,6 +718,26 @@ v9fs_vfs_symlink_dotl(struct mnt_idmap *idmap, struct = inode *dir, =20 v9fs_invalidate_inode_attr(dir); =20 + /* instantiate inode and assign the unopened fid to the dentry */ + fid =3D p9_client_walk(dfid, 1, &name, 1); + if (IS_ERR(fid)) { + err =3D PTR_ERR(fid); + p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", + err); + goto error; + } + + v9ses =3D v9fs_inode2v9ses(dir); + inode =3D v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); + if (IS_ERR(inode)) { + err =3D PTR_ERR(inode); + p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", + err); + goto error; + } + v9fs_fid_add(dentry, &fid); + d_instantiate(dentry, inode); + err =3D 0; error: p9_fid_put(fid); p9_fid_put(dfid); @@ -857,24 +879,23 @@ v9fs_vfs_mknod_dotl(struct mnt_idmap *idmap, struct i= node *dir, } =20 /** - * 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; =20 - if (!dentry) - return ERR_PTR(-ECHILD); - p9_debug(P9_DEBUG_VFS, "%pd\n", dentry); =20 fid =3D v9fs_fid_lookup(dentry); @@ -888,6 +909,29 @@ v9fs_vfs_get_link_dotl(struct dentry *dentry, return target; } =20 +/** + * 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 =3D 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; --=20 2.52.0