mirror of
https://github.com/torvalds/linux.git
synced 2026-10-25 08:16:03 +01:00
9p: Enable symlink caching in page cache
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> Message-ID: <982462d17c0c0d2856763266a25eb04d080c1dbb.1779355927.git.repk@triplefau.lt> Signed-off-by: Dominique Martinet <asmadeus@codewreck.org>
This commit is contained in:
parent
15bbf82857
commit
712da38d13
|
|
@ -70,11 +70,34 @@ static void v9fs_issue_read(struct netfs_io_subrequest *subreq)
|
||||||
{
|
{
|
||||||
struct netfs_io_request *rreq = subreq->rreq;
|
struct netfs_io_request *rreq = subreq->rreq;
|
||||||
struct p9_fid *fid = rreq->netfs_priv;
|
struct p9_fid *fid = rreq->netfs_priv;
|
||||||
|
char *target;
|
||||||
unsigned long long pos = subreq->start + subreq->transferred;
|
unsigned long long pos = subreq->start + subreq->transferred;
|
||||||
int total, err;
|
int total = 0, err, len, n;
|
||||||
|
|
||||||
total = p9_client_read(fid, pos, &subreq->io_iter, &err);
|
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 = -EIO;
|
||||||
|
goto fill_subreq;
|
||||||
|
}
|
||||||
|
err = p9_client_readlink(fid, &target);
|
||||||
|
if (err != 0)
|
||||||
|
goto fill_subreq;
|
||||||
|
len = strlen(target);
|
||||||
|
n = copy_to_iter(target, len, &subreq->io_iter);
|
||||||
|
kfree(target);
|
||||||
|
total = n;
|
||||||
|
} else {
|
||||||
|
total = p9_client_read(fid, pos, &subreq->io_iter, &err);
|
||||||
|
}
|
||||||
|
|
||||||
|
fill_subreq:
|
||||||
/* if we just extended the file size, any portion not in
|
/* if we just extended the file size, any portion not in
|
||||||
* cache won't be on server and is zeroes */
|
* cache won't be on server and is zeroes */
|
||||||
if (subreq->rreq->origin != NETFS_UNBUFFERED_READ &&
|
if (subreq->rreq->origin != NETFS_UNBUFFERED_READ &&
|
||||||
|
|
@ -99,6 +122,7 @@ static void v9fs_issue_read(struct netfs_io_subrequest *subreq)
|
||||||
static int v9fs_init_request(struct netfs_io_request *rreq, struct file *file)
|
static int v9fs_init_request(struct netfs_io_request *rreq, struct file *file)
|
||||||
{
|
{
|
||||||
struct p9_fid *fid;
|
struct p9_fid *fid;
|
||||||
|
struct dentry *dentry;
|
||||||
bool writing = (rreq->origin == NETFS_READ_FOR_WRITE ||
|
bool writing = (rreq->origin == NETFS_READ_FOR_WRITE ||
|
||||||
rreq->origin == NETFS_WRITETHROUGH ||
|
rreq->origin == NETFS_WRITETHROUGH ||
|
||||||
rreq->origin == NETFS_UNBUFFERED_WRITE ||
|
rreq->origin == NETFS_UNBUFFERED_WRITE ||
|
||||||
|
|
@ -115,6 +139,14 @@ static int v9fs_init_request(struct netfs_io_request *rreq, struct file *file)
|
||||||
if (!fid)
|
if (!fid)
|
||||||
goto no_fid;
|
goto no_fid;
|
||||||
p9_fid_get(fid);
|
p9_fid_get(fid);
|
||||||
|
} else if (S_ISLNK(rreq->inode->i_mode)) {
|
||||||
|
dentry = d_find_any_alias(rreq->inode);
|
||||||
|
if (!dentry)
|
||||||
|
goto no_fid;
|
||||||
|
fid = v9fs_fid_lookup(dentry);
|
||||||
|
dput(dentry);
|
||||||
|
if (IS_ERR(fid))
|
||||||
|
goto no_fid;
|
||||||
} else {
|
} else {
|
||||||
fid = v9fs_fid_find_inode(rreq->inode, writing, INVALID_UID, true);
|
fid = v9fs_fid_find_inode(rreq->inode, writing, INVALID_UID, true);
|
||||||
if (!fid)
|
if (!fid)
|
||||||
|
|
|
||||||
|
|
@ -302,10 +302,12 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v9fs_proto_dotl(v9ses))
|
if (v9fs_proto_dotl(v9ses)) {
|
||||||
inode->i_op = &v9fs_symlink_inode_operations_dotl;
|
inode->i_op = &v9fs_symlink_inode_operations_dotl;
|
||||||
else
|
inode_nohighmem(inode);
|
||||||
|
} else {
|
||||||
inode->i_op = &v9fs_symlink_inode_operations;
|
inode->i_op = &v9fs_symlink_inode_operations;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case S_IFDIR:
|
case S_IFDIR:
|
||||||
|
|
|
||||||
|
|
@ -686,9 +686,11 @@ v9fs_vfs_symlink_dotl(struct mnt_idmap *idmap, struct inode *dir,
|
||||||
int err;
|
int err;
|
||||||
kgid_t gid;
|
kgid_t gid;
|
||||||
const unsigned char *name;
|
const unsigned char *name;
|
||||||
|
struct v9fs_session_info *v9ses;
|
||||||
struct p9_qid qid;
|
struct p9_qid qid;
|
||||||
struct p9_fid *dfid;
|
struct p9_fid *dfid;
|
||||||
struct p9_fid *fid = NULL;
|
struct p9_fid *fid = NULL;
|
||||||
|
struct inode *inode;
|
||||||
|
|
||||||
name = dentry->d_name.name;
|
name = dentry->d_name.name;
|
||||||
p9_debug(P9_DEBUG_VFS, "%lu,%s,%s\n", dir->i_ino, name, symname);
|
p9_debug(P9_DEBUG_VFS, "%lu,%s,%s\n", dir->i_ino, name, symname);
|
||||||
|
|
@ -712,6 +714,26 @@ v9fs_vfs_symlink_dotl(struct mnt_idmap *idmap, struct inode *dir,
|
||||||
|
|
||||||
v9fs_invalidate_inode_attr(dir);
|
v9fs_invalidate_inode_attr(dir);
|
||||||
|
|
||||||
|
/* instantiate inode and assign the unopened fid to the dentry */
|
||||||
|
fid = p9_client_walk(dfid, 1, &name, 1);
|
||||||
|
if (IS_ERR(fid)) {
|
||||||
|
err = PTR_ERR(fid);
|
||||||
|
p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
|
||||||
|
err);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
v9ses = v9fs_inode2v9ses(dir);
|
||||||
|
inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
|
||||||
|
if (IS_ERR(inode)) {
|
||||||
|
err = 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 = 0;
|
||||||
error:
|
error:
|
||||||
p9_fid_put(fid);
|
p9_fid_put(fid);
|
||||||
p9_fid_put(dfid);
|
p9_fid_put(dfid);
|
||||||
|
|
@ -853,16 +875,18 @@ 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
|
* @dentry: dentry for symlink
|
||||||
* @inode: inode for symlink
|
* @inode: inode for symlink
|
||||||
* @done: destructor for return value
|
* @done: destructor for return value
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
v9fs_vfs_get_link_dotl(struct dentry *dentry,
|
v9fs_vfs_get_link_nocache_dotl(struct dentry *dentry,
|
||||||
struct inode *inode,
|
struct inode *inode,
|
||||||
struct delayed_call *done)
|
struct delayed_call *done)
|
||||||
{
|
{
|
||||||
struct p9_fid *fid;
|
struct p9_fid *fid;
|
||||||
char *target;
|
char *target;
|
||||||
|
|
@ -884,6 +908,26 @@ v9fs_vfs_get_link_dotl(struct dentry *dentry,
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
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)
|
int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
|
||||||
{
|
{
|
||||||
struct p9_stat_dotl *st;
|
struct p9_stat_dotl *st;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user