[PATCH] NFS: Deal with failure of invalidate_inode_pages2()
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 20 Oct 2006 06:28:40 +0000 (23:28 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Fri, 20 Oct 2006 17:26:39 +0000 (10:26 -0700)
If invalidate_inode_pages2() fails, then it should in principle just be
because the current process was signalled.  In that case, we just want to
ensure that the inode's page cache remains marked as invalid.

Also add a helper to allow the O_DIRECT code to simply mark the page cache as
invalid once it is finished writing, instead of calling
invalidate_inode_pages2() itself.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/nfs/dir.c
fs/nfs/direct.c
fs/nfs/inode.c
include/linux/nfs_fs.h

index 481f8892a919489cb5705269834b0145b0d5c8f1..58d44057813e8894e2e446be0b1e166cfb79ebd8 100644 (file)
@@ -203,8 +203,10 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
         * Note: assumes we have exclusive access to this mapping either
         *       through inode->i_mutex or some other mechanism.
         */
-       if (page->index == 0)
-               invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1);
+       if (page->index == 0 && invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1) < 0) {
+               /* Should never happen */
+               nfs_zap_mapping(inode, inode->i_mapping);
+       }
        unlock_page(page);
        return 0;
  error:
index 1e873fcab947708b63af5604a45f6c2a191cd23e..bdfabf854a519af44ae5f07e83ee64e3e0089c6a 100644 (file)
@@ -497,6 +497,7 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode
                        if (dreq->commit_data != NULL)
                                nfs_commit_free(dreq->commit_data);
                        nfs_direct_free_writedata(dreq);
+                       nfs_zap_mapping(inode, inode->i_mapping);
                        nfs_direct_complete(dreq);
        }
 }
@@ -517,6 +518,7 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode
 {
        nfs_end_data_update(inode);
        nfs_direct_free_writedata(dreq);
+       nfs_zap_mapping(inode, inode->i_mapping);
        nfs_direct_complete(dreq);
 }
 #endif
@@ -830,17 +832,6 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
 
        retval = nfs_direct_write(iocb, (unsigned long) buf, count, pos);
 
-       /*
-        * XXX: nfs_end_data_update() already ensures this file's
-        *      cached data is subsequently invalidated.  Do we really
-        *      need to call invalidate_inode_pages2() again here?
-        *
-        *      For aio writes, this invalidation will almost certainly
-        *      occur before the writes complete.  Kind of racey.
-        */
-       if (mapping->nrpages)
-               invalidate_inode_pages2(mapping);
-
        if (retval > 0)
                iocb->ki_pos = pos + retval;
 
index bc9376ca86cd28ea645ea38b889ac455faf0b141..9979ad1cf8eb9668dde0072d2bab7e37eedd0444 100644 (file)
@@ -131,6 +131,15 @@ void nfs_zap_caches(struct inode *inode)
        spin_unlock(&inode->i_lock);
 }
 
+void nfs_zap_mapping(struct inode *inode, struct address_space *mapping)
+{
+       if (mapping->nrpages != 0) {
+               spin_lock(&inode->i_lock);
+               NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA;
+               spin_unlock(&inode->i_lock);
+       }
+}
+
 static void nfs_zap_acl_cache(struct inode *inode)
 {
        void (*clear_acl_cache)(struct inode *);
@@ -671,13 +680,20 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
        if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE)
                        || nfs_attribute_timeout(inode))
                ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
+       if (ret < 0)
+               goto out;
 
        if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
-               nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
-               if (S_ISREG(inode->i_mode))
-                       nfs_sync_mapping(mapping);
-               invalidate_inode_pages2(mapping);
-
+               if (mapping->nrpages != 0) {
+                       if (S_ISREG(inode->i_mode)) {
+                               ret = nfs_sync_mapping(mapping);
+                               if (ret < 0)
+                                       goto out;
+                       }
+                       ret = invalidate_inode_pages2(mapping);
+                       if (ret < 0)
+                               goto out;
+               }
                spin_lock(&inode->i_lock);
                nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
                if (S_ISDIR(inode->i_mode)) {
@@ -687,10 +703,12 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
                }
                spin_unlock(&inode->i_lock);
 
+               nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
                dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
                                inode->i_sb->s_id,
                                (long long)NFS_FILEID(inode));
        }
+out:
        return ret;
 }
 
index 76ff54846ada1e07cab6ca2fa8e0de019a906e85..6b2de1be5815965fc28a2cc066b82c4ffdfd0f58 100644 (file)
@@ -290,6 +290,7 @@ static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long
  * linux/fs/nfs/inode.c
  */
 extern int nfs_sync_mapping(struct address_space *mapping);
+extern void nfs_zap_mapping(struct inode *inode, struct address_space *mapping);
 extern void nfs_zap_caches(struct inode *);
 extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
                                struct nfs_fattr *);