summaryrefslogtreecommitdiffstats
path: root/fs/nfs/dir.c
diff options
context:
space:
mode:
authorLinus Torvalds2017-07-22 01:26:01 +0200
committerLinus Torvalds2017-07-22 01:26:01 +0200
commit505d5c11192960a3f0639d1d9e05dffeddd4e874 (patch)
tree4b9f151bda0f7c146107851bb9053fc1ec4c6461 /fs/nfs/dir.c
parentMerge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/g... (diff)
parentNFS/filelayout: Fix racy setting of fl->dsaddr in filelayout_check_deviceid() (diff)
downloadkernel-qcow2-linux-505d5c11192960a3f0639d1d9e05dffeddd4e874.tar.gz
kernel-qcow2-linux-505d5c11192960a3f0639d1d9e05dffeddd4e874.tar.xz
kernel-qcow2-linux-505d5c11192960a3f0639d1d9e05dffeddd4e874.zip
Merge tag 'nfs-for-4.13-2' of git://git.linux-nfs.org/projects/anna/linux-nfs
Pull NFS client bugfixes from Anna Schumaker: "Stable bugfix: - Fix error reporting regression Bugfixes: - Fix setting filelayout ds address race - Fix subtle access bug when using ACLs - Fix setting mnt3_counts array size - Fix a couple of pNFS commit races" * tag 'nfs-for-4.13-2' of git://git.linux-nfs.org/projects/anna/linux-nfs: NFS/filelayout: Fix racy setting of fl->dsaddr in filelayout_check_deviceid() NFS: Be more careful about mapping file permissions NFS: Store the raw NFS access mask in the inode's access cache NFSv3: Convert nfs3_proc_access() to use nfs_access_set_mask() NFS: Refactor NFS access to kernel access mask calculation net/sunrpc/xprt_sock: fix regression in connection error reporting. nfs: count correct array for mnt3_counts array size Revert commit 722f0b891198 ("pNFS: Don't send COMMITs to the DSes if...") pNFS/flexfiles: Handle expired layout segments in ff_layout_initiate_commit() NFS: Fix another COMMIT race in pNFS NFS: Fix a COMMIT race in pNFS mount: copy the port field into the cloned nfs_server structure. NFS: Don't run wake_up_bit() when nobody is waiting... nfs: add export operations
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r--fs/nfs/dir.c47
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);