Commit 3abc3ae5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '9p-for-5.19-rc4' of https://github.com/martinetd/linux

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
parents ca1fdab7 b0017602
Loading
Loading
Loading
Loading
+9 −13
Original line number Diff line number Diff line
@@ -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;
@@ -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
@@ -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) {
@@ -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);
		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.
				 */
		/* non-cloning walk will return the same fid */
		if (fid != old_fid) {
			p9_client_clunk(old_fid);
			old_fid = fid;
		}
		if (IS_ERR(fid)) {
			kfree(wnames);
			goto err_out;
		}
		old_fid = fid;
		i += l;
		clone = 0;
	}
+13 −0
Original line number Diff line number Diff line
@@ -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;
+4 −4
Original line number Diff line number Diff line
@@ -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))
+3 −0
Original line number Diff line number Diff line
@@ -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;
	}

@@ -285,6 +286,7 @@ 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),
@@ -292,6 +294,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
	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);