Skip to content

Commit

Permalink
Merge tag '9p-for-5.19-rc4' of https://github.com/martinetd/linux
Browse files Browse the repository at this point in the history
Pull 9pfs fixes from Dominique Martinet:
 "A couple of fid refcount and fscache fixes:

   - fid refcounting was incorrect in some corner cases and would leak
     resources, only freed at umount time. The first three commits fix
     three such cases

   - 'cache=loose' or fscache was broken when trying to write a partial
     page to a file with no read permission since the rework a few
     releases ago.

     The fix taken here is just to restore old behavior of using the
     special 'writeback_fid' for such reads, which is open as root/RDWR
     and such not get complains that we try to read on a WRONLY fid.

     Long-term it'd be nice to get rid of this and not issue the read at
     all (skip cache?) in such cases, but that direction hasn't
     progressed"

* tag '9p-for-5.19-rc4' of https://github.com/martinetd/linux:
  9p: fix EBADF errors in cached mode
  9p: Fix refcounting during full path walks for fid lookups
  9p: fix fid refcount leak in v9fs_vfs_get_link
  9p: fix fid refcount leak in v9fs_vfs_atomic_open_dotl
  • Loading branch information
Linus Torvalds committed Jun 22, 2022
2 parents ca1fdab + b001760 commit 3abc3ae
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 17 deletions.
22 changes: 9 additions & 13 deletions fs/9p/fid.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry,
const unsigned char **wnames, *uname;
int i, n, l, clone, access;
struct v9fs_session_info *v9ses;
struct p9_fid *fid, *old_fid = NULL;
struct p9_fid *fid, *old_fid;

v9ses = v9fs_dentry2v9ses(dentry);
access = v9ses->flags & V9FS_ACCESS_MASK;
Expand Down Expand Up @@ -194,13 +194,12 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry,
if (IS_ERR(fid))
return fid;

refcount_inc(&fid->count);
v9fs_fid_add(dentry->d_sb->s_root, fid);
}
/* If we are root ourself just return that */
if (dentry->d_sb->s_root == dentry) {
refcount_inc(&fid->count);
if (dentry->d_sb->s_root == dentry)
return fid;
}
/*
* Do a multipath walk with attached root.
* When walking parent we need to make sure we
Expand All @@ -212,6 +211,7 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry,
fid = ERR_PTR(n);
goto err_out;
}
old_fid = fid;
clone = 1;
i = 0;
while (i < n) {
Expand All @@ -221,19 +221,15 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry,
* walk to ensure none of the patch component change
*/
fid = p9_client_walk(fid, l, &wnames[i], clone);
/* non-cloning walk will return the same fid */
if (fid != old_fid) {
p9_client_clunk(old_fid);
old_fid = fid;
}
if (IS_ERR(fid)) {
if (old_fid) {
/*
* If we fail, clunk fid which are mapping
* to path component and not the last component
* of the path.
*/
p9_client_clunk(old_fid);
}
kfree(wnames);
goto err_out;
}
old_fid = fid;
i += l;
clone = 0;
}
Expand Down
13 changes: 13 additions & 0 deletions fs/9p/vfs_addr.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,21 @@ static void v9fs_issue_read(struct netfs_io_subrequest *subreq)
*/
static int v9fs_init_request(struct netfs_io_request *rreq, struct file *file)
{
struct inode *inode = file_inode(file);
struct v9fs_inode *v9inode = V9FS_I(inode);
struct p9_fid *fid = file->private_data;

BUG_ON(!fid);

/* we might need to read from a fid that was opened write-only
* for read-modify-write of page cache, use the writeback fid
* for that */
if (rreq->origin == NETFS_READ_FOR_WRITE &&
(fid->mode & O_ACCMODE) == O_WRONLY) {
fid = v9inode->writeback_fid;
BUG_ON(!fid);
}

refcount_inc(&fid->count);
rreq->netfs_priv = fid;
return 0;
Expand Down
8 changes: 4 additions & 4 deletions fs/9p/vfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1251,15 +1251,15 @@ static const char *v9fs_vfs_get_link(struct dentry *dentry,
return ERR_PTR(-ECHILD);

v9ses = v9fs_dentry2v9ses(dentry);
fid = v9fs_fid_lookup(dentry);
if (!v9fs_proto_dotu(v9ses))
return ERR_PTR(-EBADF);

p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
fid = v9fs_fid_lookup(dentry);

if (IS_ERR(fid))
return ERR_CAST(fid);

if (!v9fs_proto_dotu(v9ses))
return ERR_PTR(-EBADF);

st = p9_client_stat(fid);
p9_client_clunk(fid);
if (IS_ERR(st))
Expand Down
3 changes: 3 additions & 0 deletions fs/9p/vfs_inode_dotl.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
if (IS_ERR(ofid)) {
err = PTR_ERR(ofid);
p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
p9_client_clunk(dfid);
goto out;
}

Expand All @@ -285,13 +286,15 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
if (err) {
p9_debug(P9_DEBUG_VFS, "Failed to get acl values in creat %d\n",
err);
p9_client_clunk(dfid);
goto error;
}
err = p9_client_create_dotl(ofid, name, v9fs_open_to_dotl_flags(flags),
mode, gid, &qid);
if (err < 0) {
p9_debug(P9_DEBUG_VFS, "p9_client_open_dotl failed in creat %d\n",
err);
p9_client_clunk(dfid);
goto error;
}
v9fs_invalidate_inode_attr(dir);
Expand Down

0 comments on commit 3abc3ae

Please sign in to comment.