diff options
-rw-r--r-- | fs/nfs/dir.c | 6 | ||||
-rw-r--r-- | fs/nfs/direct.c | 13 | ||||
-rw-r--r-- | fs/nfs/inode.c | 28 | ||||
-rw-r--r-- | include/linux/nfs_fs.h | 1 |
4 files changed, 30 insertions, 18 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 481f8892a91..58d44057813 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -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: diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 1e873fcab94..bdfabf854a5 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -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; diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index bc9376ca86c..9979ad1cf8e 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -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; } diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 76ff54846ad..6b2de1be581 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -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 *); |