diff options
Diffstat (limited to 'fs/nfs/inode.c')
| -rw-r--r-- | fs/nfs/inode.c | 92 | 
1 files changed, 78 insertions, 14 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index bd7938eda6a..fe5a8b45d86 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -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:  |