Commit b79c3f26 authored by Trond Myklebust's avatar Trond Myklebust

NFS: Clean up nfs_permission().

 Fix a bug whereby we are failing to test for permissions on opendir().
 Optimize away permissions checks that request MAY_WRITE on directories.
 Ensure that VFS sets LOOKUP_CONTINUE before calling permission().
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent f6e9e45c
...@@ -1498,21 +1498,34 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) ...@@ -1498,21 +1498,34 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
int nfs_permission(struct inode *inode, int mask, struct nameidata *nd) int nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
{ {
struct rpc_cred *cred; struct rpc_cred *cred;
int res; int res = 0;
if (mask == 0) if (mask == 0)
return 0; goto out;
/* Is this sys_access() ? */
if (nd != NULL && (nd->flags & LOOKUP_ACCESS))
goto force_lookup;
/* Are we checking permissions on anything other than lookup/execute? */ switch (inode->i_mode & S_IFMT) {
if ((mask & MAY_EXEC) == 0) { case S_IFLNK:
/* We only need to check permissions on file open() and access() */ goto out;
if (!nd || !(nd->flags & (LOOKUP_OPEN|LOOKUP_ACCESS))) case S_IFREG:
return 0;
/* NFSv4 has atomic_open... */ /* NFSv4 has atomic_open... */
if (NFS_PROTO(inode)->version > 3 && (nd->flags & LOOKUP_OPEN)) if (nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN)
return 0; && nd != NULL
&& (nd->flags & LOOKUP_OPEN))
goto out;
break;
case S_IFDIR:
/*
* Optimize away all write operations, since the server
* will check permissions when we perform the op.
*/
if ((mask & MAY_WRITE) && !(mask & MAY_READ))
goto out;
} }
force_lookup:
lock_kernel(); lock_kernel();
if (!NFS_PROTO(inode)->access) if (!NFS_PROTO(inode)->access)
...@@ -1522,6 +1535,7 @@ int nfs_permission(struct inode *inode, int mask, struct nameidata *nd) ...@@ -1522,6 +1535,7 @@ int nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
res = nfs_do_access(inode, cred, mask); res = nfs_do_access(inode, cred, mask);
put_rpccred(cred); put_rpccred(cred);
unlock_kernel(); unlock_kernel();
out:
return res; return res;
out_notsup: out_notsup:
nfs_revalidate_inode(NFS_SERVER(inode), inode); nfs_revalidate_inode(NFS_SERVER(inode), inode);
......
...@@ -1542,6 +1542,7 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, ...@@ -1542,6 +1542,7 @@ static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data,
if (data->wsize != 0) if (data->wsize != 0)
server->wsize = nfs_block_size(data->wsize, NULL); server->wsize = nfs_block_size(data->wsize, NULL);
server->flags = data->flags & NFS_MOUNT_FLAGMASK; server->flags = data->flags & NFS_MOUNT_FLAGMASK;
server->caps = NFS_CAP_ATOMIC_OPEN;
server->acregmin = data->acregmin*HZ; server->acregmin = data->acregmin*HZ;
server->acregmax = data->acregmax*HZ; server->acregmax = data->acregmax*HZ;
......
...@@ -53,5 +53,6 @@ struct nfs_server { ...@@ -53,5 +53,6 @@ struct nfs_server {
#define NFS_CAP_HARDLINKS (1U << 1) #define NFS_CAP_HARDLINKS (1U << 1)
#define NFS_CAP_SYMLINKS (1U << 2) #define NFS_CAP_SYMLINKS (1U << 2)
#define NFS_CAP_ACLS (1U << 3) #define NFS_CAP_ACLS (1U << 3)
#define NFS_CAP_ATOMIC_OPEN (1U << 4)
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment