]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/nfs/inode.c
Merge branch 'writeback'
[karo-tx-linux.git] / fs / nfs / inode.c
index dda689d7a8a706862e21737cb5189ab175d976e1..f108d58101f8bc46cf08f766b86021d7030c0164 100644 (file)
@@ -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",