Commit 1543b4c5 authored by Eric Van Hensbergen's avatar Eric Van Hensbergen

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: default avatarEric Van Hensbergen <ericvh@kernel.org>
parent 6deffc89
...@@ -41,14 +41,24 @@ void v9fs_fid_add(struct dentry *dentry, struct p9_fid **pfid) ...@@ -41,14 +41,24 @@ void v9fs_fid_add(struct dentry *dentry, struct p9_fid **pfid)
*pfid = NULL; *pfid = NULL;
} }
static bool v9fs_is_writeable(int mode)
{
if (mode & (P9_OWRITE|P9_ORDWR))
return true;
else
return false;
}
/** /**
* v9fs_fid_find_inode - search for an open fid off of the inode list * v9fs_fid_find_inode - search for an open fid off of the inode list
* @inode: return a fid pointing to a specific inode * @inode: return a fid pointing to a specific inode
* @want_writeable: only consider fids which are writeable
* @uid: return a fid belonging to the specified user * @uid: return a fid belonging to the specified user
* @any: ignore uid as a selection criteria
* *
*/ */
struct p9_fid *v9fs_fid_find_inode(struct inode *inode, bool want_writeable,
static struct p9_fid *v9fs_fid_find_inode(struct inode *inode, kuid_t uid) kuid_t uid, bool any)
{ {
struct hlist_head *h; struct hlist_head *h;
struct p9_fid *fid, *ret = NULL; struct p9_fid *fid, *ret = NULL;
...@@ -58,7 +68,12 @@ static struct p9_fid *v9fs_fid_find_inode(struct inode *inode, kuid_t uid) ...@@ -58,7 +68,12 @@ static struct p9_fid *v9fs_fid_find_inode(struct inode *inode, kuid_t uid)
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
h = (struct hlist_head *)&inode->i_private; h = (struct hlist_head *)&inode->i_private;
hlist_for_each_entry(fid, h, ilist) { hlist_for_each_entry(fid, h, ilist) {
if (uid_eq(fid->uid, uid)) { if (any || uid_eq(fid->uid, uid)) {
if (want_writeable && !v9fs_is_writeable(fid->mode)) {
p9_debug(P9_DEBUG_VFS, " mode: %x not writeable?\n",
fid->mode);
continue;
}
p9_fid_get(fid); p9_fid_get(fid);
ret = fid; ret = fid;
break; break;
...@@ -118,7 +133,7 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any) ...@@ -118,7 +133,7 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, kuid_t uid, int any)
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
} else { } else {
if (dentry->d_inode) if (dentry->d_inode)
ret = v9fs_fid_find_inode(dentry->d_inode, uid); ret = v9fs_fid_find_inode(dentry->d_inode, false, uid, any);
} }
return ret; return ret;
...@@ -299,28 +314,3 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) ...@@ -299,28 +314,3 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
return v9fs_fid_lookup_with_uid(dentry, uid, any); return v9fs_fid_lookup_with_uid(dentry, uid, any);
} }
struct p9_fid *v9fs_writeback_fid(struct dentry *dentry)
{
int err;
struct p9_fid *fid, *ofid;
ofid = v9fs_fid_lookup_with_uid(dentry, GLOBAL_ROOT_UID, 0);
fid = clone_fid(ofid);
if (IS_ERR(fid))
goto error_out;
p9_fid_put(ofid);
/*
* writeback fid will only be used to write back the
* dirty pages. We always request for the open fid in read-write
* mode so that a partial page write which result in page
* read can work.
*/
err = p9_client_open(fid, O_RDWR);
if (err < 0) {
p9_fid_put(fid);
fid = ERR_PTR(err);
goto error_out;
}
error_out:
return fid;
}
...@@ -7,14 +7,16 @@ ...@@ -7,14 +7,16 @@
#ifndef FS_9P_FID_H #ifndef FS_9P_FID_H
#define FS_9P_FID_H #define FS_9P_FID_H
#include <linux/list.h> #include <linux/list.h>
#include "v9fs.h"
struct p9_fid *v9fs_fid_find_inode(struct inode *inode, bool want_writeable,
kuid_t uid, bool any);
struct p9_fid *v9fs_fid_lookup(struct dentry *dentry); struct p9_fid *v9fs_fid_lookup(struct dentry *dentry);
static inline struct p9_fid *v9fs_parent_fid(struct dentry *dentry) static inline struct p9_fid *v9fs_parent_fid(struct dentry *dentry)
{ {
return v9fs_fid_lookup(dentry->d_parent); return v9fs_fid_lookup(dentry->d_parent);
} }
void v9fs_fid_add(struct dentry *dentry, struct p9_fid **fid); void v9fs_fid_add(struct dentry *dentry, struct p9_fid **fid);
struct p9_fid *v9fs_writeback_fid(struct dentry *dentry);
void v9fs_open_fid_add(struct inode *inode, struct p9_fid **fid); void v9fs_open_fid_add(struct inode *inode, struct p9_fid **fid);
static inline struct p9_fid *clone_fid(struct p9_fid *fid) static inline struct p9_fid *clone_fid(struct p9_fid *fid)
{ {
...@@ -32,4 +34,33 @@ static inline struct p9_fid *v9fs_fid_clone(struct dentry *dentry) ...@@ -32,4 +34,33 @@ static inline struct p9_fid *v9fs_fid_clone(struct dentry *dentry)
p9_fid_put(fid); p9_fid_put(fid);
return nfid; return nfid;
} }
/**
* v9fs_fid_addmodes - add cache flags to fid mode (for client use only)
* @fid: fid to augment
* @s_flags: session info mount flags
* @s_cache: session info cache flags
* @f_flags: unix open flags
*
* make sure mode reflects flags of underlying mounts
* also qid.version == 0 reflects a synthetic or legacy file system
* NOTE: these are set after open so only reflect 9p client not
* underlying file system on server.
*/
static inline void v9fs_fid_add_modes(struct p9_fid *fid, int s_flags,
int s_cache, unsigned int f_flags)
{
if (fid->qid.type != P9_QTFILE)
return;
if ((!s_cache) ||
((fid->qid.version == 0) && !(s_flags & V9FS_IGNORE_QV)) ||
(s_flags & V9FS_DIRECT_IO) || (f_flags & O_DIRECT)) {
fid->mode |= P9L_DIRECT; /* no read or write cache */
} else if ((s_cache < CACHE_WRITEBACK) ||
(f_flags & O_DSYNC) | (s_flags & V9FS_SYNC)) {
fid->mode |= P9L_NOWRITECACHE;
} else if (s_cache == CACHE_LOOSE) {
fid->mode |= P9L_LOOSE; /* noncoherent cache */
}
}
#endif #endif
...@@ -118,7 +118,6 @@ struct v9fs_inode { ...@@ -118,7 +118,6 @@ struct v9fs_inode {
struct netfs_inode netfs; /* Netfslib context and vfs inode */ struct netfs_inode netfs; /* Netfslib context and vfs inode */
struct p9_qid qid; struct p9_qid qid;
unsigned int cache_validity; unsigned int cache_validity;
struct p9_fid *writeback_fid;
struct mutex v_mutex; struct mutex v_mutex;
}; };
......
...@@ -57,8 +57,6 @@ static void v9fs_issue_read(struct netfs_io_subrequest *subreq) ...@@ -57,8 +57,6 @@ 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 inode *inode = file_inode(file);
struct v9fs_inode *v9inode = V9FS_I(inode);
struct p9_fid *fid = file->private_data; struct p9_fid *fid = file->private_data;
BUG_ON(!fid); BUG_ON(!fid);
...@@ -66,11 +64,8 @@ static int v9fs_init_request(struct netfs_io_request *rreq, struct file *file) ...@@ -66,11 +64,8 @@ static int v9fs_init_request(struct netfs_io_request *rreq, struct file *file)
/* we might need to read from a fid that was opened write-only /* 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 read-modify-write of page cache, use the writeback fid
* for that */ * for that */
if (rreq->origin == NETFS_READ_FOR_WRITE && WARN_ON(rreq->origin == NETFS_READ_FOR_WRITE &&
(fid->mode & O_ACCMODE) == O_WRONLY) { !(fid->mode & P9_ORDWR));
fid = v9inode->writeback_fid;
BUG_ON(!fid);
}
p9_fid_get(fid); p9_fid_get(fid);
rreq->netfs_priv = fid; rreq->netfs_priv = fid;
...@@ -164,6 +159,7 @@ static int v9fs_vfs_write_folio_locked(struct folio *folio) ...@@ -164,6 +159,7 @@ static int v9fs_vfs_write_folio_locked(struct folio *folio)
loff_t i_size = i_size_read(inode); loff_t i_size = i_size_read(inode);
struct iov_iter from; struct iov_iter from;
size_t len = folio_size(folio); size_t len = folio_size(folio);
struct p9_fid *writeback_fid;
int err; int err;
if (start >= i_size) if (start >= i_size)
...@@ -173,13 +169,17 @@ static int v9fs_vfs_write_folio_locked(struct folio *folio) ...@@ -173,13 +169,17 @@ static int v9fs_vfs_write_folio_locked(struct folio *folio)
iov_iter_xarray(&from, ITER_SOURCE, &folio_mapping(folio)->i_pages, start, len); iov_iter_xarray(&from, ITER_SOURCE, &folio_mapping(folio)->i_pages, start, len);
/* We should have writeback_fid always set */ writeback_fid = v9fs_fid_find_inode(inode, true, INVALID_UID, true);
BUG_ON(!v9inode->writeback_fid); if (!writeback_fid) {
WARN_ONCE(1, "folio expected an open fid inode->i_private=%p\n",
inode->i_private);
return -EINVAL;
}
folio_wait_fscache(folio); folio_wait_fscache(folio);
folio_start_writeback(folio); folio_start_writeback(folio);
p9_client_write(v9inode->writeback_fid, start, &from, &err); p9_client_write(writeback_fid, start, &from, &err);
if (err == 0 && if (err == 0 &&
fscache_cookie_enabled(cookie) && fscache_cookie_enabled(cookie) &&
...@@ -192,6 +192,8 @@ static int v9fs_vfs_write_folio_locked(struct folio *folio) ...@@ -192,6 +192,8 @@ static int v9fs_vfs_write_folio_locked(struct folio *folio)
} }
folio_end_writeback(folio); folio_end_writeback(folio);
p9_fid_put(writeback_fid);
return err; return err;
} }
......
...@@ -43,7 +43,7 @@ int v9fs_file_open(struct inode *inode, struct file *file) ...@@ -43,7 +43,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
int err; int err;
struct v9fs_inode *v9inode; struct v9fs_inode *v9inode;
struct v9fs_session_info *v9ses; struct v9fs_session_info *v9ses;
struct p9_fid *fid, *writeback_fid; struct p9_fid *fid;
int omode; int omode;
p9_debug(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file); 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) ...@@ -60,7 +60,19 @@ int v9fs_file_open(struct inode *inode, struct file *file)
if (IS_ERR(fid)) if (IS_ERR(fid))
return PTR_ERR(fid); return PTR_ERR(fid);
err = p9_client_open(fid, omode); if ((v9ses->cache >= CACHE_WRITEBACK) && (omode & P9_OWRITE)) {
int writeback_omode = (omode & ~P9_OWRITE) | P9_ORDWR;
p9_debug(P9_DEBUG_CACHE, "write-only file with writeback enabled, try opening O_RDWR\n");
err = p9_client_open(fid, writeback_omode);
if (err < 0) {
p9_debug(P9_DEBUG_CACHE, "could not open O_RDWR, disabling caches\n");
err = p9_client_open(fid, omode);
fid->mode |= P9L_DIRECT;
}
} else {
err = p9_client_open(fid, omode);
}
if (err < 0) { if (err < 0) {
p9_fid_put(fid); p9_fid_put(fid);
return err; return err;
...@@ -72,36 +84,14 @@ int v9fs_file_open(struct inode *inode, struct file *file) ...@@ -72,36 +84,14 @@ int v9fs_file_open(struct inode *inode, struct file *file)
file->private_data = fid; file->private_data = fid;
} }
mutex_lock(&v9inode->v_mutex);
if ((v9ses->cache >= CACHE_WRITEBACK) && !v9inode->writeback_fid &&
((file->f_flags & O_ACCMODE) != O_RDONLY)) {
/*
* clone a fid and add it to writeback_fid
* we do it during open time instead of
* page dirty time via write_begin/page_mkwrite
* because we want write after unlink usecase
* to work.
*/
writeback_fid = v9fs_writeback_fid(file_dentry(file));
if (IS_ERR(writeback_fid)) {
err = PTR_ERR(writeback_fid);
mutex_unlock(&v9inode->v_mutex);
goto out_error;
}
v9inode->writeback_fid = (void *) writeback_fid;
}
mutex_unlock(&v9inode->v_mutex);
#ifdef CONFIG_9P_FSCACHE #ifdef CONFIG_9P_FSCACHE
if (v9ses->cache == CACHE_FSCACHE) if (v9ses->cache == CACHE_FSCACHE)
fscache_use_cookie(v9fs_inode_cookie(v9inode), fscache_use_cookie(v9fs_inode_cookie(v9inode),
file->f_mode & FMODE_WRITE); file->f_mode & FMODE_WRITE);
#endif #endif
v9fs_fid_add_modes(fid, v9ses->flags, v9ses->cache, file->f_flags);
v9fs_open_fid_add(inode, &fid); v9fs_open_fid_add(inode, &fid);
return 0; return 0;
out_error:
p9_fid_put(file->private_data);
file->private_data = NULL;
return err;
} }
/** /**
...@@ -367,14 +357,14 @@ v9fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to) ...@@ -367,14 +357,14 @@ v9fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
{ {
struct p9_fid *fid = iocb->ki_filp->private_data; struct p9_fid *fid = iocb->ki_filp->private_data;
int ret, err = 0; int ret, err = 0;
struct inode *inode = file_inode(iocb->ki_filp);
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
p9_debug(P9_DEBUG_VFS, "count %zu offset %lld\n", p9_debug(P9_DEBUG_VFS, "fid %d count %zu offset %lld\n",
iov_iter_count(to), iocb->ki_pos); fid->fid, iov_iter_count(to), iocb->ki_pos);
if (v9ses->cache > CACHE_MMAP) if (!(fid->mode & P9L_DIRECT)) {
p9_debug(P9_DEBUG_VFS, "(cached)\n");
return generic_file_read_iter(iocb, to); return generic_file_read_iter(iocb, to);
}
if (iocb->ki_filp->f_flags & O_NONBLOCK) if (iocb->ki_filp->f_flags & O_NONBLOCK)
ret = p9_client_read_once(fid, iocb->ki_pos, to, &err); ret = p9_client_read_once(fid, iocb->ki_pos, to, &err);
...@@ -397,14 +387,17 @@ static ssize_t ...@@ -397,14 +387,17 @@ static ssize_t
v9fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) v9fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
{ {
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct p9_fid *fid = file->private_data;
ssize_t retval; ssize_t retval;
loff_t origin; loff_t origin;
int err = 0; int err = 0;
struct inode *inode = file_inode(iocb->ki_filp);
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
if (v9ses->cache >= CACHE_WRITEBACK) p9_debug(P9_DEBUG_VFS, "fid %d\n", fid->fid);
if (!(fid->mode & (P9L_DIRECT | P9L_NOWRITECACHE))) {
p9_debug(P9_DEBUG_CACHE, "(cached)\n");
return generic_file_write_iter(iocb, from); return generic_file_write_iter(iocb, from);
}
retval = generic_write_checks(iocb, from); retval = generic_write_checks(iocb, from);
if (retval <= 0) if (retval <= 0)
...@@ -488,36 +481,18 @@ v9fs_file_mmap(struct file *filp, struct vm_area_struct *vma) ...@@ -488,36 +481,18 @@ v9fs_file_mmap(struct file *filp, struct vm_area_struct *vma)
{ {
int retval; int retval;
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
struct v9fs_inode *v9inode = V9FS_I(inode);
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
struct p9_fid *fid;
p9_debug(P9_DEBUG_MMAP, "filp :%p\n", filp);
if (v9ses->cache < CACHE_MMAP) { if (v9ses->cache < CACHE_MMAP) {
p9_debug(P9_DEBUG_CACHE, "(no mmap mode)");
if (vma->vm_flags & VM_MAYSHARE)
return -ENODEV;
invalidate_inode_pages2(filp->f_mapping); invalidate_inode_pages2(filp->f_mapping);
return generic_file_readonly_mmap(filp, vma); return generic_file_readonly_mmap(filp, vma);
} }
mutex_lock(&v9inode->v_mutex);
if (!v9inode->writeback_fid &&
(vma->vm_flags & VM_SHARED) &&
(vma->vm_flags & VM_WRITE)) {
/*
* clone a fid and add it to writeback_fid
* we do it during mmap instead of
* page dirty time via write_begin/page_mkwrite
* because we want write after unlink usecase
* to work.
*/
fid = v9fs_writeback_fid(file_dentry(filp));
if (IS_ERR(fid)) {
retval = PTR_ERR(fid);
mutex_unlock(&v9inode->v_mutex);
return retval;
}
v9inode->writeback_fid = (void *) fid;
}
mutex_unlock(&v9inode->v_mutex);
retval = generic_file_mmap(filp, vma); retval = generic_file_mmap(filp, vma);
if (!retval) if (!retval)
vma->vm_ops = &v9fs_mmap_file_vm_ops; vma->vm_ops = &v9fs_mmap_file_vm_ops;
...@@ -528,7 +503,6 @@ v9fs_file_mmap(struct file *filp, struct vm_area_struct *vma) ...@@ -528,7 +503,6 @@ v9fs_file_mmap(struct file *filp, struct vm_area_struct *vma)
static vm_fault_t static vm_fault_t
v9fs_vm_page_mkwrite(struct vm_fault *vmf) v9fs_vm_page_mkwrite(struct vm_fault *vmf)
{ {
struct v9fs_inode *v9inode;
struct folio *folio = page_folio(vmf->page); struct folio *folio = page_folio(vmf->page);
struct file *filp = vmf->vma->vm_file; struct file *filp = vmf->vma->vm_file;
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
...@@ -537,8 +511,6 @@ v9fs_vm_page_mkwrite(struct vm_fault *vmf) ...@@ -537,8 +511,6 @@ v9fs_vm_page_mkwrite(struct vm_fault *vmf)
p9_debug(P9_DEBUG_VFS, "folio %p fid %lx\n", p9_debug(P9_DEBUG_VFS, "folio %p fid %lx\n",
folio, (unsigned long)filp->private_data); folio, (unsigned long)filp->private_data);
v9inode = V9FS_I(inode);
/* Wait for the page to be written to the cache before we allow it to /* Wait for the page to be written to the cache before we allow it to
* be modified. We then assume the entire page will need writing back. * be modified. We then assume the entire page will need writing back.
*/ */
...@@ -551,7 +523,6 @@ v9fs_vm_page_mkwrite(struct vm_fault *vmf) ...@@ -551,7 +523,6 @@ v9fs_vm_page_mkwrite(struct vm_fault *vmf)
/* Update file times before taking page lock */ /* Update file times before taking page lock */
file_update_time(filp); file_update_time(filp);
BUG_ON(!v9inode->writeback_fid);
if (folio_lock_killable(folio) < 0) if (folio_lock_killable(folio) < 0)
return VM_FAULT_RETRY; return VM_FAULT_RETRY;
if (folio_mapping(folio) != inode->i_mapping) if (folio_mapping(folio) != inode->i_mapping)
......
...@@ -230,7 +230,6 @@ struct inode *v9fs_alloc_inode(struct super_block *sb) ...@@ -230,7 +230,6 @@ struct inode *v9fs_alloc_inode(struct super_block *sb)
v9inode = alloc_inode_sb(sb, v9fs_inode_cache, GFP_KERNEL); v9inode = alloc_inode_sb(sb, v9fs_inode_cache, GFP_KERNEL);
if (!v9inode) if (!v9inode)
return NULL; return NULL;
v9inode->writeback_fid = NULL;
v9inode->cache_validity = 0; v9inode->cache_validity = 0;
mutex_init(&v9inode->v_mutex); mutex_init(&v9inode->v_mutex);
return &v9inode->netfs.inode; return &v9inode->netfs.inode;
...@@ -383,9 +382,6 @@ void v9fs_evict_inode(struct inode *inode) ...@@ -383,9 +382,6 @@ void v9fs_evict_inode(struct inode *inode)
filemap_fdatawrite(&inode->i_data); filemap_fdatawrite(&inode->i_data);
fscache_relinquish_cookie(v9fs_inode_cookie(v9inode), false); fscache_relinquish_cookie(v9fs_inode_cookie(v9inode), false);
/* clunk the fid stashed in writeback_fid */
p9_fid_put(v9inode->writeback_fid);
v9inode->writeback_fid = NULL;
} }
static int v9fs_test_inode(struct inode *inode, void *data) static int v9fs_test_inode(struct inode *inode, void *data)
...@@ -796,9 +792,10 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -796,9 +792,10 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
u32 perm; u32 perm;
struct v9fs_inode *v9inode; struct v9fs_inode *v9inode;
struct v9fs_session_info *v9ses; struct v9fs_session_info *v9ses;
struct p9_fid *fid, *inode_fid; struct p9_fid *fid;
struct dentry *res = NULL; struct dentry *res = NULL;
struct inode *inode; struct inode *inode;
int p9_omode;
if (d_in_lookup(dentry)) { if (d_in_lookup(dentry)) {
res = v9fs_vfs_lookup(dir, dentry, 0); res = v9fs_vfs_lookup(dir, dentry, 0);
...@@ -817,9 +814,14 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -817,9 +814,14 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
v9ses = v9fs_inode2v9ses(dir); v9ses = v9fs_inode2v9ses(dir);
perm = unixmode2p9mode(v9ses, mode); perm = unixmode2p9mode(v9ses, mode);
fid = v9fs_create(v9ses, dir, dentry, NULL, perm, p9_omode = v9fs_uflags2omode(flags, v9fs_proto_dotu(v9ses));
v9fs_uflags2omode(flags,
v9fs_proto_dotu(v9ses))); if ((v9ses->cache >= CACHE_WRITEBACK) && (p9_omode & P9_OWRITE)) {
p9_omode = (p9_omode & !P9_OWRITE) | P9_ORDWR;
p9_debug(P9_DEBUG_CACHE,
"write-only file with writeback enabled, creating w/ O_RDWR\n");
}
fid = v9fs_create(v9ses, dir, dentry, NULL, perm, p9_omode);
if (IS_ERR(fid)) { if (IS_ERR(fid)) {
err = PTR_ERR(fid); err = PTR_ERR(fid);
goto error; goto error;
...@@ -828,25 +830,6 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -828,25 +830,6 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
v9fs_invalidate_inode_attr(dir); v9fs_invalidate_inode_attr(dir);
inode = d_inode(dentry); inode = d_inode(dentry);
v9inode = V9FS_I(inode); v9inode = V9FS_I(inode);
mutex_lock(&v9inode->v_mutex);
if ((v9ses->cache >= CACHE_WRITEBACK) && !v9inode->writeback_fid &&
((flags & O_ACCMODE) != O_RDONLY)) {
/*
* clone a fid and add it to writeback_fid
* we do it during open time instead of
* page dirty time via write_begin/page_mkwrite
* because we want write after unlink usecase
* to work.
*/
inode_fid = v9fs_writeback_fid(dentry);
if (IS_ERR(inode_fid)) {
err = PTR_ERR(inode_fid);
mutex_unlock(&v9inode->v_mutex);
goto error;
}
v9inode->writeback_fid = (void *) inode_fid;
}
mutex_unlock(&v9inode->v_mutex);
err = finish_open(file, dentry, generic_file_open); err = finish_open(file, dentry, generic_file_open);
if (err) if (err)
goto error; goto error;
...@@ -855,6 +838,8 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry, ...@@ -855,6 +838,8 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
fscache_use_cookie(v9fs_inode_cookie(v9inode), fscache_use_cookie(v9fs_inode_cookie(v9inode),
file->f_mode & FMODE_WRITE); file->f_mode & FMODE_WRITE);
v9fs_fid_add_modes(fid, v9ses->flags, v9ses->cache, file->f_flags);
v9fs_open_fid_add(inode, &fid); v9fs_open_fid_add(inode, &fid);
file->f_mode |= FMODE_CREATED; file->f_mode |= FMODE_CREATED;
...@@ -1024,7 +1009,7 @@ v9fs_vfs_getattr(struct mnt_idmap *idmap, const struct path *path, ...@@ -1024,7 +1009,7 @@ v9fs_vfs_getattr(struct mnt_idmap *idmap, const struct path *path,
p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry); p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);
v9ses = v9fs_dentry2v9ses(dentry); v9ses = v9fs_dentry2v9ses(dentry);
if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
generic_fillattr(&nop_mnt_idmap, d_inode(dentry), stat); generic_fillattr(&nop_mnt_idmap, inode, stat);
return 0; return 0;
} else if (v9ses->cache >= CACHE_WRITEBACK) { } else if (v9ses->cache >= CACHE_WRITEBACK) {
if (S_ISREG(inode->i_mode)) { if (S_ISREG(inode->i_mode)) {
...@@ -1128,10 +1113,10 @@ static int v9fs_vfs_setattr(struct mnt_idmap *idmap, ...@@ -1128,10 +1113,10 @@ static int v9fs_vfs_setattr(struct mnt_idmap *idmap,
if ((iattr->ia_valid & ATTR_SIZE) && if ((iattr->ia_valid & ATTR_SIZE) &&
iattr->ia_size != i_size_read(inode)) { iattr->ia_size != i_size_read(inode)) {
truncate_setsize(inode, iattr->ia_size); truncate_setsize(inode, iattr->ia_size);
truncate_pagecache(inode, iattr->ia_size);
if (v9ses->cache == CACHE_FSCACHE) if (v9ses->cache == CACHE_FSCACHE)
fscache_resize_cookie(v9fs_inode_cookie(v9inode), iattr->ia_size); fscache_resize_cookie(v9fs_inode_cookie(v9inode), iattr->ia_size);
else
invalidate_mapping_pages(&inode->i_data, 0, -1);
} }
v9fs_invalidate_inode_attr(inode); v9fs_invalidate_inode_attr(inode);
......
...@@ -232,12 +232,12 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, ...@@ -232,12 +232,12 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
int err = 0; int err = 0;
kgid_t gid; kgid_t gid;
umode_t mode; umode_t mode;
int p9_omode = v9fs_open_to_dotl_flags(flags);
const unsigned char *name = NULL; const unsigned char *name = NULL;
struct p9_qid qid; struct p9_qid qid;
struct inode *inode; struct inode *inode;
struct p9_fid *fid = NULL; struct p9_fid *fid = NULL;
struct v9fs_inode *v9inode; struct p9_fid *dfid = NULL, *ofid = NULL;
struct p9_fid *dfid = NULL, *ofid = NULL, *inode_fid = NULL;
struct v9fs_session_info *v9ses; struct v9fs_session_info *v9ses;
struct posix_acl *pacl = NULL, *dacl = NULL; struct posix_acl *pacl = NULL, *dacl = NULL;
struct dentry *res = NULL; struct dentry *res = NULL;
...@@ -282,14 +282,19 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, ...@@ -282,14 +282,19 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
/* Update mode based on ACL value */ /* Update mode based on ACL value */
err = v9fs_acl_mode(dir, &mode, &dacl, &pacl); err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
if (err) { if (err) {
p9_debug(P9_DEBUG_VFS, "Failed to get acl values in creat %d\n", p9_debug(P9_DEBUG_VFS, "Failed to get acl values in create %d\n",
err); err);
goto out; goto out;
} }
err = p9_client_create_dotl(ofid, name, v9fs_open_to_dotl_flags(flags),
mode, gid, &qid); if ((v9ses->cache >= CACHE_WRITEBACK) && (p9_omode & P9_OWRITE)) {
p9_omode = (p9_omode & !P9_OWRITE) | P9_ORDWR;
p9_debug(P9_DEBUG_CACHE,
"write-only file with writeback enabled, creating w/ O_RDWR\n");
}
err = p9_client_create_dotl(ofid, name, p9_omode, mode, gid, &qid);
if (err < 0) { if (err < 0) {
p9_debug(P9_DEBUG_VFS, "p9_client_open_dotl failed in creat %d\n", p9_debug(P9_DEBUG_VFS, "p9_client_open_dotl failed in create %d\n",
err); err);
goto out; goto out;
} }
...@@ -314,36 +319,19 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, ...@@ -314,36 +319,19 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
v9fs_fid_add(dentry, &fid); v9fs_fid_add(dentry, &fid);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
v9inode = V9FS_I(inode);
mutex_lock(&v9inode->v_mutex);
if ((v9ses->cache) && !v9inode->writeback_fid &&
((flags & O_ACCMODE) != O_RDONLY)) {
/*
* clone a fid and add it to writeback_fid
* we do it during open time instead of
* page dirty time via write_begin/page_mkwrite
* because we want write after unlink usecase
* to work.
*/
inode_fid = v9fs_writeback_fid(dentry);
if (IS_ERR(inode_fid)) {
err = PTR_ERR(inode_fid);
mutex_unlock(&v9inode->v_mutex);
goto out;
}
v9inode->writeback_fid = (void *) inode_fid;
}
mutex_unlock(&v9inode->v_mutex);
/* Since we are opening a file, assign the open fid to the file */ /* Since we are opening a file, assign the open fid to the file */
err = finish_open(file, dentry, generic_file_open); err = finish_open(file, dentry, generic_file_open);
if (err) if (err)
goto out; goto out;
file->private_data = ofid; file->private_data = ofid;
#ifdef CONFIG_9P_FSCACHE #ifdef CONFIG_9P_FSCACHE
if (v9ses->cache == CACHE_FSCACHE) if (v9ses->cache == CACHE_FSCACHE) {
struct v9fs_inode *v9inode = V9FS_I(inode);
fscache_use_cookie(v9fs_inode_cookie(v9inode), fscache_use_cookie(v9fs_inode_cookie(v9inode),
file->f_mode & FMODE_WRITE); file->f_mode & FMODE_WRITE);
}
#endif #endif
v9fs_fid_add_modes(ofid, v9ses->flags, v9ses->cache, flags);
v9fs_open_fid_add(inode, &ofid); v9fs_open_fid_add(inode, &ofid);
file->f_mode |= FMODE_CREATED; file->f_mode |= FMODE_CREATED;
out: out:
...@@ -464,9 +452,9 @@ v9fs_vfs_getattr_dotl(struct mnt_idmap *idmap, ...@@ -464,9 +452,9 @@ v9fs_vfs_getattr_dotl(struct mnt_idmap *idmap,
p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry); p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);
v9ses = v9fs_dentry2v9ses(dentry); v9ses = v9fs_dentry2v9ses(dentry);
if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
generic_fillattr(&nop_mnt_idmap, d_inode(dentry), stat); generic_fillattr(&nop_mnt_idmap, inode, stat);
return 0; return 0;
} else if (v9ses->cache >= CACHE_WRITEBACK) { } else if (v9ses->cache) {
if (S_ISREG(inode->i_mode)) { if (S_ISREG(inode->i_mode)) {
int retval = filemap_fdatawrite(inode->i_mapping); int retval = filemap_fdatawrite(inode->i_mapping);
...@@ -613,6 +601,8 @@ int v9fs_vfs_setattr_dotl(struct mnt_idmap *idmap, ...@@ -613,6 +601,8 @@ int v9fs_vfs_setattr_dotl(struct mnt_idmap *idmap,
if ((iattr->ia_valid & ATTR_SIZE) && iattr->ia_size != if ((iattr->ia_valid & ATTR_SIZE) && iattr->ia_size !=
i_size_read(inode)) { i_size_read(inode)) {
truncate_setsize(inode, iattr->ia_size); truncate_setsize(inode, iattr->ia_size);
truncate_pagecache(inode, iattr->ia_size);
if (v9ses->cache == CACHE_FSCACHE) if (v9ses->cache == CACHE_FSCACHE)
fscache_resize_cookie(v9fs_inode_cookie(v9inode), iattr->ia_size); fscache_resize_cookie(v9fs_inode_cookie(v9inode), iattr->ia_size);
} }
......
...@@ -290,49 +290,30 @@ static int v9fs_drop_inode(struct inode *inode) ...@@ -290,49 +290,30 @@ static int v9fs_drop_inode(struct inode *inode)
static int v9fs_write_inode(struct inode *inode, static int v9fs_write_inode(struct inode *inode,
struct writeback_control *wbc) struct writeback_control *wbc)
{ {
int ret;
struct p9_wstat wstat;
struct v9fs_inode *v9inode; struct v9fs_inode *v9inode;
/* /*
* send an fsync request to server irrespective of * send an fsync request to server irrespective of
* wbc->sync_mode. * wbc->sync_mode.
*/ */
p9_debug(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode); p9_debug(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);
v9inode = V9FS_I(inode);
if (!v9inode->writeback_fid)
return 0;
v9fs_blank_wstat(&wstat);
ret = p9_client_wstat(v9inode->writeback_fid, &wstat); v9inode = V9FS_I(inode);
if (ret < 0) {
__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
return ret;
}
fscache_unpin_writeback(wbc, v9fs_inode_cookie(v9inode)); fscache_unpin_writeback(wbc, v9fs_inode_cookie(v9inode));
return 0; return 0;
} }
static int v9fs_write_inode_dotl(struct inode *inode, static int v9fs_write_inode_dotl(struct inode *inode,
struct writeback_control *wbc) struct writeback_control *wbc)
{ {
int ret;
struct v9fs_inode *v9inode; struct v9fs_inode *v9inode;
/*
* send an fsync request to server irrespective of
* wbc->sync_mode.
*/
v9inode = V9FS_I(inode); v9inode = V9FS_I(inode);
p9_debug(P9_DEBUG_VFS, "%s: inode %p, writeback_fid %p\n", p9_debug(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);
__func__, inode, v9inode->writeback_fid);
if (!v9inode->writeback_fid)
return 0;
ret = p9_client_fsync(v9inode->writeback_fid, 0);
if (ret < 0) {
__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
return ret;
}
fscache_unpin_writeback(wbc, v9fs_inode_cookie(v9inode)); fscache_unpin_writeback(wbc, v9fs_inode_cookie(v9inode));
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment