Commit 28aa2f9e authored by Trond Myklebust's avatar Trond Myklebust Committed by Anna Schumaker

NFS: Always clear an invalid mapping when attempting a buffered write

If the page cache is invalid, then we can't do read-modify-write, so
ensure that we do clear it when we know it is invalid.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent fc9dc401
......@@ -632,6 +632,8 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
goto out;
}
nfs_clear_invalid_mapping(file->f_mapping);
since = filemap_sample_wb_err(file->f_mapping);
nfs_start_io_write(inode);
result = generic_write_checks(iocb, from);
......
......@@ -1257,55 +1257,19 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map
return 0;
}
bool nfs_mapping_need_revalidate_inode(struct inode *inode)
{
return nfs_check_cache_invalid(inode, NFS_INO_REVAL_PAGECACHE) ||
NFS_STALE(inode);
}
int nfs_revalidate_mapping_rcu(struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);
unsigned long *bitlock = &nfsi->flags;
int ret = 0;
if (IS_SWAPFILE(inode))
goto out;
if (nfs_mapping_need_revalidate_inode(inode)) {
ret = -ECHILD;
goto out;
}
spin_lock(&inode->i_lock);
if (test_bit(NFS_INO_INVALIDATING, bitlock) ||
(nfsi->cache_validity & NFS_INO_INVALID_DATA))
ret = -ECHILD;
spin_unlock(&inode->i_lock);
out:
return ret;
}
/**
* nfs_revalidate_mapping - Revalidate the pagecache
* @inode: pointer to host inode
* nfs_clear_invalid_mapping - Conditionally clear a mapping
* @mapping: pointer to mapping
*
* If the NFS_INO_INVALID_DATA inode flag is set, clear the mapping.
*/
int nfs_revalidate_mapping(struct inode *inode,
struct address_space *mapping)
int nfs_clear_invalid_mapping(struct address_space *mapping)
{
struct inode *inode = mapping->host;
struct nfs_inode *nfsi = NFS_I(inode);
unsigned long *bitlock = &nfsi->flags;
int ret = 0;
/* swapfiles are not supposed to be shared. */
if (IS_SWAPFILE(inode))
goto out;
if (nfs_mapping_need_revalidate_inode(inode)) {
ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
if (ret < 0)
goto out;
}
/*
* We must clear NFS_INO_INVALID_DATA first to ensure that
* invalidations that come in while we're shooting down the mappings
......@@ -1336,8 +1300,8 @@ int nfs_revalidate_mapping(struct inode *inode,
set_bit(NFS_INO_INVALIDATING, bitlock);
smp_wmb();
nfsi->cache_validity &= ~(NFS_INO_INVALID_DATA|
NFS_INO_DATA_INVAL_DEFER);
nfsi->cache_validity &=
~(NFS_INO_INVALID_DATA | NFS_INO_DATA_INVAL_DEFER);
spin_unlock(&inode->i_lock);
trace_nfs_invalidate_mapping_enter(inode);
ret = nfs_invalidate_mapping(inode, mapping);
......@@ -1350,6 +1314,53 @@ int nfs_revalidate_mapping(struct inode *inode,
return ret;
}
bool nfs_mapping_need_revalidate_inode(struct inode *inode)
{
return nfs_check_cache_invalid(inode, NFS_INO_REVAL_PAGECACHE) ||
NFS_STALE(inode);
}
int nfs_revalidate_mapping_rcu(struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);
unsigned long *bitlock = &nfsi->flags;
int ret = 0;
if (IS_SWAPFILE(inode))
goto out;
if (nfs_mapping_need_revalidate_inode(inode)) {
ret = -ECHILD;
goto out;
}
spin_lock(&inode->i_lock);
if (test_bit(NFS_INO_INVALIDATING, bitlock) ||
(nfsi->cache_validity & NFS_INO_INVALID_DATA))
ret = -ECHILD;
spin_unlock(&inode->i_lock);
out:
return ret;
}
/**
* nfs_revalidate_mapping - Revalidate the pagecache
* @inode: pointer to host inode
* @mapping: pointer to mapping
*/
int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
{
/* swapfiles are not supposed to be shared. */
if (IS_SWAPFILE(inode))
return 0;
if (nfs_mapping_need_revalidate_inode(inode)) {
int ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
if (ret < 0)
return ret;
}
return nfs_clear_invalid_mapping(mapping);
}
static bool nfs_file_has_writers(struct nfs_inode *nfsi)
{
struct inode *inode = &nfsi->vfs_inode;
......
......@@ -387,6 +387,7 @@ extern int nfs_open(struct inode *, struct file *);
extern int nfs_attribute_cache_expired(struct inode *inode);
extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
extern int nfs_clear_invalid_mapping(struct address_space *mapping);
extern bool nfs_mapping_need_revalidate_inode(struct inode *inode);
extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
extern int nfs_revalidate_mapping_rcu(struct inode *inode);
......
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