aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2015-03-02 23:32:08 -0500
committerTrond Myklebust <trond.myklebust@primarydata.com>2015-03-03 13:02:29 -0500
commit874f946376de57c8d6230b30ad71f742883fee3a (patch)
tree0fd166cc4798b50069d1120f822f094a60b7a9c2 /fs/nfs
parentec3ca4e57e00d52ff724b0ae49f4489667a9c311 (diff)
NFS: Fix a regression in the read() syscall
When invalidating the page cache for a regular file, we want to first sync all dirty data to disk and then call invalidate_inode_pages2(). The latter relies on nfs_launder_page() and nfs_release_page() to deal respectively with dirty pages, and unstable written pages. When commit 9590544694bec ("NFS: avoid deadlocks with loop-back mounted NFS filesystems.") changed the behaviour of nfs_release_page(), then it made it possible for invalidate_inode_pages2() to fail with an EBUSY. Unfortunately, that error is then propagated back to read(). Let's therefore work around the problem for now by protecting the call to sync the data and invalidate_inode_pages2() so that they are atomic w.r.t. the addition of new writes. Later on, we can revisit whether or not we still need nfs_launder_page() and nfs_release_page(). Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/file.c4
-rw-r--r--fs/nfs/inode.c37
2 files changed, 36 insertions, 5 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index c045c7169fa0..41963ffca597 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -178,7 +178,7 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
178 iocb->ki_filp, 178 iocb->ki_filp,
179 iov_iter_count(to), (unsigned long) iocb->ki_pos); 179 iov_iter_count(to), (unsigned long) iocb->ki_pos);
180 180
181 result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); 181 result = nfs_revalidate_mapping_protected(inode, iocb->ki_filp->f_mapping);
182 if (!result) { 182 if (!result) {
183 result = generic_file_read_iter(iocb, to); 183 result = generic_file_read_iter(iocb, to);
184 if (result > 0) 184 if (result > 0)
@@ -199,7 +199,7 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos,
199 dprintk("NFS: splice_read(%pD2, %lu@%Lu)\n", 199 dprintk("NFS: splice_read(%pD2, %lu@%Lu)\n",
200 filp, (unsigned long) count, (unsigned long long) *ppos); 200 filp, (unsigned long) count, (unsigned long long) *ppos);
201 201
202 res = nfs_revalidate_mapping(inode, filp->f_mapping); 202 res = nfs_revalidate_mapping_protected(inode, filp->f_mapping);
203 if (!res) { 203 if (!res) {
204 res = generic_file_splice_read(filp, ppos, pipe, count, flags); 204 res = generic_file_splice_read(filp, ppos, pipe, count, flags);
205 if (res > 0) 205 if (res > 0)
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 5026c44a98e1..8edb7d049565 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1067,11 +1067,14 @@ static bool nfs_mapping_need_revalidate_inode(struct inode *inode)
1067} 1067}
1068 1068
1069/** 1069/**
1070 * nfs_revalidate_mapping - Revalidate the pagecache 1070 * __nfs_revalidate_mapping - Revalidate the pagecache
1071 * @inode - pointer to host inode 1071 * @inode - pointer to host inode
1072 * @mapping - pointer to mapping 1072 * @mapping - pointer to mapping
1073 * @may_lock - take inode->i_mutex?
1073 */ 1074 */
1074int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) 1075static int __nfs_revalidate_mapping(struct inode *inode,
1076 struct address_space *mapping,
1077 bool may_lock)
1075{ 1078{
1076 struct nfs_inode *nfsi = NFS_I(inode); 1079 struct nfs_inode *nfsi = NFS_I(inode);
1077 unsigned long *bitlock = &nfsi->flags; 1080 unsigned long *bitlock = &nfsi->flags;
@@ -1120,7 +1123,12 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
1120 nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; 1123 nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
1121 spin_unlock(&inode->i_lock); 1124 spin_unlock(&inode->i_lock);
1122 trace_nfs_invalidate_mapping_enter(inode); 1125 trace_nfs_invalidate_mapping_enter(inode);
1123 ret = nfs_invalidate_mapping(inode, mapping); 1126 if (may_lock) {
1127 mutex_lock(&inode->i_mutex);
1128 ret = nfs_invalidate_mapping(inode, mapping);
1129 mutex_unlock(&inode->i_mutex);
1130 } else
1131 ret = nfs_invalidate_mapping(inode, mapping);
1124 trace_nfs_invalidate_mapping_exit(inode, ret); 1132 trace_nfs_invalidate_mapping_exit(inode, ret);
1125 1133
1126 clear_bit_unlock(NFS_INO_INVALIDATING, bitlock); 1134 clear_bit_unlock(NFS_INO_INVALIDATING, bitlock);
@@ -1130,6 +1138,29 @@ out:
1130 return ret; 1138 return ret;
1131} 1139}
1132 1140
1141/**
1142 * nfs_revalidate_mapping - Revalidate the pagecache
1143 * @inode - pointer to host inode
1144 * @mapping - pointer to mapping
1145 */
1146int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
1147{
1148 return __nfs_revalidate_mapping(inode, mapping, false);
1149}
1150
1151/**
1152 * nfs_revalidate_mapping_protected - Revalidate the pagecache
1153 * @inode - pointer to host inode
1154 * @mapping - pointer to mapping
1155 *
1156 * Differs from nfs_revalidate_mapping() in that it grabs the inode->i_mutex
1157 * while invalidating the mapping.
1158 */
1159int nfs_revalidate_mapping_protected(struct inode *inode, struct address_space *mapping)
1160{
1161 return __nfs_revalidate_mapping(inode, mapping, true);
1162}
1163
1133static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) 1164static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
1134{ 1165{
1135 struct nfs_inode *nfsi = NFS_I(inode); 1166 struct nfs_inode *nfsi = NFS_I(inode);