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)
int nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
{
struct rpc_cred *cred;
int res;
int res = 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? */
if ((mask & MAY_EXEC) == 0) {
/* We only need to check permissions on file open() and access() */
if (!nd || !(nd->flags & (LOOKUP_OPEN|LOOKUP_ACCESS)))
return 0;
switch (inode->i_mode & S_IFMT) {
case S_IFLNK:
goto out;
case S_IFREG:
/* NFSv4 has atomic_open... */
if (NFS_PROTO(inode)->version > 3 && (nd->flags & LOOKUP_OPEN))
return 0;
if (nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN)
&& 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();
if (!NFS_PROTO(inode)->access)
......@@ -1522,6 +1535,7 @@ int nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
res = nfs_do_access(inode, cred, mask);
put_rpccred(cred);
unlock_kernel();
out:
return res;
out_notsup:
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,
if (data->wsize != 0)
server->wsize = nfs_block_size(data->wsize, NULL);
server->flags = data->flags & NFS_MOUNT_FLAGMASK;
server->caps = NFS_CAP_ATOMIC_OPEN;
server->acregmin = data->acregmin*HZ;
server->acregmax = data->acregmax*HZ;
......
......@@ -53,5 +53,6 @@ struct nfs_server {
#define NFS_CAP_HARDLINKS (1U << 1)
#define NFS_CAP_SYMLINKS (1U << 2)
#define NFS_CAP_ACLS (1U << 3)
#define NFS_CAP_ATOMIC_OPEN (1U << 4)
#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