|
@@ -662,9 +662,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
|
|
|
trace_nfs_getattr_enter(inode);
|
|
|
/* Flush out writes to the server in order to update c/mtime. */
|
|
|
if (S_ISREG(inode->i_mode)) {
|
|
|
- inode_lock(inode);
|
|
|
- err = nfs_sync_inode(inode);
|
|
|
- inode_unlock(inode);
|
|
|
+ err = filemap_write_and_wait(inode->i_mapping);
|
|
|
if (err)
|
|
|
goto out;
|
|
|
}
|
|
@@ -879,7 +877,10 @@ void nfs_inode_attach_open_context(struct nfs_open_context *ctx)
|
|
|
struct nfs_inode *nfsi = NFS_I(inode);
|
|
|
|
|
|
spin_lock(&inode->i_lock);
|
|
|
- list_add(&ctx->list, &nfsi->open_files);
|
|
|
+ if (ctx->mode & FMODE_WRITE)
|
|
|
+ list_add(&ctx->list, &nfsi->open_files);
|
|
|
+ else
|
|
|
+ list_add_tail(&ctx->list, &nfsi->open_files);
|
|
|
spin_unlock(&inode->i_lock);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(nfs_inode_attach_open_context);
|
|
@@ -972,6 +973,13 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
|
|
|
if (NFS_STALE(inode))
|
|
|
goto out;
|
|
|
|
|
|
+ /* pNFS: Attributes aren't updated until we layoutcommit */
|
|
|
+ if (S_ISREG(inode->i_mode)) {
|
|
|
+ status = pnfs_sync_inode(inode, false);
|
|
|
+ if (status)
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
status = -ENOMEM;
|
|
|
fattr = nfs_alloc_fattr();
|
|
|
if (fattr == NULL)
|
|
@@ -1122,14 +1130,12 @@ out:
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * __nfs_revalidate_mapping - Revalidate the pagecache
|
|
|
+ * nfs_revalidate_mapping - Revalidate the pagecache
|
|
|
* @inode - pointer to host inode
|
|
|
* @mapping - pointer to mapping
|
|
|
- * @may_lock - take inode->i_mutex?
|
|
|
*/
|
|
|
-static int __nfs_revalidate_mapping(struct inode *inode,
|
|
|
- struct address_space *mapping,
|
|
|
- bool may_lock)
|
|
|
+int nfs_revalidate_mapping(struct inode *inode,
|
|
|
+ struct address_space *mapping)
|
|
|
{
|
|
|
struct nfs_inode *nfsi = NFS_I(inode);
|
|
|
unsigned long *bitlock = &nfsi->flags;
|
|
@@ -1178,12 +1184,7 @@ static int __nfs_revalidate_mapping(struct inode *inode,
|
|
|
nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
|
|
|
spin_unlock(&inode->i_lock);
|
|
|
trace_nfs_invalidate_mapping_enter(inode);
|
|
|
- if (may_lock) {
|
|
|
- inode_lock(inode);
|
|
|
- ret = nfs_invalidate_mapping(inode, mapping);
|
|
|
- inode_unlock(inode);
|
|
|
- } else
|
|
|
- ret = nfs_invalidate_mapping(inode, mapping);
|
|
|
+ ret = nfs_invalidate_mapping(inode, mapping);
|
|
|
trace_nfs_invalidate_mapping_exit(inode, ret);
|
|
|
|
|
|
clear_bit_unlock(NFS_INO_INVALIDATING, bitlock);
|
|
@@ -1193,27 +1194,28 @@ 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)
|
|
|
+static bool nfs_file_has_writers(struct nfs_inode *nfsi)
|
|
|
{
|
|
|
- return __nfs_revalidate_mapping(inode, mapping, false);
|
|
|
+ struct inode *inode = &nfsi->vfs_inode;
|
|
|
+
|
|
|
+ assert_spin_locked(&inode->i_lock);
|
|
|
+
|
|
|
+ if (!S_ISREG(inode->i_mode))
|
|
|
+ return false;
|
|
|
+ if (list_empty(&nfsi->open_files))
|
|
|
+ return false;
|
|
|
+ /* Note: This relies on nfsi->open_files being ordered with writers
|
|
|
+ * being placed at the head of the list.
|
|
|
+ * See nfs_inode_attach_open_context()
|
|
|
+ */
|
|
|
+ return (list_first_entry(&nfsi->open_files,
|
|
|
+ struct nfs_open_context,
|
|
|
+ list)->mode & FMODE_WRITE) == FMODE_WRITE;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * nfs_revalidate_mapping_protected - Revalidate the pagecache
|
|
|
- * @inode - pointer to host inode
|
|
|
- * @mapping - pointer to mapping
|
|
|
- *
|
|
|
- * Differs from nfs_revalidate_mapping() in that it grabs the inode->i_mutex
|
|
|
- * while invalidating the mapping.
|
|
|
- */
|
|
|
-int nfs_revalidate_mapping_protected(struct inode *inode, struct address_space *mapping)
|
|
|
+static bool nfs_file_has_buffered_writers(struct nfs_inode *nfsi)
|
|
|
{
|
|
|
- return __nfs_revalidate_mapping(inode, mapping, true);
|
|
|
+ return nfs_file_has_writers(nfsi) && nfs_file_io_is_buffered(nfsi);
|
|
|
}
|
|
|
|
|
|
static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|
@@ -1280,22 +1282,24 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
|
|
|
if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
|
|
|
return -EIO;
|
|
|
|
|
|
- if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
|
|
|
- inode->i_version != fattr->change_attr)
|
|
|
- invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
|
|
|
+ if (!nfs_file_has_buffered_writers(nfsi)) {
|
|
|
+ /* Verify a few of the more important attributes */
|
|
|
+ if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 && inode->i_version != fattr->change_attr)
|
|
|
+ invalid |= NFS_INO_INVALID_ATTR | NFS_INO_REVAL_PAGECACHE;
|
|
|
|
|
|
- /* Verify a few of the more important attributes */
|
|
|
- if ((fattr->valid & NFS_ATTR_FATTR_MTIME) && !timespec_equal(&inode->i_mtime, &fattr->mtime))
|
|
|
- invalid |= NFS_INO_INVALID_ATTR;
|
|
|
+ if ((fattr->valid & NFS_ATTR_FATTR_MTIME) && !timespec_equal(&inode->i_mtime, &fattr->mtime))
|
|
|
+ invalid |= NFS_INO_INVALID_ATTR;
|
|
|
|
|
|
- if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
|
|
|
- cur_size = i_size_read(inode);
|
|
|
- new_isize = nfs_size_to_loff_t(fattr->size);
|
|
|
- if (cur_size != new_isize)
|
|
|
- invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
|
|
|
+ if ((fattr->valid & NFS_ATTR_FATTR_CTIME) && !timespec_equal(&inode->i_ctime, &fattr->ctime))
|
|
|
+ invalid |= NFS_INO_INVALID_ATTR;
|
|
|
+
|
|
|
+ if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
|
|
|
+ cur_size = i_size_read(inode);
|
|
|
+ new_isize = nfs_size_to_loff_t(fattr->size);
|
|
|
+ if (cur_size != new_isize)
|
|
|
+ invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
|
|
|
+ }
|
|
|
}
|
|
|
- if (nfsi->nrequests != 0)
|
|
|
- invalid &= ~NFS_INO_REVAL_PAGECACHE;
|
|
|
|
|
|
/* Have any file permissions changed? */
|
|
|
if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO))
|
|
@@ -1470,28 +1474,12 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n
|
|
|
((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0);
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Don't trust the change_attribute, mtime, ctime or size if
|
|
|
- * a pnfs LAYOUTCOMMIT is outstanding
|
|
|
- */
|
|
|
-static void nfs_inode_attrs_handle_layoutcommit(struct inode *inode,
|
|
|
- struct nfs_fattr *fattr)
|
|
|
-{
|
|
|
- if (pnfs_layoutcommit_outstanding(inode))
|
|
|
- fattr->valid &= ~(NFS_ATTR_FATTR_CHANGE |
|
|
|
- NFS_ATTR_FATTR_MTIME |
|
|
|
- NFS_ATTR_FATTR_CTIME |
|
|
|
- NFS_ATTR_FATTR_SIZE);
|
|
|
-}
|
|
|
-
|
|
|
static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
|
trace_nfs_refresh_inode_enter(inode);
|
|
|
|
|
|
- nfs_inode_attrs_handle_layoutcommit(inode, fattr);
|
|
|
-
|
|
|
if (nfs_inode_attrs_need_update(inode, fattr))
|
|
|
ret = nfs_update_inode(inode, fattr);
|
|
|
else
|
|
@@ -1527,7 +1515,7 @@ EXPORT_SYMBOL_GPL(nfs_refresh_inode);
|
|
|
|
|
|
static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
|
|
|
{
|
|
|
- unsigned long invalid = NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
|
|
|
+ unsigned long invalid = NFS_INO_INVALID_ATTR;
|
|
|
|
|
|
/*
|
|
|
* Don't revalidate the pagecache if we hold a delegation, but do
|
|
@@ -1676,7 +1664,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|
|
unsigned long invalid = 0;
|
|
|
unsigned long now = jiffies;
|
|
|
unsigned long save_cache_validity;
|
|
|
- bool cache_revalidated = true;
|
|
|
+ bool have_writers = nfs_file_has_buffered_writers(nfsi);
|
|
|
+ bool cache_revalidated;
|
|
|
|
|
|
dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n",
|
|
|
__func__, inode->i_sb->s_id, inode->i_ino,
|
|
@@ -1725,17 +1714,23 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|
|
/* Do atomic weak cache consistency updates */
|
|
|
invalid |= nfs_wcc_update_inode(inode, fattr);
|
|
|
|
|
|
+
|
|
|
+ cache_revalidated = !pnfs_layoutcommit_outstanding(inode);
|
|
|
+
|
|
|
/* More cache consistency checks */
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_CHANGE) {
|
|
|
if (inode->i_version != fattr->change_attr) {
|
|
|
dprintk("NFS: change_attr change on server for file %s/%ld\n",
|
|
|
inode->i_sb->s_id, inode->i_ino);
|
|
|
- invalid |= NFS_INO_INVALID_ATTR
|
|
|
- | NFS_INO_INVALID_DATA
|
|
|
- | NFS_INO_INVALID_ACCESS
|
|
|
- | NFS_INO_INVALID_ACL;
|
|
|
- if (S_ISDIR(inode->i_mode))
|
|
|
- nfs_force_lookup_revalidate(inode);
|
|
|
+ /* Could it be a race with writeback? */
|
|
|
+ if (!have_writers) {
|
|
|
+ invalid |= NFS_INO_INVALID_ATTR
|
|
|
+ | NFS_INO_INVALID_DATA
|
|
|
+ | NFS_INO_INVALID_ACCESS
|
|
|
+ | NFS_INO_INVALID_ACL;
|
|
|
+ if (S_ISDIR(inode->i_mode))
|
|
|
+ nfs_force_lookup_revalidate(inode);
|
|
|
+ }
|
|
|
inode->i_version = fattr->change_attr;
|
|
|
}
|
|
|
} else {
|
|
@@ -1768,9 +1763,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|
|
if (new_isize != cur_isize) {
|
|
|
/* Do we perhaps have any outstanding writes, or has
|
|
|
* the file grown beyond our last write? */
|
|
|
- if ((nfsi->nrequests == 0) || new_isize > cur_isize) {
|
|
|
+ if (nfsi->nrequests == 0 || new_isize > cur_isize) {
|
|
|
i_size_write(inode, new_isize);
|
|
|
- invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
|
|
|
+ if (!have_writers)
|
|
|
+ invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
|
|
|
}
|
|
|
dprintk("NFS: isize change on server for file %s/%ld "
|
|
|
"(%Ld to %Ld)\n",
|