|
@@ -286,6 +286,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
|
|
|
/* We can't support update_atime(), since the server will reset it */
|
|
|
inode->i_flags |= S_NOATIME|S_NOCMTIME;
|
|
|
inode->i_mode = fattr->mode;
|
|
|
+ if ((fattr->valid & NFS_ATTR_FATTR_MODE) == 0
|
|
|
+ && nfs_server_capable(inode, NFS_CAP_MODE))
|
|
|
+ nfsi->cache_validity |= NFS_INO_INVALID_ATTR
|
|
|
+ | NFS_INO_INVALID_ACCESS
|
|
|
+ | NFS_INO_INVALID_ACL;
|
|
|
/* Why so? Because we want revalidate for devices/FIFOs, and
|
|
|
* that's precisely what we have in nfs_file_inode_operations.
|
|
|
*/
|
|
@@ -330,20 +335,46 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
|
|
|
nfsi->attr_gencount = fattr->gencount;
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_ATIME)
|
|
|
inode->i_atime = fattr->atime;
|
|
|
+ else if (nfs_server_capable(inode, NFS_CAP_ATIME))
|
|
|
+ nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_MTIME)
|
|
|
inode->i_mtime = fattr->mtime;
|
|
|
+ else if (nfs_server_capable(inode, NFS_CAP_MTIME))
|
|
|
+ nfsi->cache_validity |= NFS_INO_INVALID_ATTR
|
|
|
+ | NFS_INO_INVALID_DATA;
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_CTIME)
|
|
|
inode->i_ctime = fattr->ctime;
|
|
|
+ else if (nfs_server_capable(inode, NFS_CAP_CTIME))
|
|
|
+ nfsi->cache_validity |= NFS_INO_INVALID_ATTR
|
|
|
+ | NFS_INO_INVALID_ACCESS
|
|
|
+ | NFS_INO_INVALID_ACL;
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
|
|
|
nfsi->change_attr = fattr->change_attr;
|
|
|
+ else if (nfs_server_capable(inode, NFS_CAP_CHANGE_ATTR))
|
|
|
+ nfsi->cache_validity |= NFS_INO_INVALID_ATTR
|
|
|
+ | NFS_INO_INVALID_DATA;
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_SIZE)
|
|
|
inode->i_size = nfs_size_to_loff_t(fattr->size);
|
|
|
+ else
|
|
|
+ nfsi->cache_validity |= NFS_INO_INVALID_ATTR
|
|
|
+ | NFS_INO_INVALID_DATA
|
|
|
+ | NFS_INO_REVAL_PAGECACHE;
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_NLINK)
|
|
|
inode->i_nlink = fattr->nlink;
|
|
|
+ else if (nfs_server_capable(inode, NFS_CAP_NLINK))
|
|
|
+ nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_OWNER)
|
|
|
inode->i_uid = fattr->uid;
|
|
|
+ else if (nfs_server_capable(inode, NFS_CAP_OWNER))
|
|
|
+ nfsi->cache_validity |= NFS_INO_INVALID_ATTR
|
|
|
+ | NFS_INO_INVALID_ACCESS
|
|
|
+ | NFS_INO_INVALID_ACL;
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_GROUP)
|
|
|
inode->i_gid = fattr->gid;
|
|
|
+ else if (nfs_server_capable(inode, NFS_CAP_OWNER_GROUP))
|
|
|
+ nfsi->cache_validity |= NFS_INO_INVALID_ATTR
|
|
|
+ | NFS_INO_INVALID_ACCESS
|
|
|
+ | NFS_INO_INVALID_ACL;
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
|
|
|
inode->i_blocks = fattr->du.nfs2.blocks;
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
|
|
@@ -1145,6 +1176,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|
|
loff_t cur_isize, new_isize;
|
|
|
unsigned long invalid = 0;
|
|
|
unsigned long now = jiffies;
|
|
|
+ unsigned long save_cache_validity;
|
|
|
|
|
|
dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
|
|
|
__func__, inode->i_sb->s_id, inode->i_ino,
|
|
@@ -1171,10 +1203,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|
|
*/
|
|
|
nfsi->read_cache_jiffies = fattr->time_start;
|
|
|
|
|
|
- if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) || (fattr->valid & (NFS_ATTR_FATTR_MTIME|NFS_ATTR_FATTR_CTIME)))
|
|
|
- nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
|
|
|
- | NFS_INO_INVALID_ATIME
|
|
|
- | NFS_INO_REVAL_PAGECACHE);
|
|
|
+ save_cache_validity = nfsi->cache_validity;
|
|
|
+ nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
|
|
|
+ | NFS_INO_INVALID_ATIME
|
|
|
+ | NFS_INO_REVAL_FORCED
|
|
|
+ | NFS_INO_REVAL_PAGECACHE);
|
|
|
|
|
|
/* Do atomic weak cache consistency updates */
|
|
|
nfs_wcc_update_inode(inode, fattr);
|
|
@@ -1189,7 +1222,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|
|
nfs_force_lookup_revalidate(inode);
|
|
|
nfsi->change_attr = fattr->change_attr;
|
|
|
}
|
|
|
- }
|
|
|
+ } else if (server->caps & NFS_CAP_CHANGE_ATTR)
|
|
|
+ invalid |= save_cache_validity;
|
|
|
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_MTIME) {
|
|
|
/* NFSv2/v3: Check if the mtime agrees */
|
|
@@ -1201,7 +1235,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|
|
nfs_force_lookup_revalidate(inode);
|
|
|
memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
|
|
|
}
|
|
|
- }
|
|
|
+ } else if (server->caps & NFS_CAP_MTIME)
|
|
|
+ invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
|
|
|
+ | NFS_INO_INVALID_DATA
|
|
|
+ | NFS_INO_REVAL_PAGECACHE
|
|
|
+ | NFS_INO_REVAL_FORCED);
|
|
|
+
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_CTIME) {
|
|
|
/* If ctime has changed we should definitely clear access+acl caches */
|
|
|
if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) {
|
|
@@ -1215,7 +1254,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|
|
}
|
|
|
memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
|
|
|
}
|
|
|
- }
|
|
|
+ } else if (server->caps & NFS_CAP_CTIME)
|
|
|
+ invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
|
|
|
+ | NFS_INO_INVALID_ACCESS
|
|
|
+ | NFS_INO_INVALID_ACL
|
|
|
+ | NFS_INO_REVAL_FORCED);
|
|
|
|
|
|
/* Check if our cached file size is stale */
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
|
|
@@ -1231,30 +1274,50 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|
|
dprintk("NFS: isize change on server for file %s/%ld\n",
|
|
|
inode->i_sb->s_id, inode->i_ino);
|
|
|
}
|
|
|
- }
|
|
|
+ } else
|
|
|
+ invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
|
|
|
+ | NFS_INO_REVAL_PAGECACHE
|
|
|
+ | NFS_INO_REVAL_FORCED);
|
|
|
|
|
|
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_ATIME)
|
|
|
memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
|
|
|
+ else if (server->caps & NFS_CAP_ATIME)
|
|
|
+ invalid |= save_cache_validity & (NFS_INO_INVALID_ATIME
|
|
|
+ | NFS_INO_REVAL_FORCED);
|
|
|
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_MODE) {
|
|
|
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) {
|
|
|
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
|
|
|
inode->i_mode = fattr->mode;
|
|
|
}
|
|
|
- }
|
|
|
+ } else if (server->caps & NFS_CAP_MODE)
|
|
|
+ invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
|
|
|
+ | NFS_INO_INVALID_ACCESS
|
|
|
+ | NFS_INO_INVALID_ACL
|
|
|
+ | NFS_INO_REVAL_FORCED);
|
|
|
+
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_OWNER) {
|
|
|
if (inode->i_uid != fattr->uid) {
|
|
|
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
|
|
|
inode->i_uid = fattr->uid;
|
|
|
}
|
|
|
- }
|
|
|
+ } else if (server->caps & NFS_CAP_OWNER)
|
|
|
+ invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
|
|
|
+ | NFS_INO_INVALID_ACCESS
|
|
|
+ | NFS_INO_INVALID_ACL
|
|
|
+ | NFS_INO_REVAL_FORCED);
|
|
|
+
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_GROUP) {
|
|
|
if (inode->i_gid != fattr->gid) {
|
|
|
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
|
|
|
inode->i_gid = fattr->gid;
|
|
|
}
|
|
|
- }
|
|
|
+ } else if (server->caps & NFS_CAP_OWNER_GROUP)
|
|
|
+ invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
|
|
|
+ | NFS_INO_INVALID_ACCESS
|
|
|
+ | NFS_INO_INVALID_ACL
|
|
|
+ | NFS_INO_REVAL_FORCED);
|
|
|
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_NLINK) {
|
|
|
if (inode->i_nlink != fattr->nlink) {
|
|
@@ -1263,7 +1326,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|
|
invalid |= NFS_INO_INVALID_DATA;
|
|
|
inode->i_nlink = fattr->nlink;
|
|
|
}
|
|
|
- }
|
|
|
+ } else if (server->caps & NFS_CAP_NLINK)
|
|
|
+ invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
|
|
|
+ | NFS_INO_REVAL_FORCED);
|
|
|
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
|
|
|
/*
|
|
@@ -1293,9 +1358,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|
|
|| S_ISLNK(inode->i_mode)))
|
|
|
invalid &= ~NFS_INO_INVALID_DATA;
|
|
|
if (!nfs_have_delegation(inode, FMODE_READ) ||
|
|
|
- (nfsi->cache_validity & NFS_INO_REVAL_FORCED))
|
|
|
+ (save_cache_validity & NFS_INO_REVAL_FORCED))
|
|
|
nfsi->cache_validity |= invalid;
|
|
|
- nfsi->cache_validity &= ~NFS_INO_REVAL_FORCED;
|
|
|
|
|
|
return 0;
|
|
|
out_changed:
|