aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2005-06-22 13:16:30 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2005-06-22 16:07:36 -0400
commit951a143b3fcf15cfa9d38250b7462f821db241db (patch)
tree6e4ea13c5f48cc3e1ac1c8649dd0f9f20c502e20
parent08e9eac42edab63bce14b5c8419771f3c92aa3f4 (diff)
[PATCH] NFS: Fix the file size revalidation
Instead of looking at whether or not the file is open for writes before we accept to update the length using the server value, we should rather be looking at whether or not we are currently caching any writes. Failure to do so means in particular that we're not updating the file length correctly after obtaining a POSIX or BSD lock. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/direct.c2
-rw-r--r--fs/nfs/inode.c69
-rw-r--r--fs/nfs/write.c4
-rw-r--r--include/linux/nfs_fs.h1
4 files changed, 21 insertions, 55 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 68df803f27ca..d6a30c844de3 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -517,7 +517,7 @@ retry:
517 result = tot_bytes; 517 result = tot_bytes;
518 518
519out: 519out:
520 nfs_end_data_update_defer(inode); 520 nfs_end_data_update(inode);
521 nfs_writedata_free(wdata); 521 nfs_writedata_free(wdata);
522 return result; 522 return result;
523 523
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 6300e05e9463..b2d16758ced8 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1148,27 +1148,6 @@ void nfs_end_data_update(struct inode *inode)
1148} 1148}
1149 1149
1150/** 1150/**
1151 * nfs_end_data_update_defer
1152 * @inode - pointer to inode
1153 * Declare end of the operations that will update file data
1154 * This will defer marking the inode as needing revalidation
1155 * unless there are no other pending updates.
1156 */
1157void nfs_end_data_update_defer(struct inode *inode)
1158{
1159 struct nfs_inode *nfsi = NFS_I(inode);
1160
1161 if (atomic_dec_and_test(&nfsi->data_updates)) {
1162 /* Mark the attribute cache for revalidation */
1163 nfsi->flags |= NFS_INO_INVALID_ATTR;
1164 /* Directories and symlinks: invalidate page cache too */
1165 if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
1166 nfsi->flags |= NFS_INO_INVALID_DATA;
1167 nfsi->cache_change_attribute ++;
1168 }
1169}
1170
1171/**
1172 * nfs_refresh_inode - verify consistency of the inode attribute cache 1151 * nfs_refresh_inode - verify consistency of the inode attribute cache
1173 * @inode - pointer to inode 1152 * @inode - pointer to inode
1174 * @fattr - updated attributes 1153 * @fattr - updated attributes
@@ -1222,8 +1201,8 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
1222 if (!timespec_equal(&inode->i_mtime, &fattr->mtime) 1201 if (!timespec_equal(&inode->i_mtime, &fattr->mtime)
1223 || cur_size != new_isize) 1202 || cur_size != new_isize)
1224 nfsi->flags |= NFS_INO_INVALID_ATTR; 1203 nfsi->flags |= NFS_INO_INVALID_ATTR;
1225 } else if (S_ISREG(inode->i_mode) && new_isize > cur_size) 1204 } else if (new_isize != cur_size && nfsi->npages == 0)
1226 nfsi->flags |= NFS_INO_INVALID_ATTR; 1205 nfsi->flags |= NFS_INO_INVALID_ATTR;
1227 1206
1228 /* Have any file permissions changed? */ 1207 /* Have any file permissions changed? */
1229 if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) 1208 if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
@@ -1257,10 +1236,8 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
1257static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier) 1236static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier)
1258{ 1237{
1259 struct nfs_inode *nfsi = NFS_I(inode); 1238 struct nfs_inode *nfsi = NFS_I(inode);
1260 __u64 new_size; 1239 loff_t cur_isize, new_isize;
1261 loff_t new_isize;
1262 unsigned int invalid = 0; 1240 unsigned int invalid = 0;
1263 loff_t cur_isize;
1264 int data_unstable; 1241 int data_unstable;
1265 1242
1266 dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", 1243 dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
@@ -1293,49 +1270,39 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
1293 /* Are we racing with known updates of the metadata on the server? */ 1270 /* Are we racing with known updates of the metadata on the server? */
1294 data_unstable = ! nfs_verify_change_attribute(inode, verifier); 1271 data_unstable = ! nfs_verify_change_attribute(inode, verifier);
1295 1272
1296 /* Check if the file size agrees */ 1273 /* Check if our cached file size is stale */
1297 new_size = fattr->size;
1298 new_isize = nfs_size_to_loff_t(fattr->size); 1274 new_isize = nfs_size_to_loff_t(fattr->size);
1299 cur_isize = i_size_read(inode); 1275 cur_isize = i_size_read(inode);
1300 if (cur_isize != new_size) { 1276 if (new_isize != cur_isize) {
1301#ifdef NFS_DEBUG_VERBOSE 1277 /* Do we perhaps have any outstanding writes? */
1302 printk(KERN_DEBUG "NFS: isize change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino); 1278 if (nfsi->npages == 0) {
1303#endif 1279 /* No, but did we race with nfs_end_data_update()? */
1304 /* 1280 if (verifier == nfsi->cache_change_attribute) {
1305 * If we have pending writebacks, things can get
1306 * messy.
1307 */
1308 if (S_ISREG(inode->i_mode) && data_unstable) {
1309 if (new_isize > cur_isize) {
1310 inode->i_size = new_isize; 1281 inode->i_size = new_isize;
1311 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; 1282 invalid |= NFS_INO_INVALID_DATA;
1312 } 1283 }
1313 } else { 1284 invalid |= NFS_INO_INVALID_ATTR;
1285 } else if (new_isize > cur_isize) {
1314 inode->i_size = new_isize; 1286 inode->i_size = new_isize;
1315 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; 1287 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
1316 } 1288 }
1289 dprintk("NFS: isize change on server for file %s/%ld\n",
1290 inode->i_sb->s_id, inode->i_ino);
1317 } 1291 }
1318 1292
1319 /* 1293 /* Check if the mtime agrees */
1320 * Note: we don't check inode->i_mtime since pipes etc.
1321 * can change this value in VFS without requiring a
1322 * cache revalidation.
1323 */
1324 if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { 1294 if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
1325 memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); 1295 memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
1326#ifdef NFS_DEBUG_VERBOSE 1296 dprintk("NFS: mtime change on server for file %s/%ld\n",
1327 printk(KERN_DEBUG "NFS: mtime change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino); 1297 inode->i_sb->s_id, inode->i_ino);
1328#endif
1329 if (!data_unstable) 1298 if (!data_unstable)
1330 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; 1299 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
1331 } 1300 }
1332 1301
1333 if ((fattr->valid & NFS_ATTR_FATTR_V4) 1302 if ((fattr->valid & NFS_ATTR_FATTR_V4)
1334 && nfsi->change_attr != fattr->change_attr) { 1303 && nfsi->change_attr != fattr->change_attr) {
1335#ifdef NFS_DEBUG_VERBOSE 1304 dprintk("NFS: change_attr change on server for file %s/%ld\n",
1336 printk(KERN_DEBUG "NFS: change_attr change on %s/%ld\n",
1337 inode->i_sb->s_id, inode->i_ino); 1305 inode->i_sb->s_id, inode->i_ino);
1338#endif
1339 nfsi->change_attr = fattr->change_attr; 1306 nfsi->change_attr = fattr->change_attr;
1340 if (!data_unstable) 1307 if (!data_unstable)
1341 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; 1308 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 6f7a4af3bc46..c574d551f029 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -220,7 +220,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode,
220 ClearPageError(page); 220 ClearPageError(page);
221 221
222io_error: 222io_error:
223 nfs_end_data_update_defer(inode); 223 nfs_end_data_update(inode);
224 nfs_writedata_free(wdata); 224 nfs_writedata_free(wdata);
225 return written ? written : result; 225 return written ? written : result;
226} 226}
@@ -401,7 +401,7 @@ static void nfs_inode_remove_request(struct nfs_page *req)
401 nfsi->npages--; 401 nfsi->npages--;
402 if (!nfsi->npages) { 402 if (!nfsi->npages) {
403 spin_unlock(&nfsi->req_lock); 403 spin_unlock(&nfsi->req_lock);
404 nfs_end_data_update_defer(inode); 404 nfs_end_data_update(inode);
405 iput(inode); 405 iput(inode);
406 } else 406 } else
407 spin_unlock(&nfsi->req_lock); 407 spin_unlock(&nfsi->req_lock);
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index c90313bfa435..211266c56ce5 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -294,7 +294,6 @@ extern void nfs_begin_attr_update(struct inode *);
294extern void nfs_end_attr_update(struct inode *); 294extern void nfs_end_attr_update(struct inode *);
295extern void nfs_begin_data_update(struct inode *); 295extern void nfs_begin_data_update(struct inode *);
296extern void nfs_end_data_update(struct inode *); 296extern void nfs_end_data_update(struct inode *);
297extern void nfs_end_data_update_defer(struct inode *);
298extern struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred); 297extern struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred);
299extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); 298extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
300extern void put_nfs_open_context(struct nfs_open_context *ctx); 299extern void put_nfs_open_context(struct nfs_open_context *ctx);