[PATCH] NFSv4: add support for rdattr_error in NFSv4 readdir requests.
[pandora-kernel.git] / fs / nfs / inode.c
index 8a8d57d..4845911 100644 (file)
@@ -135,7 +135,7 @@ nfs_write_inode(struct inode *inode, int sync)
        int flags = sync ? FLUSH_WAIT : 0;
        int ret;
 
-       ret = nfs_commit_inode(inode, 0, 0, flags);
+       ret = nfs_commit_inode(inode, flags);
        if (ret < 0)
                return ret;
        return 0;
@@ -620,9 +620,9 @@ nfs_zap_caches(struct inode *inode)
 
        memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
        if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))
-               nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+               nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
        else
-               nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
+               nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
 }
 
 static void nfs_zap_acl_cache(struct inode *inode)
@@ -891,6 +891,7 @@ struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rp
                ctx->state = NULL;
                ctx->lockowner = current->files;
                ctx->error = 0;
+               ctx->dir_cookie = 0;
        }
        return ctx;
 }
@@ -1054,6 +1055,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
                goto out;
        }
        flags = nfsi->flags;
+       nfsi->flags &= ~NFS_INO_REVAL_PAGECACHE;
        /*
         * We may need to keep the attributes marked as invalid if
         * we raced with nfs_end_attr_update().
@@ -1061,21 +1063,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
        if (verifier == nfsi->cache_change_attribute)
                nfsi->flags &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME);
        /* Do the page cache invalidation */
-       if (flags & NFS_INO_INVALID_DATA) {
-               if (S_ISREG(inode->i_mode)) {
-                       if (filemap_fdatawrite(inode->i_mapping) == 0)
-                               filemap_fdatawait(inode->i_mapping);
-                       nfs_wb_all(inode);
-               }
-               nfsi->flags &= ~NFS_INO_INVALID_DATA;
-               invalidate_inode_pages2(inode->i_mapping);
-               memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
-               dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
-                               inode->i_sb->s_id,
-                               (long long)NFS_FILEID(inode));
-               /* This ensures we revalidate dentries */
-               nfsi->cache_change_attribute++;
-       }
+       nfs_revalidate_mapping(inode, inode->i_mapping);
        if (flags & NFS_INO_INVALID_ACL)
                nfs_zap_acl_cache(inode);
        dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n",
@@ -1114,6 +1102,34 @@ int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
        return __nfs_revalidate_inode(server, inode);
 }
 
+/**
+ * nfs_revalidate_mapping - Revalidate the pagecache
+ * @inode - pointer to host inode
+ * @mapping - pointer to mapping
+ */
+void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+
+       if (nfsi->flags & NFS_INO_INVALID_DATA) {
+               if (S_ISREG(inode->i_mode)) {
+                       if (filemap_fdatawrite(mapping) == 0)
+                               filemap_fdatawait(mapping);
+                       nfs_wb_all(inode);
+               }
+               invalidate_inode_pages2(mapping);
+               nfsi->flags &= ~NFS_INO_INVALID_DATA;
+               if (S_ISDIR(inode->i_mode)) {
+                       memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
+                       /* This ensures we revalidate child dentries */
+                       nfsi->cache_change_attribute++;
+               }
+               dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
+                               inode->i_sb->s_id,
+                               (long long)NFS_FILEID(inode));
+       }
+}
+
 /**
  * nfs_begin_data_update
  * @inode - pointer to inode
@@ -1146,27 +1162,6 @@ void nfs_end_data_update(struct inode *inode)
        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
  * @inode - pointer to inode
@@ -1193,8 +1188,11 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
                if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0
                                && nfsi->change_attr == fattr->pre_change_attr)
                        nfsi->change_attr = fattr->change_attr;
-               if (!data_unstable && nfsi->change_attr != fattr->change_attr)
+               if (nfsi->change_attr != fattr->change_attr) {
                        nfsi->flags |= NFS_INO_INVALID_ATTR;
+                       if (!data_unstable)
+                               nfsi->flags |= NFS_INO_REVAL_PAGECACHE;
+               }
        }
 
        if ((fattr->valid & NFS_ATTR_FATTR) == 0)
@@ -1217,12 +1215,16 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
        }
 
        /* Verify a few of the more important attributes */
-       if (!data_unstable) {
-               if (!timespec_equal(&inode->i_mtime, &fattr->mtime)
-                               || cur_size != new_isize)
-                       nfsi->flags |= NFS_INO_INVALID_ATTR;
-       } else if (S_ISREG(inode->i_mode) && new_isize > cur_size)
-                       nfsi->flags |= NFS_INO_INVALID_ATTR;
+       if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
+               nfsi->flags |= NFS_INO_INVALID_ATTR;
+               if (!data_unstable)
+                       nfsi->flags |= NFS_INO_REVAL_PAGECACHE;
+       }
+       if (cur_size != new_isize) {
+               nfsi->flags |= NFS_INO_INVALID_ATTR;
+               if (nfsi->npages == 0)
+                       nfsi->flags |= NFS_INO_REVAL_PAGECACHE;
+       }
 
        /* Have any file permissions changed? */
        if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
@@ -1256,10 +1258,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)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
-       __u64           new_size;
-       loff_t          new_isize;
+       loff_t cur_isize, new_isize;
        unsigned int    invalid = 0;
-       loff_t          cur_isize;
        int data_unstable;
 
        dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
@@ -1292,49 +1292,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? */
        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);
        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;
-                               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;
                        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)) {
                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)
                        invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
        }
 
        if ((fattr->valid & NFS_ATTR_FATTR_V4)
            && 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);
-#endif
                nfsi->change_attr = fattr->change_attr;
                if (!data_unstable)
                        invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;