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