|
@@ -1147,27 +1147,6 @@ void nfs_end_data_update(struct inode *inode)
|
|
atomic_dec(&nfsi->data_updates);
|
|
atomic_dec(&nfsi->data_updates);
|
|
}
|
|
}
|
|
|
|
|
|
-/**
|
|
|
|
- * nfs_end_data_update_defer
|
|
|
|
- * @inode - pointer to inode
|
|
|
|
- * Declare end of the operations that will update file data
|
|
|
|
- * This will defer marking the inode as needing revalidation
|
|
|
|
- * unless there are no other pending updates.
|
|
|
|
- */
|
|
|
|
-void nfs_end_data_update_defer(struct inode *inode)
|
|
|
|
-{
|
|
|
|
- struct nfs_inode *nfsi = NFS_I(inode);
|
|
|
|
-
|
|
|
|
- if (atomic_dec_and_test(&nfsi->data_updates)) {
|
|
|
|
- /* Mark the attribute cache for revalidation */
|
|
|
|
- nfsi->flags |= NFS_INO_INVALID_ATTR;
|
|
|
|
- /* Directories and symlinks: invalidate page cache too */
|
|
|
|
- if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
|
|
|
|
- nfsi->flags |= NFS_INO_INVALID_DATA;
|
|
|
|
- nfsi->cache_change_attribute ++;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* nfs_refresh_inode - verify consistency of the inode attribute cache
|
|
* nfs_refresh_inode - verify consistency of the inode attribute cache
|
|
* @inode - pointer to inode
|
|
* @inode - pointer to inode
|
|
@@ -1222,8 +1201,8 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|
if (!timespec_equal(&inode->i_mtime, &fattr->mtime)
|
|
if (!timespec_equal(&inode->i_mtime, &fattr->mtime)
|
|
|| cur_size != new_isize)
|
|
|| cur_size != new_isize)
|
|
nfsi->flags |= NFS_INO_INVALID_ATTR;
|
|
nfsi->flags |= NFS_INO_INVALID_ATTR;
|
|
- } else if (S_ISREG(inode->i_mode) && new_isize > cur_size)
|
|
|
|
- nfsi->flags |= NFS_INO_INVALID_ATTR;
|
|
|
|
|
|
+ } else if (new_isize != cur_size && nfsi->npages == 0)
|
|
|
|
+ nfsi->flags |= NFS_INO_INVALID_ATTR;
|
|
|
|
|
|
/* Have any file permissions changed? */
|
|
/* Have any file permissions changed? */
|
|
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
|
|
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
|
|
@@ -1257,10 +1236,8 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|
static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier)
|
|
static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier)
|
|
{
|
|
{
|
|
struct nfs_inode *nfsi = NFS_I(inode);
|
|
struct nfs_inode *nfsi = NFS_I(inode);
|
|
- __u64 new_size;
|
|
|
|
- loff_t new_isize;
|
|
|
|
|
|
+ loff_t cur_isize, new_isize;
|
|
unsigned int invalid = 0;
|
|
unsigned int invalid = 0;
|
|
- loff_t cur_isize;
|
|
|
|
int data_unstable;
|
|
int data_unstable;
|
|
|
|
|
|
dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
|
|
dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
|
|
@@ -1293,49 +1270,39 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
|
|
/* Are we racing with known updates of the metadata on the server? */
|
|
/* Are we racing with known updates of the metadata on the server? */
|
|
data_unstable = ! nfs_verify_change_attribute(inode, verifier);
|
|
data_unstable = ! nfs_verify_change_attribute(inode, verifier);
|
|
|
|
|
|
- /* Check if the file size agrees */
|
|
|
|
- new_size = fattr->size;
|
|
|
|
|
|
+ /* Check if our cached file size is stale */
|
|
new_isize = nfs_size_to_loff_t(fattr->size);
|
|
new_isize = nfs_size_to_loff_t(fattr->size);
|
|
cur_isize = i_size_read(inode);
|
|
cur_isize = i_size_read(inode);
|
|
- if (cur_isize != new_size) {
|
|
|
|
-#ifdef NFS_DEBUG_VERBOSE
|
|
|
|
- printk(KERN_DEBUG "NFS: isize change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino);
|
|
|
|
-#endif
|
|
|
|
- /*
|
|
|
|
- * If we have pending writebacks, things can get
|
|
|
|
- * messy.
|
|
|
|
- */
|
|
|
|
- if (S_ISREG(inode->i_mode) && data_unstable) {
|
|
|
|
- if (new_isize > cur_isize) {
|
|
|
|
|
|
+ if (new_isize != cur_isize) {
|
|
|
|
+ /* Do we perhaps have any outstanding writes? */
|
|
|
|
+ if (nfsi->npages == 0) {
|
|
|
|
+ /* No, but did we race with nfs_end_data_update()? */
|
|
|
|
+ if (verifier == nfsi->cache_change_attribute) {
|
|
inode->i_size = new_isize;
|
|
inode->i_size = new_isize;
|
|
- invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
|
|
|
|
|
|
+ invalid |= NFS_INO_INVALID_DATA;
|
|
}
|
|
}
|
|
- } else {
|
|
|
|
|
|
+ invalid |= NFS_INO_INVALID_ATTR;
|
|
|
|
+ } else if (new_isize > cur_isize) {
|
|
inode->i_size = new_isize;
|
|
inode->i_size = new_isize;
|
|
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
|
|
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
+ dprintk("NFS: isize change on server for file %s/%ld\n",
|
|
|
|
+ inode->i_sb->s_id, inode->i_ino);
|
|
}
|
|
}
|
|
|
|
|
|
- /*
|
|
|
|
- * Note: we don't check inode->i_mtime since pipes etc.
|
|
|
|
- * can change this value in VFS without requiring a
|
|
|
|
- * cache revalidation.
|
|
|
|
- */
|
|
|
|
|
|
+ /* Check if the mtime agrees */
|
|
if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
|
|
if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
|
|
memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
|
|
memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
|
|
-#ifdef NFS_DEBUG_VERBOSE
|
|
|
|
- printk(KERN_DEBUG "NFS: mtime change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino);
|
|
|
|
-#endif
|
|
|
|
|
|
+ dprintk("NFS: mtime change on server for file %s/%ld\n",
|
|
|
|
+ inode->i_sb->s_id, inode->i_ino);
|
|
if (!data_unstable)
|
|
if (!data_unstable)
|
|
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
|
|
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
|
|
if ((fattr->valid & NFS_ATTR_FATTR_V4)
|
|
if ((fattr->valid & NFS_ATTR_FATTR_V4)
|
|
&& nfsi->change_attr != fattr->change_attr) {
|
|
&& nfsi->change_attr != fattr->change_attr) {
|
|
-#ifdef NFS_DEBUG_VERBOSE
|
|
|
|
- printk(KERN_DEBUG "NFS: change_attr change on %s/%ld\n",
|
|
|
|
|
|
+ dprintk("NFS: change_attr change on server for file %s/%ld\n",
|
|
inode->i_sb->s_id, inode->i_ino);
|
|
inode->i_sb->s_id, inode->i_ino);
|
|
-#endif
|
|
|
|
nfsi->change_attr = fattr->change_attr;
|
|
nfsi->change_attr = fattr->change_attr;
|
|
if (!data_unstable)
|
|
if (!data_unstable)
|
|
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
|
|
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
|