diff options
Diffstat (limited to 'fs/nfs/dir.c')
| -rw-r--r-- | fs/nfs/dir.c | 47 | 
1 files changed, 37 insertions, 10 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 5ac484fe0dee..3522b1249019 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -2372,16 +2372,40 @@ void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)  }  EXPORT_SYMBOL_GPL(nfs_access_add_cache); +#define NFS_MAY_READ (NFS4_ACCESS_READ) +#define NFS_MAY_WRITE (NFS4_ACCESS_MODIFY | \ +		NFS4_ACCESS_EXTEND | \ +		NFS4_ACCESS_DELETE) +#define NFS_FILE_MAY_WRITE (NFS4_ACCESS_MODIFY | \ +		NFS4_ACCESS_EXTEND) +#define NFS_DIR_MAY_WRITE NFS_MAY_WRITE +#define NFS_MAY_LOOKUP (NFS4_ACCESS_LOOKUP) +#define NFS_MAY_EXECUTE (NFS4_ACCESS_EXECUTE) +static int +nfs_access_calc_mask(u32 access_result, umode_t umode) +{ +	int mask = 0; + +	if (access_result & NFS_MAY_READ) +		mask |= MAY_READ; +	if (S_ISDIR(umode)) { +		if ((access_result & NFS_DIR_MAY_WRITE) == NFS_DIR_MAY_WRITE) +			mask |= MAY_WRITE; +		if ((access_result & NFS_MAY_LOOKUP) == NFS_MAY_LOOKUP) +			mask |= MAY_EXEC; +	} else if (S_ISREG(umode)) { +		if ((access_result & NFS_FILE_MAY_WRITE) == NFS_FILE_MAY_WRITE) +			mask |= MAY_WRITE; +		if ((access_result & NFS_MAY_EXECUTE) == NFS_MAY_EXECUTE) +			mask |= MAY_EXEC; +	} else if (access_result & NFS_MAY_WRITE) +			mask |= MAY_WRITE; +	return mask; +} +  void nfs_access_set_mask(struct nfs_access_entry *entry, u32 access_result)  { -	entry->mask = 0; -	if (access_result & NFS4_ACCESS_READ) -		entry->mask |= MAY_READ; -	if (access_result & -	    (NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE)) -		entry->mask |= MAY_WRITE; -	if (access_result & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE)) -		entry->mask |= MAY_EXEC; +	entry->mask = access_result;  }  EXPORT_SYMBOL_GPL(nfs_access_set_mask); @@ -2389,6 +2413,7 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)  {  	struct nfs_access_entry cache;  	bool may_block = (mask & MAY_NOT_BLOCK) == 0; +	int cache_mask;  	int status;  	trace_nfs_access_enter(inode); @@ -2404,7 +2429,8 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)  		goto out;  	/* Be clever: ask server to check for all possible rights */ -	cache.mask = MAY_EXEC | MAY_WRITE | MAY_READ; +	cache.mask = NFS_MAY_LOOKUP | NFS_MAY_EXECUTE +		     | NFS_MAY_WRITE | NFS_MAY_READ;  	cache.cred = cred;  	cache.jiffies = jiffies;  	status = NFS_PROTO(inode)->access(inode, &cache); @@ -2418,7 +2444,8 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)  	}  	nfs_access_add_cache(inode, &cache);  out_cached: -	if ((mask & ~cache.mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) != 0) +	cache_mask = nfs_access_calc_mask(cache.mask, inode->i_mode); +	if ((mask & ~cache_mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) != 0)  		status = -EACCES;  out:  	trace_nfs_access_exit(inode, status);  | 
