NFS: Fix a few further cache consistency regressions

Steve Dickson writes:
Doing the following:
1. On server:
$ mkdir ~/t
$ echo Hello > ~/t/tmp

2. On client, wait for a string to appear in this file:
$ until grep -q foo t/tmp ; do echo -n . ; sleep 1 ; done

3. On server, create a *new* file with the same name containing that
string:
$ mv ~/t/tmp ~/t/tmp.old; echo foo > ~/t/tmp

will show how the client will never (and I mean never ;-) ) see
the updated file.

The problem is that we do not update nfsi->cache_change_attribute when the
file changes on the server (we only update it when our client makes the
changes). This again means that functions like nfs_check_verifier() will
fail to register when the parent directory has changed and should trigger
a dentry lookup revalidation.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

+20 -34
+20 -34
fs/nfs/inode.c
··· 54 54 #define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) 55 55 56 56 static void nfs_invalidate_inode(struct inode *); 57 - static int nfs_update_inode(struct inode *, struct nfs_fattr *, unsigned long); 57 + static int nfs_update_inode(struct inode *, struct nfs_fattr *); 58 58 59 59 static struct inode *nfs_alloc_inode(struct super_block *sb); 60 60 static void nfs_destroy_inode(struct inode *); ··· 1080 1080 int status = -ESTALE; 1081 1081 struct nfs_fattr fattr; 1082 1082 struct nfs_inode *nfsi = NFS_I(inode); 1083 - unsigned long verifier; 1084 - unsigned long cache_validity; 1085 1083 1086 1084 dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n", 1087 1085 inode->i_sb->s_id, (long long)NFS_FILEID(inode)); ··· 1104 1106 } 1105 1107 } 1106 1108 1107 - /* Protect against RPC races by saving the change attribute */ 1108 - verifier = nfs_save_change_attribute(inode); 1109 1109 status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), &fattr); 1110 1110 if (status != 0) { 1111 1111 dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n", ··· 1118 1122 } 1119 1123 1120 1124 spin_lock(&inode->i_lock); 1121 - status = nfs_update_inode(inode, &fattr, verifier); 1125 + status = nfs_update_inode(inode, &fattr); 1122 1126 if (status) { 1123 1127 spin_unlock(&inode->i_lock); 1124 1128 dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n", ··· 1126 1130 (long long)NFS_FILEID(inode), status); 1127 1131 goto out; 1128 1132 } 1129 - cache_validity = nfsi->cache_validity; 1130 - nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE; 1131 - 1132 - /* 1133 - * We may need to keep the attributes marked as invalid if 1134 - * we raced with nfs_end_attr_update(). 1135 - */ 1136 - if (time_after_eq(verifier, nfsi->cache_change_attribute)) 1137 - nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); 1138 1133 spin_unlock(&inode->i_lock); 1139 1134 1140 1135 nfs_revalidate_mapping(inode, inode->i_mapping); 1141 1136 1142 - if (cache_validity & NFS_INO_INVALID_ACL) 1137 + if (nfsi->cache_validity & NFS_INO_INVALID_ACL) 1143 1138 nfs_zap_acl_cache(inode); 1144 1139 1145 1140 dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", ··· 1333 1346 return 0; 1334 1347 spin_lock(&inode->i_lock); 1335 1348 nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE; 1336 - if (nfs_verify_change_attribute(inode, fattr->time_start)) 1337 - nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); 1338 1349 if (time_after(fattr->time_start, nfsi->last_updated)) 1339 - status = nfs_update_inode(inode, fattr, fattr->time_start); 1350 + status = nfs_update_inode(inode, fattr); 1340 1351 else 1341 1352 status = nfs_check_inode_attributes(inode, fattr); 1342 1353 ··· 1360 1375 nfsi->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS; 1361 1376 goto out; 1362 1377 } 1363 - status = nfs_update_inode(inode, fattr, fattr->time_start); 1364 - if (time_after_eq(fattr->time_start, nfsi->cache_change_attribute)) 1365 - nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME|NFS_INO_REVAL_PAGECACHE); 1366 - nfsi->cache_change_attribute = jiffies; 1378 + status = nfs_update_inode(inode, fattr); 1367 1379 out: 1368 1380 spin_unlock(&inode->i_lock); 1369 1381 return status; ··· 1378 1396 * 1379 1397 * A very similar scenario holds for the dir cache. 1380 1398 */ 1381 - static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier) 1399 + static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) 1382 1400 { 1383 1401 struct nfs_inode *nfsi = NFS_I(inode); 1384 1402 loff_t cur_isize, new_isize; 1385 1403 unsigned int invalid = 0; 1386 - int data_unstable; 1404 + int data_stable; 1387 1405 1388 1406 dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", 1389 1407 __FUNCTION__, inode->i_sb->s_id, inode->i_ino, ··· 1414 1432 nfsi->last_updated = jiffies; 1415 1433 1416 1434 /* Are we racing with known updates of the metadata on the server? */ 1417 - data_unstable = ! (nfs_verify_change_attribute(inode, verifier) || 1418 - (nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE)); 1435 + data_stable = nfs_verify_change_attribute(inode, fattr->time_start); 1436 + if (data_stable) 1437 + nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); 1419 1438 1420 1439 /* Check if our cached file size is stale */ 1421 1440 new_isize = nfs_size_to_loff_t(fattr->size); ··· 1425 1442 /* Do we perhaps have any outstanding writes? */ 1426 1443 if (nfsi->npages == 0) { 1427 1444 /* No, but did we race with nfs_end_data_update()? */ 1428 - if (time_after_eq(verifier, nfsi->cache_change_attribute)) { 1445 + if (data_stable) { 1429 1446 inode->i_size = new_isize; 1430 1447 invalid |= NFS_INO_INVALID_DATA; 1431 1448 } ··· 1434 1451 inode->i_size = new_isize; 1435 1452 invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; 1436 1453 } 1454 + nfsi->cache_change_attribute = jiffies; 1437 1455 dprintk("NFS: isize change on server for file %s/%ld\n", 1438 1456 inode->i_sb->s_id, inode->i_ino); 1439 1457 } ··· 1444 1460 memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); 1445 1461 dprintk("NFS: mtime change on server for file %s/%ld\n", 1446 1462 inode->i_sb->s_id, inode->i_ino); 1447 - if (!data_unstable) 1448 - invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; 1463 + invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; 1464 + nfsi->cache_change_attribute = jiffies; 1449 1465 } 1450 1466 1451 1467 if ((fattr->valid & NFS_ATTR_FATTR_V4) ··· 1453 1469 dprintk("NFS: change_attr change on server for file %s/%ld\n", 1454 1470 inode->i_sb->s_id, inode->i_ino); 1455 1471 nfsi->change_attr = fattr->change_attr; 1456 - if (!data_unstable) 1457 - invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; 1472 + invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; 1473 + nfsi->cache_change_attribute = jiffies; 1458 1474 } 1459 1475 1460 1476 /* If ctime has changed we should definitely clear access+acl caches */ 1461 1477 if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { 1462 - if (!data_unstable) 1463 - invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; 1478 + invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; 1464 1479 memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); 1480 + nfsi->cache_change_attribute = jiffies; 1465 1481 } 1466 1482 memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); 1467 1483 ··· 1499 1515 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) 1500 1516 || S_ISLNK(inode->i_mode))) 1501 1517 invalid &= ~NFS_INO_INVALID_DATA; 1518 + if (data_stable) 1519 + invalid &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME|NFS_INO_REVAL_PAGECACHE); 1502 1520 if (!nfs_have_delegation(inode, FMODE_READ)) 1503 1521 nfsi->cache_validity |= invalid; 1504 1522