diff options
Diffstat (limited to 'fs/nfs/dir.c')
| -rw-r--r-- | fs/nfs/dir.c | 73 | 
1 files changed, 36 insertions, 37 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 5f1af4cd1a33..cb22a9f9ae7e 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -455,14 +455,17 @@ bool nfs_use_readdirplus(struct inode *dir, struct dir_context *ctx)  }  /* - * This function is called by the lookup code to request the use of - * readdirplus to accelerate any future lookups in the same + * This function is called by the lookup and getattr code to request the + * use of readdirplus to accelerate any future lookups in the same   * directory.   */ -static  void nfs_advise_use_readdirplus(struct inode *dir)  { -	set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(dir)->flags); +	struct nfs_inode *nfsi = NFS_I(dir); + +	if (nfs_server_capable(dir, NFS_CAP_READDIRPLUS) && +	    !list_empty(&nfsi->open_files)) +		set_bit(NFS_INO_ADVISE_RDPLUS, &nfsi->flags);  }  /* @@ -475,9 +478,12 @@ void nfs_advise_use_readdirplus(struct inode *dir)   */  void nfs_force_use_readdirplus(struct inode *dir)  { -	if (!list_empty(&NFS_I(dir)->open_files)) { -		nfs_advise_use_readdirplus(dir); -		nfs_zap_mapping(dir, dir->i_mapping); +	struct nfs_inode *nfsi = NFS_I(dir); + +	if (nfs_server_capable(dir, NFS_CAP_READDIRPLUS) && +	    !list_empty(&nfsi->open_files)) { +		set_bit(NFS_INO_ADVISE_RDPLUS, &nfsi->flags); +		invalidate_mapping_pages(dir->i_mapping, 0, -1);  	}  } @@ -886,17 +892,6 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc)  	goto out;  } -static bool nfs_dir_mapping_need_revalidate(struct inode *dir) -{ -	struct nfs_inode *nfsi = NFS_I(dir); - -	if (nfs_attribute_cache_expired(dir)) -		return true; -	if (nfsi->cache_validity & NFS_INO_INVALID_DATA) -		return true; -	return false; -} -  /* The file offset position represents the dirent entry number.  A     last cookie cache takes care of the common case of reading the     whole directory. @@ -928,7 +923,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)  	desc->decode = NFS_PROTO(inode)->decode_dirent;  	desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0; -	if (ctx->pos == 0 || nfs_dir_mapping_need_revalidate(inode)) +	if (ctx->pos == 0 || nfs_attribute_cache_expired(inode))  		res = nfs_revalidate_mapping(inode, file->f_mapping);  	if (res < 0)  		goto out; @@ -1035,8 +1030,6 @@ EXPORT_SYMBOL_GPL(nfs_force_lookup_revalidate);  static int nfs_check_verifier(struct inode *dir, struct dentry *dentry,  			      int rcu_walk)  { -	int ret; -  	if (IS_ROOT(dentry))  		return 1;  	if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONE) @@ -1044,12 +1037,12 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry,  	if (!nfs_verify_change_attribute(dir, dentry->d_time))  		return 0;  	/* Revalidate nfsi->cache_change_attribute before we declare a match */ -	if (rcu_walk) -		ret = nfs_revalidate_inode_rcu(NFS_SERVER(dir), dir); -	else -		ret = nfs_revalidate_inode(NFS_SERVER(dir), dir); -	if (ret < 0) -		return 0; +	if (nfs_mapping_need_revalidate_inode(dir)) { +		if (rcu_walk) +			return 0; +		if (__nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0) +			return 0; +	}  	if (!nfs_verify_change_attribute(dir, dentry->d_time))  		return 0;  	return 1; @@ -1161,7 +1154,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)  				return -ECHILD;  			goto out_bad;  		} -		goto out_valid_noent; +		goto out_valid;  	}  	if (is_bad_inode(inode)) { @@ -1184,6 +1177,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)  				return -ECHILD;  			goto out_zap_parent;  		} +		nfs_advise_use_readdirplus(dir);  		goto out_valid;  	} @@ -1219,12 +1213,12 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)  	nfs_free_fhandle(fhandle);  	nfs4_label_free(label); +	/* set a readdirplus hint that we had a cache miss */ +	nfs_force_use_readdirplus(dir); +  out_set_verifier:  	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));   out_valid: -	/* Success: notify readdir to use READDIRPLUS */ -	nfs_advise_use_readdirplus(dir); - out_valid_noent:  	if (flags & LOOKUP_RCU) {  		if (parent != ACCESS_ONCE(dentry->d_parent))  			return -ECHILD; @@ -1424,8 +1418,8 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in  	if (IS_ERR(res))  		goto out_label; -	/* Success: notify readdir to use READDIRPLUS */ -	nfs_advise_use_readdirplus(dir); +	/* Notify readdir to use READDIRPLUS */ +	nfs_force_use_readdirplus(dir);  no_entry:  	res = d_splice_alias(inode, dentry); @@ -1467,9 +1461,9 @@ static fmode_t flags_to_mode(int flags)  	return res;  } -static struct nfs_open_context *create_nfs_open_context(struct dentry *dentry, int open_flags) +static struct nfs_open_context *create_nfs_open_context(struct dentry *dentry, int open_flags, struct file *filp)  { -	return alloc_nfs_open_context(dentry, flags_to_mode(open_flags)); +	return alloc_nfs_open_context(dentry, flags_to_mode(open_flags), filp);  }  static int do_open(struct inode *inode, struct file *filp) @@ -1535,8 +1529,13 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,  		return -ENAMETOOLONG;  	if (open_flags & O_CREAT) { +		struct nfs_server *server = NFS_SERVER(dir); + +		if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK)) +			mode &= ~current_umask(); +  		attr.ia_valid |= ATTR_MODE; -		attr.ia_mode = mode & ~current_umask(); +		attr.ia_mode = mode;  	}  	if (open_flags & O_TRUNC) {  		attr.ia_valid |= ATTR_SIZE; @@ -1554,7 +1553,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,  			return finish_no_open(file, dentry);  	} -	ctx = create_nfs_open_context(dentry, open_flags); +	ctx = create_nfs_open_context(dentry, open_flags, file);  	err = PTR_ERR(ctx);  	if (IS_ERR(ctx))  		goto out;  |