Skip to content

Commit 1543b4c

Browse files
committed
fs/9p: remove writeback fid and fix per-file modes
This patch removes the creating of an additional writeback_fid for opened files. The patch addresses problems when files were opened write-only or getattr on files with dirty caches. This patch also incorporates information about cache behavior in the fid for every file. This allows us to reflect cache behavior from mount flags, open mode, and information from the server to inform readahead and writeback behavior. This includes adding support for a 9p semantic that qid.version==0 is used to mark a file as non-cachable which is important for synthetic files. This may have a side-effect of not supporting caching on certain legacy file servers that do not properly set qid.version. There is also now a mount flag which can disable the qid.version behavior. Signed-off-by: Eric Van Hensbergen <ericvh@kernel.org>
1 parent 6deffc8 commit 1543b4c

8 files changed

Lines changed: 135 additions & 186 deletions

File tree

fs/9p/fid.c

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,24 @@ void v9fs_fid_add(struct dentry *dentry, struct p9_fid **pfid)
4141
*pfid = NULL;
4242
}
4343

44+
static bool v9fs_is_writeable(int mode)
45+
{
46+
if (mode & (P9_OWRITE|P9_ORDWR))
47+
return true;
48+
else
49+
return false;
50+
}
51+
4452
/**
4553
* v9fs_fid_find_inode - search for an open fid off of the inode list
4654
* @inode: return a fid pointing to a specific inode
55+
* @want_writeable: only consider fids which are writeable
4756
* @uid: return a fid belonging to the specified user
57+
* @any: ignore uid as a selection criteria
4858
*
4959
*/
50-
51-
static struct p9_fid *v9fs_fid_find_inode(struct inode *inode, kuid_t uid)
60+
struct p9_fid *v9fs_fid_find_inode(struct inode *inode, bool want_writeable,
61+
kuid_t uid, bool any)
5262
{
5363
struct hlist_head *h;
5464
struct p9_fid *fid, *ret = NULL;
@@ -58,7 +68,12 @@ static struct p9_fid *v9fs_fid_find_inode(struct inode *inode, kuid_t uid)
5868
spin_lock(&inode->i_lock);
5969
h = (struct hlist_head *)&inode->i_private;
6070
hlist_for_each_entry(fid, h, ilist) {
61-
if (uid_eq(fid->uid, uid)) {
71+
if (any || uid_eq(fid->uid, uid)) {
72+
if (want_writeable && !v9fs_is_writeable(fid->mode)) {
73+
p9_debug(P9_DEBUG_VFS, " mode: %x not writeable?\n",
74+
fid->mode);
75+
continue;
76+
}
6277
p9_fid_get(fid);
6378
ret = fid;
6479
break;
@@ -118,7 +133,7 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)
118133
spin_unlock(&dentry->d_lock);
119134
} else {
120135
if (dentry->d_inode)
121-
ret = v9fs_fid_find_inode(dentry->d_inode, uid);
136+
ret = v9fs_fid_find_inode(dentry->d_inode, false, uid, any);
122137
}
123138

124139
return ret;
@@ -299,28 +314,3 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
299314
return v9fs_fid_lookup_with_uid(dentry, uid, any);
300315
}
301316

302-
struct p9_fid *v9fs_writeback_fid(struct dentry *dentry)
303-
{
304-
int err;
305-
struct p9_fid *fid, *ofid;
306-
307-
ofid = v9fs_fid_lookup_with_uid(dentry, GLOBAL_ROOT_UID, 0);
308-
fid = clone_fid(ofid);
309-
if (IS_ERR(fid))
310-
goto error_out;
311-
p9_fid_put(ofid);
312-
/*
313-
* writeback fid will only be used to write back the
314-
* dirty pages. We always request for the open fid in read-write
315-
* mode so that a partial page write which result in page
316-
* read can work.
317-
*/
318-
err = p9_client_open(fid, O_RDWR);
319-
if (err < 0) {
320-
p9_fid_put(fid);
321-
fid = ERR_PTR(err);
322-
goto error_out;
323-
}
324-
error_out:
325-
return fid;
326-
}

fs/9p/fid.h

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@
77
#ifndef FS_9P_FID_H
88
#define FS_9P_FID_H
99
#include <linux/list.h>
10+
#include "v9fs.h"
1011

12+
struct p9_fid *v9fs_fid_find_inode(struct inode *inode, bool want_writeable,
13+
kuid_t uid, bool any);
1114
struct p9_fid *v9fs_fid_lookup(struct dentry *dentry);
1215
static inline struct p9_fid *v9fs_parent_fid(struct dentry *dentry)
1316
{
1417
return v9fs_fid_lookup(dentry->d_parent);
1518
}
1619
void v9fs_fid_add(struct dentry *dentry, struct p9_fid **fid);
17-
struct p9_fid *v9fs_writeback_fid(struct dentry *dentry);
1820
void v9fs_open_fid_add(struct inode *inode, struct p9_fid **fid);
1921
static inline struct p9_fid *clone_fid(struct p9_fid *fid)
2022
{
@@ -32,4 +34,33 @@ static inline struct p9_fid *v9fs_fid_clone(struct dentry *dentry)
3234
p9_fid_put(fid);
3335
return nfid;
3436
}
37+
/**
38+
* v9fs_fid_addmodes - add cache flags to fid mode (for client use only)
39+
* @fid: fid to augment
40+
* @s_flags: session info mount flags
41+
* @s_cache: session info cache flags
42+
* @f_flags: unix open flags
43+
*
44+
* make sure mode reflects flags of underlying mounts
45+
* also qid.version == 0 reflects a synthetic or legacy file system
46+
* NOTE: these are set after open so only reflect 9p client not
47+
* underlying file system on server.
48+
*/
49+
static inline void v9fs_fid_add_modes(struct p9_fid *fid, int s_flags,
50+
int s_cache, unsigned int f_flags)
51+
{
52+
if (fid->qid.type != P9_QTFILE)
53+
return;
54+
55+
if ((!s_cache) ||
56+
((fid->qid.version == 0) && !(s_flags & V9FS_IGNORE_QV)) ||
57+
(s_flags & V9FS_DIRECT_IO) || (f_flags & O_DIRECT)) {
58+
fid->mode |= P9L_DIRECT; /* no read or write cache */
59+
} else if ((s_cache < CACHE_WRITEBACK) ||
60+
(f_flags & O_DSYNC) | (s_flags & V9FS_SYNC)) {
61+
fid->mode |= P9L_NOWRITECACHE;
62+
} else if (s_cache == CACHE_LOOSE) {
63+
fid->mode |= P9L_LOOSE; /* noncoherent cache */
64+
}
65+
}
3566
#endif

fs/9p/v9fs.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ struct v9fs_inode {
118118
struct netfs_inode netfs; /* Netfslib context and vfs inode */
119119
struct p9_qid qid;
120120
unsigned int cache_validity;
121-
struct p9_fid *writeback_fid;
122121
struct mutex v_mutex;
123122
};
124123

fs/9p/vfs_addr.c

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,20 +57,15 @@ static void v9fs_issue_read(struct netfs_io_subrequest *subreq)
5757
*/
5858
static int v9fs_init_request(struct netfs_io_request *rreq, struct file *file)
5959
{
60-
struct inode *inode = file_inode(file);
61-
struct v9fs_inode *v9inode = V9FS_I(inode);
6260
struct p9_fid *fid = file->private_data;
6361

6462
BUG_ON(!fid);
6563

6664
/* we might need to read from a fid that was opened write-only
6765
* for read-modify-write of page cache, use the writeback fid
6866
* for that */
69-
if (rreq->origin == NETFS_READ_FOR_WRITE &&
70-
(fid->mode & O_ACCMODE) == O_WRONLY) {
71-
fid = v9inode->writeback_fid;
72-
BUG_ON(!fid);
73-
}
67+
WARN_ON(rreq->origin == NETFS_READ_FOR_WRITE &&
68+
!(fid->mode & P9_ORDWR));
7469

7570
p9_fid_get(fid);
7671
rreq->netfs_priv = fid;
@@ -164,6 +159,7 @@ static int v9fs_vfs_write_folio_locked(struct folio *folio)
164159
loff_t i_size = i_size_read(inode);
165160
struct iov_iter from;
166161
size_t len = folio_size(folio);
162+
struct p9_fid *writeback_fid;
167163
int err;
168164

169165
if (start >= i_size)
@@ -173,13 +169,17 @@ static int v9fs_vfs_write_folio_locked(struct folio *folio)
173169

174170
iov_iter_xarray(&from, ITER_SOURCE, &folio_mapping(folio)->i_pages, start, len);
175171

176-
/* We should have writeback_fid always set */
177-
BUG_ON(!v9inode->writeback_fid);
172+
writeback_fid = v9fs_fid_find_inode(inode, true, INVALID_UID, true);
173+
if (!writeback_fid) {
174+
WARN_ONCE(1, "folio expected an open fid inode->i_private=%p\n",
175+
inode->i_private);
176+
return -EINVAL;
177+
}
178178

179179
folio_wait_fscache(folio);
180180
folio_start_writeback(folio);
181181

182-
p9_client_write(v9inode->writeback_fid, start, &from, &err);
182+
p9_client_write(writeback_fid, start, &from, &err);
183183

184184
if (err == 0 &&
185185
fscache_cookie_enabled(cookie) &&
@@ -192,6 +192,8 @@ static int v9fs_vfs_write_folio_locked(struct folio *folio)
192192
}
193193

194194
folio_end_writeback(folio);
195+
p9_fid_put(writeback_fid);
196+
195197
return err;
196198
}
197199

fs/9p/vfs_file.c

Lines changed: 31 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
4343
int err;
4444
struct v9fs_inode *v9inode;
4545
struct v9fs_session_info *v9ses;
46-
struct p9_fid *fid, *writeback_fid;
46+
struct p9_fid *fid;
4747
int omode;
4848

4949
p9_debug(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file);
@@ -60,7 +60,19 @@ int v9fs_file_open(struct inode *inode, struct file *file)
6060
if (IS_ERR(fid))
6161
return PTR_ERR(fid);
6262

63-
err = p9_client_open(fid, omode);
63+
if ((v9ses->cache >= CACHE_WRITEBACK) && (omode & P9_OWRITE)) {
64+
int writeback_omode = (omode & ~P9_OWRITE) | P9_ORDWR;
65+
66+
p9_debug(P9_DEBUG_CACHE, "write-only file with writeback enabled, try opening O_RDWR\n");
67+
err = p9_client_open(fid, writeback_omode);
68+
if (err < 0) {
69+
p9_debug(P9_DEBUG_CACHE, "could not open O_RDWR, disabling caches\n");
70+
err = p9_client_open(fid, omode);
71+
fid->mode |= P9L_DIRECT;
72+
}
73+
} else {
74+
err = p9_client_open(fid, omode);
75+
}
6476
if (err < 0) {
6577
p9_fid_put(fid);
6678
return err;
@@ -72,36 +84,14 @@ int v9fs_file_open(struct inode *inode, struct file *file)
7284
file->private_data = fid;
7385
}
7486

75-
mutex_lock(&v9inode->v_mutex);
76-
if ((v9ses->cache >= CACHE_WRITEBACK) && !v9inode->writeback_fid &&
77-
((file->f_flags & O_ACCMODE) != O_RDONLY)) {
78-
/*
79-
* clone a fid and add it to writeback_fid
80-
* we do it during open time instead of
81-
* page dirty time via write_begin/page_mkwrite
82-
* because we want write after unlink usecase
83-
* to work.
84-
*/
85-
writeback_fid = v9fs_writeback_fid(file_dentry(file));
86-
if (IS_ERR(writeback_fid)) {
87-
err = PTR_ERR(writeback_fid);
88-
mutex_unlock(&v9inode->v_mutex);
89-
goto out_error;
90-
}
91-
v9inode->writeback_fid = (void *) writeback_fid;
92-
}
93-
mutex_unlock(&v9inode->v_mutex);
9487
#ifdef CONFIG_9P_FSCACHE
9588
if (v9ses->cache == CACHE_FSCACHE)
9689
fscache_use_cookie(v9fs_inode_cookie(v9inode),
9790
file->f_mode & FMODE_WRITE);
9891
#endif
92+
v9fs_fid_add_modes(fid, v9ses->flags, v9ses->cache, file->f_flags);
9993
v9fs_open_fid_add(inode, &fid);
10094
return 0;
101-
out_error:
102-
p9_fid_put(file->private_data);
103-
file->private_data = NULL;
104-
return err;
10595
}
10696

10797
/**
@@ -367,14 +357,14 @@ v9fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
367357
{
368358
struct p9_fid *fid = iocb->ki_filp->private_data;
369359
int ret, err = 0;
370-
struct inode *inode = file_inode(iocb->ki_filp);
371-
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
372360

373-
p9_debug(P9_DEBUG_VFS, "count %zu offset %lld\n",
374-
iov_iter_count(to), iocb->ki_pos);
361+
p9_debug(P9_DEBUG_VFS, "fid %d count %zu offset %lld\n",
362+
fid->fid, iov_iter_count(to), iocb->ki_pos);
375363

376-
if (v9ses->cache > CACHE_MMAP)
364+
if (!(fid->mode & P9L_DIRECT)) {
365+
p9_debug(P9_DEBUG_VFS, "(cached)\n");
377366
return generic_file_read_iter(iocb, to);
367+
}
378368

379369
if (iocb->ki_filp->f_flags & O_NONBLOCK)
380370
ret = p9_client_read_once(fid, iocb->ki_pos, to, &err);
@@ -397,14 +387,17 @@ static ssize_t
397387
v9fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
398388
{
399389
struct file *file = iocb->ki_filp;
390+
struct p9_fid *fid = file->private_data;
400391
ssize_t retval;
401392
loff_t origin;
402393
int err = 0;
403-
struct inode *inode = file_inode(iocb->ki_filp);
404-
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
405394

406-
if (v9ses->cache >= CACHE_WRITEBACK)
395+
p9_debug(P9_DEBUG_VFS, "fid %d\n", fid->fid);
396+
397+
if (!(fid->mode & (P9L_DIRECT | P9L_NOWRITECACHE))) {
398+
p9_debug(P9_DEBUG_CACHE, "(cached)\n");
407399
return generic_file_write_iter(iocb, from);
400+
}
408401

409402
retval = generic_write_checks(iocb, from);
410403
if (retval <= 0)
@@ -488,36 +481,18 @@ v9fs_file_mmap(struct file *filp, struct vm_area_struct *vma)
488481
{
489482
int retval;
490483
struct inode *inode = file_inode(filp);
491-
struct v9fs_inode *v9inode = V9FS_I(inode);
492484
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
493-
struct p9_fid *fid;
485+
486+
p9_debug(P9_DEBUG_MMAP, "filp :%p\n", filp);
494487

495488
if (v9ses->cache < CACHE_MMAP) {
489+
p9_debug(P9_DEBUG_CACHE, "(no mmap mode)");
490+
if (vma->vm_flags & VM_MAYSHARE)
491+
return -ENODEV;
496492
invalidate_inode_pages2(filp->f_mapping);
497493
return generic_file_readonly_mmap(filp, vma);
498494
}
499495

500-
mutex_lock(&v9inode->v_mutex);
501-
if (!v9inode->writeback_fid &&
502-
(vma->vm_flags & VM_SHARED) &&
503-
(vma->vm_flags & VM_WRITE)) {
504-
/*
505-
* clone a fid and add it to writeback_fid
506-
* we do it during mmap instead of
507-
* page dirty time via write_begin/page_mkwrite
508-
* because we want write after unlink usecase
509-
* to work.
510-
*/
511-
fid = v9fs_writeback_fid(file_dentry(filp));
512-
if (IS_ERR(fid)) {
513-
retval = PTR_ERR(fid);
514-
mutex_unlock(&v9inode->v_mutex);
515-
return retval;
516-
}
517-
v9inode->writeback_fid = (void *) fid;
518-
}
519-
mutex_unlock(&v9inode->v_mutex);
520-
521496
retval = generic_file_mmap(filp, vma);
522497
if (!retval)
523498
vma->vm_ops = &v9fs_mmap_file_vm_ops;
@@ -528,7 +503,6 @@ v9fs_file_mmap(struct file *filp, struct vm_area_struct *vma)
528503
static vm_fault_t
529504
v9fs_vm_page_mkwrite(struct vm_fault *vmf)
530505
{
531-
struct v9fs_inode *v9inode;
532506
struct folio *folio = page_folio(vmf->page);
533507
struct file *filp = vmf->vma->vm_file;
534508
struct inode *inode = file_inode(filp);
@@ -537,8 +511,6 @@ v9fs_vm_page_mkwrite(struct vm_fault *vmf)
537511
p9_debug(P9_DEBUG_VFS, "folio %p fid %lx\n",
538512
folio, (unsigned long)filp->private_data);
539513

540-
v9inode = V9FS_I(inode);
541-
542514
/* Wait for the page to be written to the cache before we allow it to
543515
* be modified. We then assume the entire page will need writing back.
544516
*/
@@ -551,7 +523,6 @@ v9fs_vm_page_mkwrite(struct vm_fault *vmf)
551523
/* Update file times before taking page lock */
552524
file_update_time(filp);
553525

554-
BUG_ON(!v9inode->writeback_fid);
555526
if (folio_lock_killable(folio) < 0)
556527
return VM_FAULT_RETRY;
557528
if (folio_mapping(folio) != inode->i_mapping)

0 commit comments

Comments
 (0)