From nobody Mon Feb 9 01:22:24 2026 Received: from e2i340.smtp2go.com (e2i340.smtp2go.com [103.2.141.84]) (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 28C6C3DA7DD for ; Wed, 21 Jan 2026 20:14:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=103.2.141.84 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769026443; cv=none; b=PcjKDyTeLa6ASng+jWTuhaBPrAJue00wCQNbjQvxbsc4beuzncITvGAOLbjDn/a21t67RAr2LBzbbLct8swforfF1d+hXDV79KhBZP5R53K3vCmJxFFHpuGmcb7nRJPsrn+wxJ8vAPJWLGtjXwCcZZRXDgVjepsP39v5rgeeWo4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769026443; c=relaxed/simple; bh=oXRQ+OIvRVA8lOdQTnWadsO0WEXGTxyNaHE7RJnSbuI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MHqrAB2QMHlmCrCvlcKeeqDaxr6RUZwzqXQDBPDNZObsln1hxQVbObzi/t8UlWfTkl9Fqg75HbXAr/prJegD3XPWFW3au5ki0un7CNya65yneUB+SCuRtAW6m0wjIgWD4n1x03s4dUiqOOSvC08nLHpheMDSIxebACXcyGblltE= 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=fail (0-bit key) header.d=smtpservice.net header.i=@smtpservice.net header.b=Y1hxpmHG reason="unknown key version"; dkim=pass (2048-bit key) header.d=triplefau.lt header.i=@triplefau.lt header.b=l1KNJIvC; arc=none smtp.client-ip=103.2.141.84 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=fail reason="unknown key version" (0-bit key) header.d=smtpservice.net header.i=@smtpservice.net header.b="Y1hxpmHG"; dkim=pass (2048-bit key) header.d=triplefau.lt header.i=@triplefau.lt header.b="l1KNJIvC" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=smtpservice.net; s=maxzs0.a1-4.dyn; x=1769027341; h=Feedback-ID: X-Smtpcorp-Track:Message-ID:Date:Subject:To:From:Reply-To:Sender: List-Unsubscribe:List-Unsubscribe-Post; bh=1bBRb8rvUmXiBXLsNIGFcB0tqFd9sAVSXXO9H/xLowQ=; b=Y1hxpmHGdVpXWVbisydEbIFCwy KUwFRTUpGC8umzFtf6sz5gb8NhTd6XXbg3qtYV6uDqSy5vVkxjeVIuIrrEQaG/z7cnRbxV4J7W580 qi77Wt6PMJl5/Sg+tTWXXd5ODLYOv02+pz2ZbIaK8CxXY8KHzQ+l7xQPfs6Iy6rnA8EYwsI2JqQIs t/XigPqKBUI4UVKc6I4L40yNgVSL5yuAqu1XM9aOSiNrJN3Hfr3+rI03+N2nHG6VcNdnChtzbbs22 CRGnWLR4Oen4W2efwftargdoff5EVgpLM+wALx4MtD1K8YHIFHdCvwiejdaU+jA8pOlZdaur0IvlA 2mpIVaFg==; DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=triplefau.lt; i=@triplefau.lt; q=dns/txt; s=s510616; t=1769026441; h=from : subject : to : message-id : date; bh=1bBRb8rvUmXiBXLsNIGFcB0tqFd9sAVSXXO9H/xLowQ=; b=l1KNJIvCpXz5X6Fb/78S5ZynOuMcVGayZKlcE72kvPYq53C/fcnuFbT5/5bbg4iMVhW87 it6egODUdjZQAtp1VGikL0OrO1jJ7Ny6N/65x5nMEUQVq/728T116Bpm8QPC4cqsq2Q1a7Y JERo4TvS51gSMj0Sbv+wC1kY6Gd+R2S13MfhBOUu/SeE+WZu7nNDliBY4+YQ+MYJtCGs9Qd LlIRHuJKSjcJOZmR1LoSB25y+ShGnYrmyolAxs4YAbPWXGP0bMmZ0XEAd5ymKp7w5yHKkH7 GuV3Fdo1jvZWvMvPubU+PTHo0uQPBhFHlQ7M795f/h/eqZKe6SY+Z4Us8icA== Received: from [10.172.233.45] (helo=SmtpCorp) by smtpcorp.com with esmtpsa (TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.94.2-S2G) (envelope-from ) id 1vieaM-TRk2I3-Ta; Wed, 21 Jan 2026 20:13:50 +0000 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.98.1-S2G) (envelope-from ) id 1vieaM-AIkwcC8tEoU-IKfM; Wed, 21 Jan 2026 20:13: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 v2 3/3] 9p: Enable symlink caching in page cache Date: Wed, 21 Jan 2026 20:56:10 +0100 Message-ID: X-Mailer: git-send-email 2.50.1 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-Smtpcorp-Track: tl-p2at0v3Wy.aoUkW_VmLTPo.QTc-swmgF0f Feedback-ID: 510616m:510616apGKSTK:510616sgw8awW5O5 X-Report-Abuse: Please forward a copy of this message, including all headers, to 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 | 24 ++++++++++++-- fs/9p/vfs_inode.c | 6 ++-- fs/9p/vfs_inode_dotl.c | 73 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 90 insertions(+), 13 deletions(-) diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index 862164181bac..ee672abbb02c 100644 --- a/fs/9p/vfs_addr.c +++ b/fs/9p/vfs_addr.c @@ -70,10 +70,19 @@ 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, err, len, n; + + if (S_ISLNK(rreq->inode->i_mode)) { + err =3D p9_client_readlink(fid, &target); + len =3D strnlen(target, PAGE_SIZE - 1); + n =3D copy_to_iter(target, len, &subreq->io_iter); + if (n !=3D len) + err =3D -EFAULT; + total =3D i_size_read(rreq->inode); + } else + total =3D p9_client_read(fid, pos, &subreq->io_iter, &err); =20 /* if we just extended the file size, any portion not in * cache won't be on server and is zeroes */ @@ -99,6 +108,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 +125,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_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 a82a71be309b..e1b762f3e081 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 6312b3590f74..486b11dbada3 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -686,9 +686,13 @@ v9fs_vfs_symlink_dotl(struct mnt_idmap *idmap, struct = inode *dir, int err; kgid_t gid; const unsigned char *name; + umode_t mode; + struct v9fs_session_info *v9ses; struct p9_qid qid; struct p9_fid *dfid; struct p9_fid *fid =3D NULL; + struct inode *inode; + struct posix_acl *dacl =3D NULL, *pacl =3D NULL; =20 name =3D dentry->d_name.name; p9_debug(P9_DEBUG_VFS, "%lu,%s,%s\n", dir->i_ino, name, symname); @@ -702,6 +706,15 @@ v9fs_vfs_symlink_dotl(struct mnt_idmap *idmap, struct = inode *dir, =20 gid =3D v9fs_get_fsgid_for_create(dir); =20 + /* Update mode based on ACL value */ + err =3D v9fs_acl_mode(dir, &mode, &dacl, &pacl); + if (err) { + p9_debug(P9_DEBUG_VFS, + "Failed to get acl values in symlink %d\n", + err); + goto error; + } + /* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */ err =3D p9_client_symlink(dfid, name, symname, gid, &qid); =20 @@ -712,8 +725,30 @@ 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_set_create_acl(inode, fid, dacl, pacl); + v9fs_fid_add(dentry, &fid); + d_instantiate(dentry, inode); + err =3D 0; error: p9_fid_put(fid); + v9fs_put_acl(dacl, pacl); p9_fid_put(dfid); return err; } @@ -853,24 +888,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); @@ -884,6 +918,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.50.1