diff options
Diffstat (limited to 'fs/nfs')
| -rw-r--r-- | fs/nfs/Kconfig | 2 | ||||
| -rw-r--r-- | fs/nfs/dir.c | 58 | ||||
| -rw-r--r-- | fs/nfs/inode.c | 7 | ||||
| -rw-r--r-- | fs/nfs/internal.h | 3 | ||||
| -rw-r--r-- | fs/nfs/nfs3xdr.c | 3 | ||||
| -rw-r--r-- | fs/nfs/nfs42proc.c | 12 | ||||
| -rw-r--r-- | fs/nfs/nfs4proc.c | 33 | ||||
| -rw-r--r-- | fs/nfs/unlink.c | 6 | ||||
| -rw-r--r-- | fs/nfs/write.c | 8 | 
9 files changed, 72 insertions, 60 deletions
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index e2a488d403a6..14a72224b657 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig @@ -127,7 +127,7 @@ config PNFS_BLOCK  config PNFS_FLEXFILE_LAYOUT  	tristate  	depends on NFS_V4_1 && NFS_V3 -	default m +	default NFS_V4  config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN  	string "NFSv4.1 Implementation ID Domain" diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 19a9f434442f..fc4f490f2d78 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -81,8 +81,9 @@ static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir  		spin_lock(&dir->i_lock);  		if (list_empty(&nfsi->open_files) &&  		    (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER)) -			nfsi->cache_validity |= NFS_INO_INVALID_DATA | -				NFS_INO_REVAL_FORCED; +			nfs_set_cache_invalid(dir, +					      NFS_INO_INVALID_DATA | +						      NFS_INO_REVAL_FORCED);  		list_add(&ctx->list, &nfsi->open_files);  		spin_unlock(&dir->i_lock);  		return ctx; @@ -1401,6 +1402,13 @@ out_force:  	goto out;  } +static void nfs_mark_dir_for_revalidate(struct inode *inode) +{ +	spin_lock(&inode->i_lock); +	nfs_set_cache_invalid(inode, NFS_INO_REVAL_PAGECACHE); +	spin_unlock(&inode->i_lock); +} +  /*   * We judge how long we want to trust negative   * dentries by looking at the parent inode mtime. @@ -1435,19 +1443,14 @@ nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry,  			__func__, dentry);  		return 1;  	case 0: -		nfs_mark_for_revalidate(dir); -		if (inode && S_ISDIR(inode->i_mode)) { -			/* Purge readdir caches. */ -			nfs_zap_caches(inode); -			/* -			 * We can't d_drop the root of a disconnected tree: -			 * its d_hash is on the s_anon list and d_drop() would hide -			 * it from shrink_dcache_for_unmount(), leading to busy -			 * inodes on unmount and further oopses. -			 */ -			if (IS_ROOT(dentry)) -				return 1; -		} +		/* +		 * We can't d_drop the root of a disconnected tree: +		 * its d_hash is on the s_anon list and d_drop() would hide +		 * it from shrink_dcache_for_unmount(), leading to busy +		 * inodes on unmount and further oopses. +		 */ +		if (inode && IS_ROOT(dentry)) +			return 1;  		dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is invalid\n",  				__func__, dentry);  		return 0; @@ -1525,6 +1528,13 @@ out:  	nfs_free_fattr(fattr);  	nfs_free_fhandle(fhandle);  	nfs4_label_free(label); + +	/* +	 * If the lookup failed despite the dentry change attribute being +	 * a match, then we should revalidate the directory cache. +	 */ +	if (!ret && nfs_verify_change_attribute(dir, dentry->d_time)) +		nfs_mark_dir_for_revalidate(dir);  	return nfs_lookup_revalidate_done(dir, dentry, inode, ret);  } @@ -1567,7 +1577,7 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,  		error = nfs_lookup_verify_inode(inode, flags);  		if (error) {  			if (error == -ESTALE) -				nfs_zap_caches(dir); +				nfs_mark_dir_for_revalidate(dir);  			goto out_bad;  		}  		nfs_advise_use_readdirplus(dir); @@ -1691,10 +1701,9 @@ static void nfs_drop_nlink(struct inode *inode)  	if (inode->i_nlink > 0)  		drop_nlink(inode);  	NFS_I(inode)->attr_gencount = nfs_inc_attr_generation_counter(); -	NFS_I(inode)->cache_validity |= NFS_INO_INVALID_CHANGE -		| NFS_INO_INVALID_CTIME -		| NFS_INO_INVALID_OTHER -		| NFS_INO_REVAL_FORCED; +	nfs_set_cache_invalid( +		inode, NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_CTIME | +			       NFS_INO_INVALID_OTHER | NFS_INO_REVAL_FORCED);  	spin_unlock(&inode->i_lock);  } @@ -1706,7 +1715,7 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)  {  	if (S_ISDIR(inode->i_mode))  		/* drop any readdir cache as it could easily be old */ -		NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA; +		nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA);  	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {  		nfs_complete_unlink(dentry, inode); @@ -2064,7 +2073,6 @@ out:  	dput(parent);  	return d;  out_error: -	nfs_mark_for_revalidate(dir);  	d = ERR_PTR(error);  	goto out;  } @@ -2473,9 +2481,9 @@ int nfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,  	if (error == 0) {  		spin_lock(&old_inode->i_lock);  		NFS_I(old_inode)->attr_gencount = nfs_inc_attr_generation_counter(); -		NFS_I(old_inode)->cache_validity |= NFS_INO_INVALID_CHANGE -			| NFS_INO_INVALID_CTIME -			| NFS_INO_REVAL_FORCED; +		nfs_set_cache_invalid(old_inode, NFS_INO_INVALID_CHANGE | +							 NFS_INO_INVALID_CTIME | +							 NFS_INO_REVAL_FORCED);  		spin_unlock(&old_inode->i_lock);  	}  out: diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 749bbea14d99..a7fb076a5f44 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -207,7 +207,7 @@ static bool nfs_has_xattr_cache(const struct nfs_inode *nfsi)  }  #endif -static void nfs_set_cache_invalid(struct inode *inode, unsigned long flags) +void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)  {  	struct nfs_inode *nfsi = NFS_I(inode);  	bool have_delegation = NFS_PROTO(inode)->have_delegation(inode, FMODE_READ); @@ -229,6 +229,7 @@ static void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)  	if (flags & NFS_INO_INVALID_DATA)  		nfs_fscache_invalidate(inode);  } +EXPORT_SYMBOL_GPL(nfs_set_cache_invalid);  /*   * Invalidate the local caches @@ -1067,8 +1068,8 @@ void nfs_inode_attach_open_context(struct nfs_open_context *ctx)  	spin_lock(&inode->i_lock);  	if (list_empty(&nfsi->open_files) &&  	    (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER)) -		nfsi->cache_validity |= NFS_INO_INVALID_DATA | -			NFS_INO_REVAL_FORCED; +		nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA | +						     NFS_INO_REVAL_FORCED);  	list_add_tail_rcu(&ctx->list, &nfsi->open_files);  	spin_unlock(&inode->i_lock);  } diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 25fb43b69e5a..7b644d6c09e4 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -411,7 +411,8 @@ extern int nfs_write_inode(struct inode *, struct writeback_control *);  extern int nfs_drop_inode(struct inode *);  extern void nfs_clear_inode(struct inode *);  extern void nfs_evict_inode(struct inode *); -void nfs_zap_acl_cache(struct inode *inode); +extern void nfs_zap_acl_cache(struct inode *inode); +extern void nfs_set_cache_invalid(struct inode *inode, unsigned long flags);  extern bool nfs_check_cache_invalid(struct inode *, unsigned long);  extern int nfs_wait_bit_killable(struct wait_bit_key *key, int mode);  extern int nfs_wait_atomic_killable(atomic_t *p, unsigned int mode); diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index ca10072644ff..ed1c83738c30 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c @@ -36,6 +36,7 @@  #define NFS3_pagepad_sz		(1) /* Page padding */  #define NFS3_fhandle_sz		(1+16)  #define NFS3_fh_sz		(NFS3_fhandle_sz)	/* shorthand */ +#define NFS3_post_op_fh_sz	(1+NFS3_fh_sz)  #define NFS3_sattr_sz		(15)  #define NFS3_filename_sz	(1+(NFS3_MAXNAMLEN>>2))  #define NFS3_path_sz		(1+(NFS3_MAXPATHLEN>>2)) @@ -73,7 +74,7 @@  #define NFS3_readlinkres_sz	(1+NFS3_post_op_attr_sz+1+NFS3_pagepad_sz)  #define NFS3_readres_sz		(1+NFS3_post_op_attr_sz+3+NFS3_pagepad_sz)  #define NFS3_writeres_sz	(1+NFS3_wcc_data_sz+4) -#define NFS3_createres_sz	(1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz) +#define NFS3_createres_sz	(1+NFS3_post_op_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)  #define NFS3_renameres_sz	(1+(2 * NFS3_wcc_data_sz))  #define NFS3_linkres_sz		(1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)  #define NFS3_readdirres_sz	(1+NFS3_post_op_attr_sz+2+NFS3_pagepad_sz) diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index f3fd935620fc..094024b0aca1 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c @@ -357,13 +357,15 @@ static ssize_t _nfs42_proc_copy(struct file *src,  	truncate_pagecache_range(dst_inode, pos_dst,  				 pos_dst + res->write_res.count);  	spin_lock(&dst_inode->i_lock); -	NFS_I(dst_inode)->cache_validity |= (NFS_INO_REVAL_PAGECACHE | -			NFS_INO_REVAL_FORCED | NFS_INO_INVALID_SIZE | -			NFS_INO_INVALID_ATTR | NFS_INO_INVALID_DATA); +	nfs_set_cache_invalid( +		dst_inode, NFS_INO_REVAL_PAGECACHE | NFS_INO_REVAL_FORCED | +				   NFS_INO_INVALID_SIZE | NFS_INO_INVALID_ATTR | +				   NFS_INO_INVALID_DATA);  	spin_unlock(&dst_inode->i_lock);  	spin_lock(&src_inode->i_lock); -	NFS_I(src_inode)->cache_validity |= (NFS_INO_REVAL_PAGECACHE | -			NFS_INO_REVAL_FORCED | NFS_INO_INVALID_ATIME); +	nfs_set_cache_invalid(src_inode, NFS_INO_REVAL_PAGECACHE | +						 NFS_INO_REVAL_FORCED | +						 NFS_INO_INVALID_ATIME);  	spin_unlock(&src_inode->i_lock);  	status = res->write_res.count;  out: diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 74bc5120013d..c65c4b41e2c1 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1169,14 +1169,14 @@ int nfs4_call_sync(struct rpc_clnt *clnt,  static void  nfs4_inc_nlink_locked(struct inode *inode)  { -	NFS_I(inode)->cache_validity |= NFS_INO_INVALID_OTHER; +	nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER);  	inc_nlink(inode);  }  static void  nfs4_dec_nlink_locked(struct inode *inode)  { -	NFS_I(inode)->cache_validity |= NFS_INO_INVALID_OTHER; +	nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER);  	drop_nlink(inode);  } @@ -1187,35 +1187,31 @@ nfs4_update_changeattr_locked(struct inode *inode,  {  	struct nfs_inode *nfsi = NFS_I(inode); -	nfsi->cache_validity |= NFS_INO_INVALID_CTIME -		| NFS_INO_INVALID_MTIME -		| cache_validity; +	cache_validity |= NFS_INO_INVALID_CTIME | NFS_INO_INVALID_MTIME;  	if (cinfo->atomic && cinfo->before == inode_peek_iversion_raw(inode)) {  		nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE;  		nfsi->attrtimeo_timestamp = jiffies;  	} else {  		if (S_ISDIR(inode->i_mode)) { -			nfsi->cache_validity |= NFS_INO_INVALID_DATA; +			cache_validity |= NFS_INO_INVALID_DATA;  			nfs_force_lookup_revalidate(inode);  		} else {  			if (!NFS_PROTO(inode)->have_delegation(inode,  							       FMODE_READ)) -				nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; +				cache_validity |= NFS_INO_REVAL_PAGECACHE;  		}  		if (cinfo->before != inode_peek_iversion_raw(inode)) -			nfsi->cache_validity |= NFS_INO_INVALID_ACCESS | -						NFS_INO_INVALID_ACL | -						NFS_INO_INVALID_XATTR; +			cache_validity |= NFS_INO_INVALID_ACCESS | +					  NFS_INO_INVALID_ACL | +					  NFS_INO_INVALID_XATTR;  	}  	inode_set_iversion_raw(inode, cinfo->after);  	nfsi->read_cache_jiffies = timestamp;  	nfsi->attr_gencount = nfs_inc_attr_generation_counter(); +	nfs_set_cache_invalid(inode, cache_validity);  	nfsi->cache_validity &= ~NFS_INO_INVALID_CHANGE; - -	if (nfsi->cache_validity & NFS_INO_INVALID_DATA) -		nfs_fscache_invalidate(inode);  }  void @@ -5893,6 +5889,9 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl  	unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);  	int ret, i; +	/* You can't remove system.nfs4_acl: */ +	if (buflen == 0) +		return -EINVAL;  	if (!nfs4_server_supports_acls(server))  		return -EOPNOTSUPP;  	if (npages > ARRAY_SIZE(pages)) @@ -5915,9 +5914,9 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl  	 * so mark the attribute cache invalid.  	 */  	spin_lock(&inode->i_lock); -	NFS_I(inode)->cache_validity |= NFS_INO_INVALID_CHANGE -		| NFS_INO_INVALID_CTIME -		| NFS_INO_REVAL_FORCED; +	nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE | +					     NFS_INO_INVALID_CTIME | +					     NFS_INO_REVAL_FORCED);  	spin_unlock(&inode->i_lock);  	nfs_access_zap_cache(inode);  	nfs_zap_acl_cache(inode); @@ -5969,7 +5968,7 @@ static int _nfs4_get_security_label(struct inode *inode, void *buf,  		return ret;  	if (!(fattr.valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL))  		return -ENOENT; -	return 0; +	return label.len;  }  static int nfs4_get_security_label(struct inode *inode, void *buf, diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index b27ebdccef70..5fa11e1aca4c 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -500,9 +500,9 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry)  		nfs_set_verifier(dentry, nfs_save_change_attribute(dir));  		spin_lock(&inode->i_lock);  		NFS_I(inode)->attr_gencount = nfs_inc_attr_generation_counter(); -		NFS_I(inode)->cache_validity |= NFS_INO_INVALID_CHANGE -			| NFS_INO_INVALID_CTIME -			| NFS_INO_REVAL_FORCED; +		nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE | +						     NFS_INO_INVALID_CTIME | +						     NFS_INO_REVAL_FORCED);  		spin_unlock(&inode->i_lock);  		d_move(dentry, sdentry);  		break; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 82bdcb982186..f05a90338a76 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -303,9 +303,9 @@ static void nfs_set_pageerror(struct address_space *mapping)  	nfs_zap_mapping(mapping->host, mapping);  	/* Force file size revalidation */  	spin_lock(&inode->i_lock); -	NFS_I(inode)->cache_validity |= NFS_INO_REVAL_FORCED | -					NFS_INO_REVAL_PAGECACHE | -					NFS_INO_INVALID_SIZE; +	nfs_set_cache_invalid(inode, NFS_INO_REVAL_FORCED | +					     NFS_INO_REVAL_PAGECACHE | +					     NFS_INO_INVALID_SIZE);  	spin_unlock(&inode->i_lock);  } @@ -1604,7 +1604,7 @@ static int nfs_writeback_done(struct rpc_task *task,  	/* Deal with the suid/sgid bit corner case */  	if (nfs_should_remove_suid(inode)) {  		spin_lock(&inode->i_lock); -		NFS_I(inode)->cache_validity |= NFS_INO_INVALID_OTHER; +		nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER);  		spin_unlock(&inode->i_lock);  	}  	return 0;  | 
