Skip to content

Commit 3abc3ae

Browse files
committed
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
2 parents ca1fdab + b001760 commit 3abc3ae

File tree

4 files changed

+29
-17
lines changed

4 files changed

+29
-17
lines changed

fs/9p/fid.c

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry,
152152
const unsigned char **wnames, *uname;
153153
int i, n, l, clone, access;
154154
struct v9fs_session_info *v9ses;
155-
struct p9_fid *fid, *old_fid = NULL;
155+
struct p9_fid *fid, *old_fid;
156156

157157
v9ses = v9fs_dentry2v9ses(dentry);
158158
access = v9ses->flags & V9FS_ACCESS_MASK;
@@ -194,13 +194,12 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry,
194194
if (IS_ERR(fid))
195195
return fid;
196196

197+
refcount_inc(&fid->count);
197198
v9fs_fid_add(dentry->d_sb->s_root, fid);
198199
}
199200
/* If we are root ourself just return that */
200-
if (dentry->d_sb->s_root == dentry) {
201-
refcount_inc(&fid->count);
201+
if (dentry->d_sb->s_root == dentry)
202202
return fid;
203-
}
204203
/*
205204
* Do a multipath walk with attached root.
206205
* 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,
212211
fid = ERR_PTR(n);
213212
goto err_out;
214213
}
214+
old_fid = fid;
215215
clone = 1;
216216
i = 0;
217217
while (i < n) {
@@ -221,19 +221,15 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry,
221221
* walk to ensure none of the patch component change
222222
*/
223223
fid = p9_client_walk(fid, l, &wnames[i], clone);
224+
/* non-cloning walk will return the same fid */
225+
if (fid != old_fid) {
226+
p9_client_clunk(old_fid);
227+
old_fid = fid;
228+
}
224229
if (IS_ERR(fid)) {
225-
if (old_fid) {
226-
/*
227-
* If we fail, clunk fid which are mapping
228-
* to path component and not the last component
229-
* of the path.
230-
*/
231-
p9_client_clunk(old_fid);
232-
}
233230
kfree(wnames);
234231
goto err_out;
235232
}
236-
old_fid = fid;
237233
i += l;
238234
clone = 0;
239235
}

fs/9p/vfs_addr.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,21 @@ static void v9fs_issue_read(struct netfs_io_subrequest *subreq)
5858
*/
5959
static int v9fs_init_request(struct netfs_io_request *rreq, struct file *file)
6060
{
61+
struct inode *inode = file_inode(file);
62+
struct v9fs_inode *v9inode = V9FS_I(inode);
6163
struct p9_fid *fid = file->private_data;
6264

65+
BUG_ON(!fid);
66+
67+
/* we might need to read from a fid that was opened write-only
68+
* for read-modify-write of page cache, use the writeback fid
69+
* for that */
70+
if (rreq->origin == NETFS_READ_FOR_WRITE &&
71+
(fid->mode & O_ACCMODE) == O_WRONLY) {
72+
fid = v9inode->writeback_fid;
73+
BUG_ON(!fid);
74+
}
75+
6376
refcount_inc(&fid->count);
6477
rreq->netfs_priv = fid;
6578
return 0;

fs/9p/vfs_inode.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,15 +1251,15 @@ static const char *v9fs_vfs_get_link(struct dentry *dentry,
12511251
return ERR_PTR(-ECHILD);
12521252

12531253
v9ses = v9fs_dentry2v9ses(dentry);
1254-
fid = v9fs_fid_lookup(dentry);
1254+
if (!v9fs_proto_dotu(v9ses))
1255+
return ERR_PTR(-EBADF);
1256+
12551257
p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
1258+
fid = v9fs_fid_lookup(dentry);
12561259

12571260
if (IS_ERR(fid))
12581261
return ERR_CAST(fid);
12591262

1260-
if (!v9fs_proto_dotu(v9ses))
1261-
return ERR_PTR(-EBADF);
1262-
12631263
st = p9_client_stat(fid);
12641264
p9_client_clunk(fid);
12651265
if (IS_ERR(st))

fs/9p/vfs_inode_dotl.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
274274
if (IS_ERR(ofid)) {
275275
err = PTR_ERR(ofid);
276276
p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
277+
p9_client_clunk(dfid);
277278
goto out;
278279
}
279280

@@ -285,13 +286,15 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
285286
if (err) {
286287
p9_debug(P9_DEBUG_VFS, "Failed to get acl values in creat %d\n",
287288
err);
289+
p9_client_clunk(dfid);
288290
goto error;
289291
}
290292
err = p9_client_create_dotl(ofid, name, v9fs_open_to_dotl_flags(flags),
291293
mode, gid, &qid);
292294
if (err < 0) {
293295
p9_debug(P9_DEBUG_VFS, "p9_client_open_dotl failed in creat %d\n",
294296
err);
297+
p9_client_clunk(dfid);
295298
goto error;
296299
}
297300
v9fs_invalidate_inode_attr(dir);

0 commit comments

Comments
 (0)