Merge remote-tracking branch 'mkp-scsi/4.5/scsi-fixes' into fixes
[cascardo/linux.git] / fs / nfs / dir.c
index ce5a218..9cce670 100644 (file)
@@ -940,7 +940,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence)
        dfprintk(FILE, "NFS: llseek dir(%pD2, %lld, %d)\n",
                        filp, offset, whence);
 
-       mutex_lock(&inode->i_mutex);
+       inode_lock(inode);
        switch (whence) {
                case 1:
                        offset += filp->f_pos;
@@ -957,7 +957,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence)
                dir_ctx->duped = 0;
        }
 out:
-       mutex_unlock(&inode->i_mutex);
+       inode_unlock(inode);
        return offset;
 }
 
@@ -972,9 +972,9 @@ static int nfs_fsync_dir(struct file *filp, loff_t start, loff_t end,
 
        dfprintk(FILE, "NFS: fsync dir(%pD2) datasync %d\n", filp, datasync);
 
-       mutex_lock(&inode->i_mutex);
+       inode_lock(inode);
        nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
-       mutex_unlock(&inode->i_mutex);
+       inode_unlock(inode);
        return 0;
 }
 
@@ -1894,15 +1894,14 @@ int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
        attr.ia_mode = S_IFLNK | S_IRWXUGO;
        attr.ia_valid = ATTR_MODE;
 
-       page = alloc_page(GFP_HIGHUSER);
+       page = alloc_page(GFP_USER);
        if (!page)
                return -ENOMEM;
 
-       kaddr = kmap_atomic(page);
+       kaddr = page_address(page);
        memcpy(kaddr, symname, pathlen);
        if (pathlen < PAGE_SIZE)
                memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen);
-       kunmap_atomic(kaddr);
 
        trace_nfs_symlink_enter(dir, dentry);
        error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr);
@@ -2432,6 +2431,20 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags)
 }
 EXPORT_SYMBOL_GPL(nfs_may_open);
 
+static int nfs_execute_ok(struct inode *inode, int mask)
+{
+       struct nfs_server *server = NFS_SERVER(inode);
+       int ret;
+
+       if (mask & MAY_NOT_BLOCK)
+               ret = nfs_revalidate_inode_rcu(server, inode);
+       else
+               ret = nfs_revalidate_inode(server, inode);
+       if (ret == 0 && !execute_ok(inode))
+               ret = -EACCES;
+       return ret;
+}
+
 int nfs_permission(struct inode *inode, int mask)
 {
        struct rpc_cred *cred;
@@ -2449,6 +2462,9 @@ int nfs_permission(struct inode *inode, int mask)
                case S_IFLNK:
                        goto out;
                case S_IFREG:
+                       if ((mask & MAY_OPEN) &&
+                          nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN))
+                               return 0;
                        break;
                case S_IFDIR:
                        /*
@@ -2481,8 +2497,8 @@ force_lookup:
                        res = PTR_ERR(cred);
        }
 out:
-       if (!res && (mask & MAY_EXEC) && !execute_ok(inode))
-               res = -EACCES;
+       if (!res && (mask & MAY_EXEC))
+               res = nfs_execute_ok(inode, mask);
 
        dfprintk(VFS, "NFS: permission(%s/%lu), mask=0x%x, res=%d\n",
                inode->i_sb->s_id, inode->i_ino, mask, res);