[git patch] vfs: permission API cleanup (v2)

From: Miklos Szeredi
Date: Thu May 22 2008 - 12:50:54 EST


I've committed this series to the vfs-cleanups tree at:

git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git vfs-cleanups

Changes since yesterday's posting:

- removed flags passed to ->permission() and path_permission()
- renamed exec_permission() to check_execute()

Thanks to Al and Trond for the suggestions.

Miklos
---

Miklos Szeredi (12):
hppfs: remove hppfs_permission
gfs2: don't call permission()
hpfs: don't call permission()
hfsplus: remove hfsplus_permission()
vfs: pass dentry to permission()
vfs: don't use nameidata flags in ->permission()
vfs: cleanup i_op->permission()
security: don't pass nameidata to security_inode_permission()
vfs: don't pass nameidata to dentry_permission()
vfs: move executable checking into ->permission()
vfs: create path_permission()
vfs: don't use dentry_permission()

Documentation/filesystems/Locking | 2 +-
Documentation/filesystems/vfs.txt | 2 +-
fs/afs/internal.h | 4 +-
fs/afs/security.c | 3 +-
fs/bad_inode.c | 3 +-
fs/cifs/cifsfs.c | 5 +-
fs/coda/dir.c | 10 ++-
fs/coda/pioctl.c | 8 +-
fs/ecryptfs/inode.c | 20 +---
fs/exec.c | 4 +-
fs/ext2/acl.c | 4 +-
fs/ext2/acl.h | 2 +-
fs/ext3/acl.c | 4 +-
fs/ext3/acl.h | 2 +-
fs/ext4/acl.c | 4 +-
fs/ext4/acl.h | 2 +-
fs/fuse/dir.c | 8 +-
fs/gfs2/inode.c | 6 +-
fs/gfs2/inode.h | 1 +
fs/gfs2/ops_file.c | 11 ++-
fs/gfs2/ops_inode.c | 18 +++-
fs/hfs/inode.c | 7 +-
fs/hfsplus/inode.c | 13 ---
fs/hostfs/hostfs_kern.c | 3 +-
fs/hpfs/namei.c | 2 +-
fs/hppfs/hppfs.c | 7 --
fs/inotify_user.c | 2 +-
fs/jffs2/acl.c | 4 +-
fs/jffs2/acl.h | 2 +-
fs/jfs/acl.c | 4 +-
fs/jfs/jfs_acl.h | 2 +-
fs/namei.c | 203 ++++++++++++++++++++-----------------
fs/nfs/dir.c | 17 ++--
fs/nfsd/nfsfh.c | 11 +-
fs/nfsd/vfs.c | 8 +-
fs/ocfs2/file.c | 3 +-
fs/ocfs2/file.h | 3 +-
fs/open.c | 15 ++--
fs/proc/base.c | 4 +-
fs/proc/proc_sysctl.c | 11 ++-
fs/reiserfs/xattr.c | 4 +-
fs/smbfs/file.c | 11 +-
fs/utimes.c | 2 +-
fs/xattr.c | 22 +++--
fs/xfs/linux-2.6/xfs_iops.c | 7 +-
include/linux/coda_linux.h | 2 +-
include/linux/fs.h | 16 +++-
include/linux/namei.h | 2 -
include/linux/nfs_fs.h | 2 +-
include/linux/reiserfs_xattr.h | 2 +-
include/linux/security.h | 8 +-
include/linux/shmem_fs.h | 2 +-
ipc/mqueue.c | 15 ++-
mm/shmem_acl.c | 4 +-
net/unix/af_unix.c | 2 +-
security/dummy.c | 2 +-
security/security.c | 4 +-
security/selinux/hooks.c | 6 +-
security/smack/smack_lsm.c | 4 +-
59 files changed, 296 insertions(+), 265 deletions(-)
---

diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 8b22d7d..9801e87 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -44,7 +44,7 @@ ata *);
int (*readlink) (struct dentry *, char __user *,int);
int (*follow_link) (struct dentry *, struct nameidata *);
void (*truncate) (struct inode *);
- int (*permission) (struct inode *, int, struct nameidata *);
+ int (*permission) (struct dentry *, int);
int (*setattr) (struct dentry *, struct iattr *);
int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *);
int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index b7522c6..a597097 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -326,7 +326,7 @@ struct inode_operations {
void * (*follow_link) (struct dentry *, struct nameidata *);
void (*put_link) (struct dentry *, struct nameidata *, void *);
void (*truncate) (struct inode *);
- int (*permission) (struct inode *, int, struct nameidata *);
+ int (*permission) (struct dentry *, int);
int (*setattr) (struct dentry *, struct iattr *);
int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 7102824..6aa93b1 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -469,8 +469,6 @@ extern bool afs_cm_incoming_call(struct afs_call *);
extern const struct inode_operations afs_dir_inode_operations;
extern const struct file_operations afs_dir_file_operations;

-extern int afs_permission(struct inode *, int, struct nameidata *);
-
/*
* file.c
*/
@@ -605,7 +603,7 @@ extern void afs_clear_permits(struct afs_vnode *);
extern void afs_cache_permit(struct afs_vnode *, struct key *, long);
extern void afs_zap_permits(struct rcu_head *);
extern struct key *afs_request_key(struct afs_cell *);
-extern int afs_permission(struct inode *, int, struct nameidata *);
+extern int afs_permission(struct dentry *, int);

/*
* server.c
diff --git a/fs/afs/security.c b/fs/afs/security.c
index 3bcbece..dd53831 100644
--- a/fs/afs/security.c
+++ b/fs/afs/security.c
@@ -284,8 +284,9 @@ static int afs_check_permit(struct afs_vnode *vnode, struct key *key,
* - AFS ACLs are attached to directories only, and a file is controlled by its
* parent directory's ACL
*/
-int afs_permission(struct inode *inode, int mask, struct nameidata *nd)
+int afs_permission(struct dentry *dentry, int mask)
{
+ struct inode *inode = dentry->d_inode;
struct afs_vnode *vnode = AFS_FS_I(inode);
afs_access_t uninitialized_var(access);
struct key *key;
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index f1c2ea8..d1320bd 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -243,8 +243,7 @@ static int bad_inode_readlink(struct dentry *dentry, char __user *buffer,
return -EIO;
}

-static int bad_inode_permission(struct inode *inode, int mask,
- struct nameidata *nd)
+static int bad_inode_permission(struct dentry *dentry, int mask)
{
return -EIO;
}
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 427a7c6..bd16cc8 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -268,14 +268,15 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0;
}

-static int cifs_permission(struct inode *inode, int mask, struct nameidata *nd)
+static int cifs_permission(struct dentry *dentry, int mask)
{
+ struct inode *inode = dentry->d_inode;
struct cifs_sb_info *cifs_sb;

cifs_sb = CIFS_SB(inode->i_sb);

if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
- return 0;
+ return check_execute(inode, mask);
else /* file mode might have been restricted at mount time
on the client (above and beyond ACL on servers) for
servers which do not support setting and viewing mode bits,
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 3d2580e..51d1500 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -137,13 +137,19 @@ exit:
}


-int coda_permission(struct inode *inode, int mask, struct nameidata *nd)
+int coda_permission(struct dentry *dentry, int mask)
{
- int error = 0;
+ struct inode *inode = dentry->d_inode;
+ int error = 0;

+ mask &= PERMISSION_MASK;
if (!mask)
return 0;

+ error = check_execute(inode, mask);
+ if (error)
+ return error;
+
lock_kernel();

if (coda_cache_check(inode, mask))
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c
index c21a1f5..afb7836 100644
--- a/fs/coda/pioctl.c
+++ b/fs/coda/pioctl.c
@@ -24,8 +24,7 @@
#include <linux/coda_psdev.h>

/* pioctl ops */
-static int coda_ioctl_permission(struct inode *inode, int mask,
- struct nameidata *nd);
+static int coda_ioctl_permission(struct dentry *dentry, int mask);
static int coda_pioctl(struct inode * inode, struct file * filp,
unsigned int cmd, unsigned long user_data);

@@ -42,10 +41,9 @@ const struct file_operations coda_ioctl_operations = {
};

/* the coda pioctl inode ops */
-static int coda_ioctl_permission(struct inode *inode, int mask,
- struct nameidata *nd)
+static int coda_ioctl_permission(struct dentry *dentry, int mask)
{
- return 0;
+ return check_execute(dentry->d_inode, mask);
}

static int coda_pioctl(struct inode * inode, struct file * filp,
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 5b0c334..f4074f7 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -808,22 +808,14 @@ out:
}

static int
-ecryptfs_permission(struct inode *inode, int mask, struct nameidata *nd)
+ecryptfs_permission(struct dentry *dentry, int mask)
{
- int rc;
+ struct path lower_path;
+
+ lower_path.mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+ lower_path.dentry = ecryptfs_dentry_to_lower(dentry);

- if (nd) {
- struct vfsmount *vfsmnt_save = nd->path.mnt;
- struct dentry *dentry_save = nd->path.dentry;
-
- nd->path.mnt = ecryptfs_dentry_to_lower_mnt(nd->path.dentry);
- nd->path.dentry = ecryptfs_dentry_to_lower(nd->path.dentry);
- rc = permission(ecryptfs_inode_to_lower(inode), mask, nd);
- nd->path.mnt = vfsmnt_save;
- nd->path.dentry = dentry_save;
- } else
- rc = permission(ecryptfs_inode_to_lower(inode), mask, NULL);
- return rc;
+ return path_permission(&lower_path, mask);
}

/**
diff --git a/fs/exec.c b/fs/exec.c
index b68682a..5924a42 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -116,7 +116,7 @@ asmlinkage long sys_uselib(const char __user * library)
if (!S_ISREG(nd.path.dentry->d_inode->i_mode))
goto exit;

- error = vfs_permission(&nd, MAY_READ | MAY_EXEC);
+ error = path_permission(&nd.path, MAY_READ | MAY_EXEC);
if (error)
goto exit;

@@ -664,7 +664,7 @@ struct file *open_exec(const char *name)
struct inode *inode = nd.path.dentry->d_inode;
file = ERR_PTR(-EACCES);
if (S_ISREG(inode->i_mode)) {
- int err = vfs_permission(&nd, MAY_EXEC);
+ int err = path_permission(&nd.path, MAY_EXEC);
file = ERR_PTR(err);
if (!err) {
file = nameidata_to_filp(&nd,
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
index e58669e..124668a 100644
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -294,9 +294,9 @@ ext2_check_acl(struct inode *inode, int mask)
}

int
-ext2_permission(struct inode *inode, int mask, struct nameidata *nd)
+ext2_permission(struct dentry *dentry, int mask)
{
- return generic_permission(inode, mask, ext2_check_acl);
+ return generic_permission(dentry->d_inode, mask, ext2_check_acl);
}

/*
diff --git a/fs/ext2/acl.h b/fs/ext2/acl.h
index 0bde85b..a8ebf60 100644
--- a/fs/ext2/acl.h
+++ b/fs/ext2/acl.h
@@ -58,7 +58,7 @@ static inline int ext2_acl_count(size_t size)
#define EXT2_ACL_NOT_CACHED ((void *)-1)

/* acl.c */
-extern int ext2_permission (struct inode *, int, struct nameidata *);
+extern int ext2_permission(struct dentry *, int);
extern int ext2_acl_chmod (struct inode *);
extern int ext2_init_acl (struct inode *, struct inode *);

diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c
index a754d18..f8d1bea 100644
--- a/fs/ext3/acl.c
+++ b/fs/ext3/acl.c
@@ -299,9 +299,9 @@ ext3_check_acl(struct inode *inode, int mask)
}

int
-ext3_permission(struct inode *inode, int mask, struct nameidata *nd)
+ext3_permission(struct dentry *dentry, int mask)
{
- return generic_permission(inode, mask, ext3_check_acl);
+ return generic_permission(dentry->d_inode, mask, ext3_check_acl);
}

/*
diff --git a/fs/ext3/acl.h b/fs/ext3/acl.h
index 0d1e627..d6cc255 100644
--- a/fs/ext3/acl.h
+++ b/fs/ext3/acl.h
@@ -58,7 +58,7 @@ static inline int ext3_acl_count(size_t size)
#define EXT3_ACL_NOT_CACHED ((void *)-1)

/* acl.c */
-extern int ext3_permission (struct inode *, int, struct nameidata *);
+extern int ext3_permission(struct dentry *, int);
extern int ext3_acl_chmod (struct inode *);
extern int ext3_init_acl (handle_t *, struct inode *, struct inode *);

diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
index 3c8dab8..097a518 100644
--- a/fs/ext4/acl.c
+++ b/fs/ext4/acl.c
@@ -299,9 +299,9 @@ ext4_check_acl(struct inode *inode, int mask)
}

int
-ext4_permission(struct inode *inode, int mask, struct nameidata *nd)
+ext4_permission(struct dentry *dentry, int mask)
{
- return generic_permission(inode, mask, ext4_check_acl);
+ return generic_permission(dentry->d_inode, mask, ext4_check_acl);
}

/*
diff --git a/fs/ext4/acl.h b/fs/ext4/acl.h
index 26a5c1a..f5289af 100644
--- a/fs/ext4/acl.h
+++ b/fs/ext4/acl.h
@@ -58,7 +58,7 @@ static inline int ext4_acl_count(size_t size)
#define EXT4_ACL_NOT_CACHED ((void *)-1)

/* acl.c */
-extern int ext4_permission (struct inode *, int, struct nameidata *);
+extern int ext4_permission(struct dentry *, int);
extern int ext4_acl_chmod (struct inode *);
extern int ext4_init_acl (handle_t *, struct inode *, struct inode *);

diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 2060bf0..5cf0740 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -886,8 +886,9 @@ static int fuse_access(struct inode *inode, int mask)
* access request is sent. Execute permission is still checked
* locally based on file mode.
*/
-static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
+static int fuse_permission(struct dentry *dentry, int mask)
{
+ struct inode *inode = dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
bool refreshed = false;
int err = 0;
@@ -921,8 +922,9 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
exist. So if permissions are revoked this won't be
noticed immediately, only after the attribute
timeout has expired */
- } else if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR))) {
- err = fuse_access(inode, mask);
+ } else if ((mask & PERM_OP_MASK) == PERM_OP_ACCESS ||
+ (mask & PERM_OP_MASK) == PERM_OP_CHDIR) {
+ err = fuse_access(inode, mask & PERMISSION_MASK);
} else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
if (!(inode->i_mode & S_IXUGO)) {
if (refreshed)
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 3a9ef52..3666c32 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -504,7 +504,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
}

if (!is_root) {
- error = permission(dir, MAY_EXEC, NULL);
+ error = gfs2_do_permission(dir, MAY_EXEC);
if (error)
goto out;
}
@@ -667,7 +667,7 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name,
{
int error;

- error = permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL);
+ error = gfs2_do_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC);
if (error)
return error;

@@ -1134,7 +1134,7 @@ int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
if (IS_APPEND(&dip->i_inode))
return -EPERM;

- error = permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL);
+ error = gfs2_do_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC);
if (error)
return error;

diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
index 580da45..49c1a3e 100644
--- a/fs/gfs2/inode.h
+++ b/fs/gfs2/inode.h
@@ -91,6 +91,7 @@ int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
struct gfs2_inode *ip);
int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
const struct gfs2_inode *ip);
+int gfs2_do_permission(struct inode *inode, int mask);
int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to);
int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len);
int gfs2_glock_nq_atime(struct gfs2_holder *gh);
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
index e1b7d52..68a3dd7 100644
--- a/fs/gfs2/ops_file.c
+++ b/fs/gfs2/ops_file.c
@@ -15,6 +15,7 @@
#include <linux/uio.h>
#include <linux/blkdev.h>
#include <linux/mm.h>
+#include <linux/mount.h>
#include <linux/fs.h>
#include <linux/gfs2_ondisk.h>
#include <linux/ext2_fs.h>
@@ -220,10 +221,14 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
int error;
u32 new_flags, flags;

- error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
+ error = mnt_want_write(filp->f_path.mnt);
if (error)
return error;

+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
+ if (error)
+ goto out_drop_write;
+
flags = ip->i_di.di_flags;
new_flags = (flags & ~mask) | (reqflags & mask);
if ((new_flags ^ flags) == 0)
@@ -242,7 +247,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
!capable(CAP_LINUX_IMMUTABLE))
goto out;
if (!IS_IMMUTABLE(inode)) {
- error = permission(inode, MAY_WRITE, NULL);
+ error = gfs2_do_permission(inode, MAY_WRITE);
if (error)
goto out;
}
@@ -272,6 +277,8 @@ out_trans_end:
gfs2_trans_end(sdp);
out:
gfs2_glock_dq_uninit(&gh);
+out_drop_write:
+ mnt_drop_write(filp->f_path.mnt);
return error;
}

diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
index 2686ad4..a9d6a63 100644
--- a/fs/gfs2/ops_inode.c
+++ b/fs/gfs2/ops_inode.c
@@ -163,7 +163,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
if (error)
goto out;

- error = permission(dir, MAY_WRITE | MAY_EXEC, NULL);
+ error = gfs2_do_permission(dir, MAY_WRITE | MAY_EXEC);
if (error)
goto out_gunlock;

@@ -669,7 +669,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
}
}
} else {
- error = permission(ndir, MAY_WRITE | MAY_EXEC, NULL);
+ error = gfs2_do_permission(ndir, MAY_WRITE | MAY_EXEC);
if (error)
goto out_gunlock;

@@ -704,7 +704,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
/* Check out the dir to be renamed */

if (dir_rename) {
- error = permission(odentry->d_inode, MAY_WRITE, NULL);
+ error = gfs2_do_permission(odentry->d_inode, MAY_WRITE);
if (error)
goto out_gunlock;
}
@@ -891,7 +891,7 @@ static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
* Returns: errno
*/

-static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
+int gfs2_do_permission(struct inode *inode, int mask)
{
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder i_gh;
@@ -905,13 +905,21 @@ static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
unlock = 1;
}

- error = generic_permission(inode, mask, gfs2_check_acl);
+ if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode))
+ error = -EACCES;
+ else
+ error = generic_permission(inode, mask, gfs2_check_acl);
if (unlock)
gfs2_glock_dq_uninit(&i_gh);

return error;
}

+static int gfs2_permission(struct dentry *dentry, int mask)
+{
+ return gfs2_do_permission(dentry->d_inode, mask);
+}
+
static int setattr_size(struct inode *inode, struct iattr *attr)
{
struct gfs2_inode *ip = GFS2_I(inode);
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 97f8446..c87eeee 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -511,11 +511,12 @@ void hfs_clear_inode(struct inode *inode)
}
}

-static int hfs_permission(struct inode *inode, int mask,
- struct nameidata *nd)
+static int hfs_permission(struct dentry *dentry, int mask)
{
+ struct inode *inode = dentry->d_inode;
+
if (S_ISREG(inode->i_mode) && mask & MAY_EXEC)
- return 0;
+ return check_execute(inode, mask);
return generic_permission(inode, mask, NULL);
}

diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 67e1c8b..369624c 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -238,18 +238,6 @@ static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms)
perms->dev = cpu_to_be32(HFSPLUS_I(inode).dev);
}

-static int hfsplus_permission(struct inode *inode, int mask, struct nameidata *nd)
-{
- /* MAY_EXEC is also used for lookup, if no x bit is set allow lookup,
- * open_exec has the same test, so it's still not executable, if a x bit
- * is set fall back to standard permission check.
- */
- if (S_ISREG(inode->i_mode) && mask & MAY_EXEC && !(inode->i_mode & 0111))
- return 0;
- return generic_permission(inode, mask, NULL);
-}
-
-
static int hfsplus_file_open(struct inode *inode, struct file *file)
{
if (HFSPLUS_IS_RSRC(inode))
@@ -283,7 +271,6 @@ static int hfsplus_file_release(struct inode *inode, struct file *file)
static const struct inode_operations hfsplus_file_inode_operations = {
.lookup = hfsplus_file_lookup,
.truncate = hfsplus_file_truncate,
- .permission = hfsplus_permission,
.setxattr = hfsplus_setxattr,
.getxattr = hfsplus_getxattr,
.listxattr = hfsplus_listxattr,
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 5222345..1bf36c1 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -822,8 +822,9 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from,
return err;
}

-int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd)
+int hostfs_permission(struct dentry *dentry, int desired)
{
+ struct inode *ino = dentry->d_inode;
char *name;
int r = 0, w = 0, x = 0, err;

diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index d5ed786..e1fadd3 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -415,7 +415,7 @@ again:
d_drop(dentry);
spin_lock(&dentry->d_lock);
if (atomic_read(&dentry->d_count) > 1 ||
- permission(inode, MAY_WRITE, NULL) ||
+ generic_permission(inode, MAY_WRITE, NULL) ||
!S_ISREG(inode->i_mode) ||
get_write_access(inode)) {
spin_unlock(&dentry->d_lock);
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c
index 65077aa..2b3d182 100644
--- a/fs/hppfs/hppfs.c
+++ b/fs/hppfs/hppfs.c
@@ -655,20 +655,13 @@ static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd)
return proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd);
}

-int hppfs_permission(struct inode *inode, int mask, struct nameidata *nd)
-{
- return generic_permission(inode, mask, NULL);
-}
-
static const struct inode_operations hppfs_dir_iops = {
.lookup = hppfs_lookup,
- .permission = hppfs_permission,
};

static const struct inode_operations hppfs_link_iops = {
.readlink = hppfs_readlink,
.follow_link = hppfs_follow_link,
- .permission = hppfs_permission,
};

static struct inode *get_inode(struct super_block *sb, struct dentry *dentry)
diff --git a/fs/inotify_user.c b/fs/inotify_user.c
index 6676c06..254c7fb 100644
--- a/fs/inotify_user.c
+++ b/fs/inotify_user.c
@@ -365,7 +365,7 @@ static int find_inode(const char __user *dirname, struct nameidata *nd,
if (error)
return error;
/* you can only watch an inode if you have read permissions on it */
- error = vfs_permission(nd, MAY_READ);
+ error = path_permission(&nd->path, MAY_READ);
if (error)
path_put(&nd->path);
return error;
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
index 4c80404..f1ecb8c 100644
--- a/fs/jffs2/acl.c
+++ b/fs/jffs2/acl.c
@@ -314,9 +314,9 @@ static int jffs2_check_acl(struct inode *inode, int mask)
return -EAGAIN;
}

-int jffs2_permission(struct inode *inode, int mask, struct nameidata *nd)
+int jffs2_permission(struct dentry *dentry, int mask)
{
- return generic_permission(inode, mask, jffs2_check_acl);
+ return generic_permission(dentry->d_inode, mask, jffs2_check_acl);
}

int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode)
diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h
index 0bb7f00..b5da329 100644
--- a/fs/jffs2/acl.h
+++ b/fs/jffs2/acl.h
@@ -28,7 +28,7 @@ struct jffs2_acl_header {

#define JFFS2_ACL_NOT_CACHED ((void *)-1)

-extern int jffs2_permission(struct inode *, int, struct nameidata *);
+extern int jffs2_permission(struct dentry *, int);
extern int jffs2_acl_chmod(struct inode *);
extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *);
extern int jffs2_init_acl_post(struct inode *);
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c
index 4d84bdc..0b4c3a1 100644
--- a/fs/jfs/acl.c
+++ b/fs/jfs/acl.c
@@ -140,9 +140,9 @@ static int jfs_check_acl(struct inode *inode, int mask)
return -EAGAIN;
}

-int jfs_permission(struct inode *inode, int mask, struct nameidata *nd)
+int jfs_permission(struct dentry *dentry, int mask)
{
- return generic_permission(inode, mask, jfs_check_acl);
+ return generic_permission(dentry->d_inode, mask, jfs_check_acl);
}

int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir)
diff --git a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h
index 455fa42..69f4af5 100644
--- a/fs/jfs/jfs_acl.h
+++ b/fs/jfs/jfs_acl.h
@@ -20,7 +20,7 @@

#ifdef CONFIG_JFS_POSIX_ACL

-int jfs_permission(struct inode *, int, struct nameidata *);
+int jfs_permission(struct dentry *, int);
int jfs_init_acl(tid_t, struct inode *, struct inode *);
int jfs_setattr(struct dentry *, struct iattr *);

diff --git a/fs/namei.c b/fs/namei.c
index 1114bc0..83d0f37 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -185,6 +185,7 @@ int generic_permission(struct inode *inode, int mask,
{
umode_t mode = inode->i_mode;

+ mask &= PERMISSION_MASK;
if (current->fsuid == inode->i_uid)
mode >>= 6;
else {
@@ -226,13 +227,30 @@ int generic_permission(struct inode *inode, int mask,
return -EACCES;
}

-int permission(struct inode *inode, int mask, struct nameidata *nd)
+/**
+ * check_execute - check for general execute permission on file
+ * @inode: inode to check access rights for
+ * @mask: right to check for
+ *
+ * Exec permission on a regular file is denied if none of the execute
+ * bits are set.
+ *
+ * This needs to be called by filesystems which define a
+ * ->permission() method, and don't call generic_permission().
+ */
+int check_execute(struct inode *inode, int mask)
{
- int retval, submask;
- struct vfsmount *mnt = NULL;
+ if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode) &&
+ !(inode->i_mode & S_IXUGO))
+ return -EACCES;

- if (nd)
- mnt = nd->path.mnt;
+ return 0;
+}
+
+static int dentry_permission(struct dentry *dentry, int mask)
+{
+ struct inode *inode = dentry->d_inode;
+ int retval, submask;

if (mask & MAY_WRITE) {
umode_t mode = inode->i_mode;
@@ -251,34 +269,13 @@ int permission(struct inode *inode, int mask, struct nameidata *nd)
return -EACCES;
}

- if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
- /*
- * MAY_EXEC on regular files is denied if the fs is mounted
- * with the "noexec" flag.
- */
- if (mnt && (mnt->mnt_flags & MNT_NOEXEC))
- return -EACCES;
- }
-
/* Ordinary permission routines do not understand MAY_APPEND. */
submask = mask & ~MAY_APPEND;
- if (inode->i_op && inode->i_op->permission) {
- retval = inode->i_op->permission(inode, submask, nd);
- if (!retval) {
- /*
- * Exec permission on a regular file is denied if none
- * of the execute bits are set.
- *
- * This check should be done by the ->permission()
- * method.
- */
- if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode) &&
- !(inode->i_mode & S_IXUGO))
- return -EACCES;
- }
- } else {
+ if (inode->i_op && inode->i_op->permission)
+ retval = inode->i_op->permission(dentry, submask);
+ else
retval = generic_permission(inode, submask, NULL);
- }
+
if (retval)
return retval;

@@ -286,12 +283,12 @@ int permission(struct inode *inode, int mask, struct nameidata *nd)
if (retval)
return retval;

- return security_inode_permission(inode, mask, nd);
+ return security_inode_permission(inode, mask);
}

/**
- * vfs_permission - check for access rights to a given path
- * @nd: lookup result that describes the path
+ * path_permission - check for access rights to a given path
+ * @path: lookup result that describes the path
* @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
*
* Used to check for read/write/execute permissions on a path.
@@ -299,9 +296,23 @@ int permission(struct inode *inode, int mask, struct nameidata *nd)
* for filesystem access without changing the "normal" uids which
* are used for other things.
*/
-int vfs_permission(struct nameidata *nd, int mask)
+int path_permission(struct path *path, int mask)
{
- return permission(nd->path.dentry->d_inode, mask, nd);
+ struct dentry *dentry = path->dentry;
+ struct inode *inode = dentry->d_inode;
+
+ if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
+ struct vfsmount *mnt = path->mnt;
+
+ /*
+ * MAY_EXEC on regular files is denied if the fs is mounted
+ * with the "noexec" flag.
+ */
+ if (mnt->mnt_flags & MNT_NOEXEC)
+ return -EACCES;
+ }
+
+ return dentry_permission(dentry, mask);
}

/**
@@ -309,16 +320,11 @@ int vfs_permission(struct nameidata *nd, int mask)
* @file: file to check access rights for
* @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
*
- * Used to check for read/write/execute permissions on an already opened
- * file.
- *
- * Note:
- * Do not use this function in new code. All access checks should
- * be done using vfs_permission().
+ * This is a helper for path_permission().
*/
int file_permission(struct file *file, int mask)
{
- return permission(file->f_path.dentry->d_inode, mask, NULL);
+ return path_permission(&file->f_path, mask);
}

/*
@@ -459,8 +465,7 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name,
* short-cut DAC fails, then call permission() to do more
* complete permission check.
*/
-static int exec_permission_lite(struct inode *inode,
- struct nameidata *nd)
+static int exec_permission_lite(struct inode *inode)
{
umode_t mode = inode->i_mode;

@@ -486,7 +491,7 @@ static int exec_permission_lite(struct inode *inode,

return -EACCES;
ok:
- return security_inode_permission(inode, MAY_EXEC, nd);
+ return security_inode_permission(inode, MAY_EXEC);
}

/*
@@ -891,9 +896,9 @@ static int __link_path_walk(const char *name, struct nameidata *nd)
unsigned int c;

nd->flags |= LOOKUP_CONTINUE;
- err = exec_permission_lite(inode, nd);
+ err = exec_permission_lite(inode);
if (err == -EAGAIN)
- err = vfs_permission(nd, MAY_EXEC);
+ err = path_permission(&nd->path, MAY_EXEC);
if (err)
break;

@@ -1341,7 +1346,7 @@ static struct dentry *lookup_hash(struct nameidata *nd)
{
int err;

- err = permission(nd->path.dentry->d_inode, MAY_EXEC, nd);
+ err = path_permission(&nd->path, MAY_EXEC);
if (err)
return ERR_PTR(err);
return __lookup_hash(&nd->last, nd->path.dentry, nd);
@@ -1389,7 +1394,7 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
if (err)
return ERR_PTR(err);

- err = permission(base->d_inode, MAY_EXEC, NULL);
+ err = dentry_permission(base, MAY_EXEC);
if (err)
return ERR_PTR(err);
return __lookup_hash(&this, base, NULL);
@@ -1469,8 +1474,10 @@ static inline int check_sticky(struct inode *dir, struct inode *inode)
* 10. We don't allow removal of NFS sillyrenamed files; it's handled by
* nfs_async_unlink().
*/
-static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
+static int may_delete(struct dentry *dir_dentry, struct dentry *victim,
+ int isdir)
{
+ struct inode *dir = dir_dentry->d_inode;
int error;

if (!victim->d_inode)
@@ -1479,7 +1486,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
BUG_ON(victim->d_parent->d_inode != dir);
audit_inode_child(victim->d_name.name, victim, dir);

- error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
+ error = dentry_permission(dir_dentry, MAY_WRITE | MAY_EXEC);
if (error)
return error;
if (IS_APPEND(dir))
@@ -1509,14 +1516,13 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
* 3. We should have write and exec permissions on dir
* 4. We can't do it if dir is immutable (done in permission())
*/
-static inline int may_create(struct inode *dir, struct dentry *child,
- struct nameidata *nd)
+static inline int may_create(struct dentry *dir_dentry, struct dentry *child)
{
if (child->d_inode)
return -EEXIST;
- if (IS_DEADDIR(dir))
+ if (IS_DEADDIR(dir_dentry->d_inode))
return -ENOENT;
- return permission(dir,MAY_WRITE | MAY_EXEC, nd);
+ return dentry_permission(dir_dentry, MAY_WRITE | MAY_EXEC);
}

/*
@@ -1579,10 +1585,11 @@ void unlock_rename(struct dentry *p1, struct dentry *p2)
}
}

-static int vfs_create(struct inode *dir, struct dentry *dentry, int mode,
- struct nameidata *nd)
+static int vfs_create(struct dentry *dir_dentry, struct dentry *dentry,
+ int mode, struct nameidata *nd)
{
- int error = may_create(dir, dentry, nd);
+ struct inode *dir = dir_dentry->d_inode;
+ int error = may_create(dir_dentry, dentry);

if (error)
return error;
@@ -1607,7 +1614,7 @@ int path_create(struct path *dir_path, struct dentry *dentry, int mode,
int error = mnt_want_write(dir_path->mnt);

if (!error) {
- error = vfs_create(dir_path->dentry->d_inode, dentry, mode, nd);
+ error = vfs_create(dir_path->dentry, dentry, mode, nd);
mnt_drop_write(dir_path->mnt);
}

@@ -1617,6 +1624,7 @@ EXPORT_SYMBOL(path_create);

int may_open(struct nameidata *nd, int acc_mode, int flag)
{
+ int op;
struct dentry *dentry = nd->path.dentry;
struct inode *inode = dentry->d_inode;
int error;
@@ -1644,7 +1652,8 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
flag &= ~O_TRUNC;
}

- error = vfs_permission(nd, acc_mode);
+ op = (nd->flags & LOOKUP_OPEN) ? PERM_OP_OPEN : 0;
+ error = path_permission(&nd->path, acc_mode | op);
if (error)
return error;
/*
@@ -1708,7 +1717,7 @@ static int __open_namei_create(struct nameidata *nd, struct path *path,

if (!IS_POSIXACL(dir->d_inode))
mode &= ~current->fs->umask;
- error = vfs_create(dir->d_inode, path->dentry, mode, nd);
+ error = vfs_create(dir, path->dentry, mode, nd);
mutex_unlock(&dir->d_inode->i_mutex);
dput(nd->path.dentry);
nd->path.dentry = path->dentry;
@@ -2034,9 +2043,11 @@ fail:
}
EXPORT_SYMBOL_GPL(lookup_create);

-static int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+static int vfs_mknod(struct dentry *dir_dentry, struct dentry *dentry,
+ int mode, dev_t dev)
{
- int error = may_create(dir, dentry, NULL);
+ struct inode *dir = dir_dentry->d_inode;
+ int error = may_create(dir_dentry, dentry);

if (error)
return error;
@@ -2068,7 +2079,7 @@ int path_mknod(struct path *dir_path, struct dentry *dentry, int mode,
int error = mnt_want_write(dir_path->mnt);

if (!error) {
- error = vfs_mknod(dir_path->dentry->d_inode, dentry, mode, dev);
+ error = vfs_mknod(dir_path->dentry, dentry, mode, dev);
mnt_drop_write(dir_path->mnt);
}

@@ -2131,9 +2142,10 @@ asmlinkage long sys_mknod(const char __user *filename, int mode, unsigned dev)
return sys_mknodat(AT_FDCWD, filename, mode, dev);
}

-static int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+static int vfs_mkdir(struct dentry *dir_dentry, struct dentry *dentry, int mode)
{
- int error = may_create(dir, dentry, NULL);
+ struct inode *dir = dir_dentry->d_inode;
+ int error = may_create(dir_dentry, dentry);

if (error)
return error;
@@ -2158,7 +2170,7 @@ int path_mkdir(struct path *dir_path, struct dentry *dentry, int mode)
int error = mnt_want_write(dir_path->mnt);

if (!error) {
- error = vfs_mkdir(dir_path->dentry->d_inode, dentry, mode);
+ error = vfs_mkdir(dir_path->dentry, dentry, mode);
mnt_drop_write(dir_path->mnt);
}

@@ -2231,9 +2243,10 @@ void dentry_unhash(struct dentry *dentry)
spin_unlock(&dcache_lock);
}

-static int vfs_rmdir(struct inode *dir, struct dentry *dentry)
+static int vfs_rmdir(struct dentry *dir_dentry, struct dentry *dentry)
{
- int error = may_delete(dir, dentry, 1);
+ struct inode *dir = dir_dentry->d_inode;
+ int error = may_delete(dir_dentry, dentry, 1);

if (error)
return error;
@@ -2269,7 +2282,7 @@ int path_rmdir(struct path *dir_path, struct dentry *dentry)
int error = mnt_want_write(dir_path->mnt);

if (!error) {
- error = vfs_rmdir(dir_path->dentry->d_inode, dentry);
+ error = vfs_rmdir(dir_path->dentry, dentry);
mnt_drop_write(dir_path->mnt);
}

@@ -2324,9 +2337,10 @@ asmlinkage long sys_rmdir(const char __user *pathname)
return do_rmdir(AT_FDCWD, pathname);
}

-static int vfs_unlink(struct inode *dir, struct dentry *dentry)
+static int vfs_unlink(struct dentry *dir_dentry, struct dentry *dentry)
{
- int error = may_delete(dir, dentry, 0);
+ struct inode *dir = dir_dentry->d_inode;
+ int error = may_delete(dir_dentry, dentry, 0);

if (error)
return error;
@@ -2360,7 +2374,7 @@ int path_unlink(struct path *dir_path, struct dentry *dentry)
int error = mnt_want_write(dir_path->mnt);

if (!error) {
- error = vfs_unlink(dir_path->dentry->d_inode, dentry);
+ error = vfs_unlink(dir_path->dentry, dentry);
mnt_drop_write(dir_path->mnt);
}

@@ -2437,9 +2451,11 @@ asmlinkage long sys_unlink(const char __user *pathname)
return do_unlinkat(AT_FDCWD, pathname);
}

-static int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
+static int vfs_symlink(struct dentry *dir_dentry, struct dentry *dentry,
+ const char *oldname)
{
- int error = may_create(dir, dentry, NULL);
+ struct inode *dir = dir_dentry->d_inode;
+ int error = may_create(dir_dentry, dentry);

if (error)
return error;
@@ -2464,9 +2480,7 @@ int path_symlink(struct path *dir_path, struct dentry *dentry,
int error = mnt_want_write(dir_path->mnt);

if (!error) {
- struct inode *dir = dir_path->dentry->d_inode;
-
- error = vfs_symlink(dir, dentry, oldname);
+ error = vfs_symlink(dir_path->dentry, dentry, oldname);
mnt_drop_write(dir_path->mnt);
}

@@ -2516,15 +2530,17 @@ asmlinkage long sys_symlink(const char __user *oldname, const char __user *newna
return sys_symlinkat(oldname, AT_FDCWD, newname);
}

-static int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
+static int vfs_link(struct dentry *old_dentry, struct dentry *new_dir_dentry,
+ struct dentry *new_dentry)
{
+ struct inode *dir = new_dir_dentry->d_inode;
struct inode *inode = old_dentry->d_inode;
int error;

if (!inode)
return -ENOENT;

- error = may_create(dir, new_dentry, NULL);
+ error = may_create(new_dir_dentry, new_dentry);
if (error)
return error;

@@ -2560,9 +2576,7 @@ int path_link(struct dentry *old_dentry, struct path *dir_path,
int error = mnt_want_write(dir_path->mnt);

if (!error) {
- struct inode *dir = dir_path->dentry->d_inode;
-
- error = vfs_link(old_dentry, dir, new_dentry);
+ error = vfs_link(old_dentry, dir_path->dentry, new_dentry);
mnt_drop_write(dir_path->mnt);
}

@@ -2672,7 +2686,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
* we'll need to flip '..'.
*/
if (new_dir != old_dir) {
- error = permission(old_dentry->d_inode, MAY_WRITE, NULL);
+ error = dentry_permission(old_dentry, MAY_WRITE);
if (error)
return error;
}
@@ -2732,9 +2746,11 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
return error;
}

-static int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+static int vfs_rename(struct dentry *old_dir_dentry, struct dentry *old_dentry,
+ struct dentry *new_dir_dentry, struct dentry *new_dentry)
{
+ struct inode *old_dir = old_dir_dentry->d_inode;
+ struct inode *new_dir = new_dir_dentry->d_inode;
int error;
int is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
const char *old_name;
@@ -2742,14 +2758,14 @@ static int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (old_dentry->d_inode == new_dentry->d_inode)
return 0;

- error = may_delete(old_dir, old_dentry, is_dir);
+ error = may_delete(old_dir_dentry, old_dentry, is_dir);
if (error)
return error;

if (!new_dentry->d_inode)
- error = may_create(new_dir, new_dentry, NULL);
+ error = may_create(new_dir_dentry, new_dentry);
else
- error = may_delete(new_dir, new_dentry, is_dir);
+ error = may_delete(new_dir_dentry, new_dentry, is_dir);
if (error)
return error;

@@ -2785,10 +2801,8 @@ int path_rename(struct path *old_dir_path, struct dentry *old_dentry,

error = mnt_want_write(mnt);
if (!error) {
- struct inode *old_dir = old_dir_path->dentry->d_inode;
- struct inode *new_dir = new_dir_path->dentry->d_inode;
-
- error = vfs_rename(old_dir, old_dentry, new_dir, new_dentry);
+ error = vfs_rename(old_dir_path->dentry, old_dentry,
+ new_dir_path->dentry, new_dentry);
mnt_drop_write(mnt);
}

@@ -3041,8 +3055,7 @@ EXPORT_SYMBOL(page_symlink);
EXPORT_SYMBOL(page_symlink_inode_operations);
EXPORT_SYMBOL(path_lookup);
EXPORT_SYMBOL(vfs_path_lookup);
-EXPORT_SYMBOL(permission);
-EXPORT_SYMBOL(vfs_permission);
+EXPORT_SYMBOL(path_permission);
EXPORT_SYMBOL(file_permission);
EXPORT_SYMBOL(unlock_rename);
EXPORT_SYMBOL(vfs_follow_link);
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index f288b3e..060bd4d 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1929,17 +1929,18 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags)
return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags));
}

-int nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
+int nfs_permission(struct dentry *dentry, int mask)
{
+ struct inode *inode = dentry->d_inode;
struct rpc_cred *cred;
int res = 0;

nfs_inc_stats(inode, NFSIOS_VFSACCESS);

- if (mask == 0)
+ if ((mask & PERMISSION_MASK) == 0)
goto out;
/* Is this sys_access() ? */
- if (nd != NULL && (nd->flags & LOOKUP_ACCESS))
+ if ((mask & PERM_OP_MASK) == PERM_OP_ACCESS)
goto force_lookup;

switch (inode->i_mode & S_IFMT) {
@@ -1947,9 +1948,8 @@ int nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
goto out;
case S_IFREG:
/* NFSv4 has atomic_open... */
- if (nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN)
- && nd != NULL
- && (nd->flags & LOOKUP_OPEN))
+ if (nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN) &&
+ (mask & PERM_OP_MASK) == PERM_OP_OPEN)
goto out;
break;
case S_IFDIR:
@@ -1969,12 +1969,15 @@ force_lookup:

cred = rpc_lookup_cred();
if (!IS_ERR(cred)) {
- res = nfs_do_access(inode, cred, mask);
+ res = nfs_do_access(inode, cred, mask & PERMISSION_MASK);
put_rpccred(cred);
} else
res = PTR_ERR(cred);
unlock_kernel();
out:
+ if (res == 0)
+ res = check_execute(inode, mask);
+
dfprintk(VFS, "NFS: permission(%s/%ld), mask=0x%x, res=%d\n",
inode->i_sb->s_id, inode->i_ino, mask, res);
return res;
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 100ae56..f8240ea 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -41,7 +41,7 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry)
struct svc_export *exp = expv;
int rv;
struct dentry *tdentry;
- struct dentry *parent;
+ struct path parent = { .mnt = exp->ex_path.mnt };

if (exp->ex_flags & NFSEXP_NOSUBTREECHECK)
return 1;
@@ -50,14 +50,15 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry)
while (tdentry != exp->ex_path.dentry && !IS_ROOT(tdentry)) {
/* make sure parents give x permission to user */
int err;
- parent = dget_parent(tdentry);
- err = permission(parent->d_inode, MAY_EXEC, NULL);
+
+ parent.dentry = dget_parent(tdentry);
+ err = path_permission(&parent, MAY_EXEC);
if (err < 0) {
- dput(parent);
+ dput(parent.dentry);
break;
}
dput(tdentry);
- tdentry = parent;
+ tdentry = parent.dentry;
}
if (tdentry != exp->ex_path.dentry)
dprintk("nfsd_acceptable failed at %p %s\n", tdentry, tdentry->d_name.name);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index d361354..ccda8ce 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1878,6 +1878,10 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
{
struct inode *inode = dentry->d_inode;
int err;
+ struct path path = {
+ .mnt = exp->ex_path.mnt,
+ .dentry = dentry,
+ };

if (acc == MAY_NOP)
return 0;
@@ -1942,12 +1946,12 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
inode->i_uid == current->fsuid)
return 0;

- err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC), NULL);
+ err = path_permission(&path, acc & (MAY_READ|MAY_WRITE|MAY_EXEC));

/* Allow read access to binaries even when mode 111 */
if (err == -EACCES && S_ISREG(inode->i_mode) &&
acc == (MAY_READ | MAY_OWNER_OVERRIDE))
- err = permission(inode, MAY_EXEC, NULL);
+ err = path_permission(&path, MAY_EXEC);

return err? nfserrno(err) : 0;
}
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 57e0d30..0a53a18 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1176,8 +1176,9 @@ bail:
return err;
}

-int ocfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
+int ocfs2_permission(struct dentry *dentry, int mask)
{
+ struct inode *inode = dentry->d_inode;
int ret;

mlog_entry_void();
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h
index 048ddca..ef74fa7 100644
--- a/fs/ocfs2/file.h
+++ b/fs/ocfs2/file.h
@@ -62,8 +62,7 @@ int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
int ocfs2_setattr(struct dentry *dentry, struct iattr *attr);
int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat);
-int ocfs2_permission(struct inode *inode, int mask,
- struct nameidata *nd);
+int ocfs2_permission(struct dentry *dentry, int mask);

int ocfs2_should_update_atime(struct inode *inode,
struct vfsmount *vfsmnt);
diff --git a/fs/open.c b/fs/open.c
index ceb18bc..6f9cbcc 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -267,7 +267,7 @@ static long do_sys_truncate(const char __user * path, loff_t length)
if (error)
goto dput_and_out;

- error = vfs_permission(&nd, MAY_WRITE);
+ error = path_permission(&nd.path, MAY_WRITE);
if (error)
goto mnt_drop_write_and_out;

@@ -467,11 +467,11 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
else
current->cap_effective = current->cap_permitted;

- res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
+ res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
if (res)
goto out;

- res = vfs_permission(&nd, mode);
+ res = path_permission(&nd.path, mode | PERM_OP_ACCESS);
/* SuS v2 requires we report a read only fs too */
if(res || !(mode & S_IWOTH) ||
special_file(nd.path.dentry->d_inode->i_mode))
@@ -509,12 +509,11 @@ asmlinkage long sys_chdir(const char __user * filename)
struct nameidata nd;
int error;

- error = __user_walk(filename,
- LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_CHDIR, &nd);
+ error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd);
if (error)
goto out;

- error = vfs_permission(&nd, MAY_EXEC);
+ error = path_permission(&nd.path, MAY_EXEC | PERM_OP_CHDIR);
if (error)
goto dput_and_out;

@@ -543,7 +542,7 @@ asmlinkage long sys_fchdir(unsigned int fd)
if (!S_ISDIR(inode->i_mode))
goto out_putf;

- error = file_permission(file, MAY_EXEC);
+ error = file_permission(file, MAY_EXEC | PERM_OP_CHDIR);
if (!error)
set_fs_pwd(current->fs, &file->f_path);
out_putf:
@@ -561,7 +560,7 @@ asmlinkage long sys_chroot(const char __user * filename)
if (error)
goto out;

- error = vfs_permission(&nd, MAY_EXEC);
+ error = path_permission(&nd.path, MAY_EXEC);
if (error)
goto dput_and_out;

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 808cbdc..2d74dbb 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1814,9 +1814,9 @@ static const struct file_operations proc_fd_operations = {
* /proc/pid/fd needs a special permission handler so that a process can still
* access /proc/self/fd after it has executed a setuid().
*/
-static int proc_fd_permission(struct inode *inode, int mask,
- struct nameidata *nd)
+static int proc_fd_permission(struct dentry *dentry, int mask)
{
+ struct inode *inode = dentry->d_inode;
int rv;

rv = generic_permission(inode, mask, NULL);
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 5acc001..f72fae4 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -343,7 +343,7 @@ out:
return ret;
}

-static int proc_sys_permission(struct inode *inode, int mask, struct nameidata *nd)
+static int proc_sys_permission(struct dentry *dentry, int mask)
{
/*
* sysctl entries that are not writeable,
@@ -351,7 +351,7 @@ static int proc_sys_permission(struct inode *inode, int mask, struct nameidata *
*/
struct ctl_table_header *head;
struct ctl_table *table;
- struct dentry *dentry;
+ struct inode *inode = dentry->d_inode;
int mode;
int depth;
int error;
@@ -359,6 +359,7 @@ static int proc_sys_permission(struct inode *inode, int mask, struct nameidata *
head = NULL;
depth = PROC_I(inode)->fd;

+ mask &= PERMISSION_MASK;
/* First check the cached permissions, in case we don't have
* enough information to lookup the sysctl table entry.
*/
@@ -376,10 +377,9 @@ static int proc_sys_permission(struct inode *inode, int mask, struct nameidata *
/* If we can't get a sysctl table entry the permission
* checks on the cached mode will have to be enough.
*/
- if (!nd || !depth)
+ if (!depth)
goto out;

- dentry = nd->path.dentry;
table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);

/* If the entry does not exist deny permission */
@@ -391,6 +391,9 @@ static int proc_sys_permission(struct inode *inode, int mask, struct nameidata *
error = sysctl_perm(head->root, table, mask);
out:
sysctl_head_finish(head);
+ if (!error)
+ error = check_execute(inode, mask);
+
return error;
}

diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index 4125468..6d710e3 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -1270,8 +1270,10 @@ static int reiserfs_check_acl(struct inode *inode, int mask)
return error;
}

-int reiserfs_permission(struct inode *inode, int mask, struct nameidata *nd)
+int reiserfs_permission(struct dentry *dentry, int mask)
{
+ struct inode *inode = dentry->d_inode;
+
/*
* We don't do permission checks on the internal objects.
* Permissions are determined by the "owning" object.
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index efbe29a..7000dc2 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -408,18 +408,19 @@ smb_file_release(struct inode *inode, struct file * file)
* privileges, so we need our own check for this.
*/
static int
-smb_file_permission(struct inode *inode, int mask, struct nameidata *nd)
+smb_file_permission(struct dentry *dentry, int mask)
{
- int mode = inode->i_mode;
- int error = 0;
+ int mode = dentry->d_inode->i_mode;

VERBOSE("mode=%x, mask=%x\n", mode, mask);

/* Look at user permissions */
+ mask &= PERMISSION_MASK;
mode >>= 6;
if ((mode & 7 & mask) != mask)
- error = -EACCES;
- return error;
+ return -EACCES;
+
+ return check_execute(dentry->d_inode, mask);
}

const struct file_operations smb_file_operations =
diff --git a/fs/utimes.c b/fs/utimes.c
index 2390e3a..3b85b0b 100644
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -141,7 +141,7 @@ static int do_utimes_name(int dfd, char __user *filename,
goto out_path_put;

if (!is_owner_or_cap(inode)) {
- error = vfs_permission(&nd, MAY_WRITE);
+ error = path_permission(&nd.path, MAY_WRITE);
if (error)
goto out_path_put;
}
diff --git a/fs/xattr.c b/fs/xattr.c
index 7eb9cd9..b403da3 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -26,8 +26,10 @@
* because different namespaces have very different rules.
*/
static int
-xattr_permission(struct inode *inode, const char *name, int mask)
+xattr_permission(struct path *path, const char *name, int mask)
{
+ struct inode *inode = path->dentry->d_inode;
+
/*
* We can never set or remove an extended attribute on a read-only
* filesystem or on an immutable / append-only inode.
@@ -63,17 +65,18 @@ xattr_permission(struct inode *inode, const char *name, int mask)
return -EPERM;
}

- return permission(inode, mask, NULL);
+ return path_permission(path, mask);
}

static int
-vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
+vfs_setxattr(struct path *path, const char *name, const void *value,
size_t size, int flags)
{
+ struct dentry *dentry = path->dentry;
struct inode *inode = dentry->d_inode;
int error;

- error = xattr_permission(inode, name, MAY_WRITE);
+ error = xattr_permission(path, name, MAY_WRITE);
if (error)
return error;

@@ -108,7 +111,7 @@ int path_setxattr(struct path *path, const char *name, const void *value,
int error = mnt_want_write(path->mnt);

if (!error) {
- error = vfs_setxattr(path->dentry, name, value, size, flags);
+ error = vfs_setxattr(path, name, value, size, flags);
mnt_drop_write(path->mnt);
}

@@ -150,7 +153,7 @@ path_getxattr(struct path *path, const char *name, void *value, size_t size)
struct inode *inode = dentry->d_inode;
int error;

- error = xattr_permission(inode, name, MAY_READ);
+ error = xattr_permission(path, name, MAY_READ);
if (error)
return error;

@@ -202,15 +205,16 @@ path_listxattr(struct path *path, char *list, size_t size)
EXPORT_SYMBOL_GPL(path_listxattr);

static int
-vfs_removexattr(struct dentry *dentry, const char *name)
+vfs_removexattr(struct path *path, const char *name)
{
+ struct dentry *dentry = path->dentry;
struct inode *inode = dentry->d_inode;
int error;

if (!inode->i_op->removexattr)
return -EOPNOTSUPP;

- error = xattr_permission(inode, name, MAY_WRITE);
+ error = xattr_permission(path, name, MAY_WRITE);
if (error)
return error;

@@ -232,7 +236,7 @@ int path_removexattr(struct path *path, const char *name)
int error = mnt_want_write(path->mnt);

if (!error) {
- error = vfs_removexattr(path->dentry, name);
+ error = vfs_removexattr(path, name);
mnt_drop_write(path->mnt);
}

diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index 2bf287e..5b31e4a 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -588,11 +588,10 @@ xfs_check_acl(

STATIC int
xfs_vn_permission(
- struct inode *inode,
- int mask,
- struct nameidata *nd)
+ struct dentry *dentry,
+ int mask)
{
- return generic_permission(inode, mask, xfs_check_acl);
+ return generic_permission(dentry->d_inode, mask, xfs_check_acl);
}
#else
#define xfs_vn_permission NULL
diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h
index 31b7531..663559c 100644
--- a/include/linux/coda_linux.h
+++ b/include/linux/coda_linux.h
@@ -37,7 +37,7 @@ extern const struct file_operations coda_ioctl_operations;
/* operations shared over more than one file */
int coda_open(struct inode *i, struct file *f);
int coda_release(struct inode *i, struct file *f);
-int coda_permission(struct inode *inode, int mask, struct nameidata *nd);
+int coda_permission(struct dentry *dentry, int mask);
int coda_revalidate_inode(struct dentry *);
int coda_getattr(struct vfsmount *, struct dentry *, struct kstat *);
int coda_setattr(struct dentry *, struct iattr *);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index f7f273b..fb26e0f 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -60,6 +60,16 @@ extern int dir_notify_enable;
#define MAY_WRITE 2
#define MAY_READ 4
#define MAY_APPEND 8
+#define PERMISSION_MASK (MAY_EXEC | MAY_WRITE | MAY_READ | MAY_APPEND)
+
+/*
+ * Special "MAY_" flags for i_op->permission(), indicating the filesystem
+ * operation for which we are performing the permission check.
+ */
+#define PERM_OP_MASK (0xf << 28)
+#define PERM_OP_OPEN (0x1 << 28)
+#define PERM_OP_ACCESS (0x2 << 28)
+#define PERM_OP_CHDIR (0x3 << 28)

#define FMODE_READ 1
#define FMODE_WRITE 2
@@ -1123,7 +1133,7 @@ extern void unlock_super(struct super_block *);
/*
* VFS helper functions..
*/
-extern int vfs_permission(struct nameidata *, int);
+extern int path_permission(struct path *, int);
extern int path_create(struct path *, struct dentry *, int, struct nameidata *);
extern int path_mkdir(struct path *, struct dentry *, int);
extern int path_mknod(struct path *, struct dentry *, int, dev_t);
@@ -1264,7 +1274,7 @@ struct inode_operations {
void * (*follow_link) (struct dentry *, struct nameidata *);
void (*put_link) (struct dentry *, struct nameidata *, void *);
void (*truncate) (struct inode *);
- int (*permission) (struct inode *, int, struct nameidata *);
+ int (*permission) (struct dentry *, int);
int (*setattr) (struct dentry *, struct iattr *);
int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
@@ -1758,9 +1768,9 @@ extern sector_t bmap(struct inode *, sector_t);
#endif
extern int notify_change(struct dentry *, struct iattr *);
extern int path_setattr(struct path *, struct iattr *);
-extern int permission(struct inode *, int, struct nameidata *);
extern int generic_permission(struct inode *, int,
int (*check_acl)(struct inode *, int));
+extern int check_execute(struct inode *, int);

extern int get_write_access(struct inode *);
extern int deny_write_access(struct file *);
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 24d88e9..75e8270 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -54,8 +54,6 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
*/
#define LOOKUP_OPEN (0x0100)
#define LOOKUP_CREATE (0x0200)
-#define LOOKUP_ACCESS (0x0400)
-#define LOOKUP_CHDIR (0x0800)

extern int __user_walk(const char __user *, unsigned, struct nameidata *);
extern int __user_walk_fd(int dfd, const char __user *, unsigned, struct nameidata *);
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 27d6a8d..07ef8a8 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -322,7 +322,7 @@ extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
-extern int nfs_permission(struct inode *, int, struct nameidata *);
+extern int nfs_permission(struct dentry *, int);
extern int nfs_open(struct inode *, struct file *);
extern int nfs_release(struct inode *, struct file *);
extern int nfs_attribute_timeout(struct inode *inode);
diff --git a/include/linux/reiserfs_xattr.h b/include/linux/reiserfs_xattr.h
index 66a9681..91f9dbb 100644
--- a/include/linux/reiserfs_xattr.h
+++ b/include/linux/reiserfs_xattr.h
@@ -55,7 +55,7 @@ int reiserfs_removexattr(struct dentry *dentry, const char *name);
int reiserfs_delete_xattrs(struct inode *inode);
int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs);
int reiserfs_xattr_init(struct super_block *sb, int mount_flags);
-int reiserfs_permission(struct inode *inode, int mask, struct nameidata *nd);
+int reiserfs_permission(struct dentry *dentry, int mask);

int reiserfs_xattr_del(struct inode *, const char *);
int reiserfs_xattr_get(const struct inode *, const char *, void *, size_t);
diff --git a/include/linux/security.h b/include/linux/security.h
index 50737c7..030b137 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -407,7 +407,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* called when the actual read/write operations are performed.
* @inode contains the inode structure to check.
* @mask contains the permission mask.
- * @nd contains the nameidata (may be NULL).
* Return 0 if permission is granted.
* @inode_setattr:
* Check permission before setting file attributes. Note that the kernel
@@ -1370,7 +1369,7 @@ struct security_operations {
struct inode *new_dir, struct dentry *new_dentry);
int (*inode_readlink) (struct dentry *dentry);
int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);
- int (*inode_permission) (struct inode *inode, int mask, struct nameidata *nd);
+ int (*inode_permission) (struct inode *inode, int mask);
int (*inode_setattr) (struct dentry *dentry, struct iattr *attr);
int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
void (*inode_delete) (struct inode *inode);
@@ -1641,7 +1640,7 @@ int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry);
int security_inode_readlink(struct dentry *dentry);
int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd);
-int security_inode_permission(struct inode *inode, int mask, struct nameidata *nd);
+int security_inode_permission(struct inode *inode, int mask);
int security_inode_setattr(struct dentry *dentry, struct iattr *attr);
int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry);
void security_inode_delete(struct inode *inode);
@@ -2032,8 +2031,7 @@ static inline int security_inode_follow_link(struct dentry *dentry,
return 0;
}

-static inline int security_inode_permission(struct inode *inode, int mask,
- struct nameidata *nd)
+static inline int security_inode_permission(struct inode *inode, int mask)
{
return 0;
}
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index f2d12d5..be2ae57 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -43,7 +43,7 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
}

#ifdef CONFIG_TMPFS_POSIX_ACL
-int shmem_permission(struct inode *, int, struct nameidata *);
+int shmem_permission(struct dentry *, int);
int shmem_acl_init(struct inode *, struct inode *);
void shmem_acl_destroy_inode(struct inode *);

diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index c229691..265a27d 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -647,19 +647,22 @@ static struct file *do_open(struct dentry *dentry, int oflag)
static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
MAY_READ | MAY_WRITE };

+ struct path path = {
+ .mnt = mqueue_mnt,
+ .dentry = dentry,
+ };
+
if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) {
- dput(dentry);
- mntput(mqueue_mnt);
+ path_put(&path);
return ERR_PTR(-EINVAL);
}

- if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL)) {
- dput(dentry);
- mntput(mqueue_mnt);
+ if (path_permission(&path, oflag2acc[oflag & O_ACCMODE])) {
+ path_put(&path);
return ERR_PTR(-EACCES);
}

- return dentry_open(dentry, mqueue_mnt, oflag);
+ return dentry_open(path.dentry, path.mnt, oflag);
}

asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
diff --git a/mm/shmem_acl.c b/mm/shmem_acl.c
index f5664c5..042f244 100644
--- a/mm/shmem_acl.c
+++ b/mm/shmem_acl.c
@@ -191,7 +191,7 @@ shmem_check_acl(struct inode *inode, int mask)
* shmem_permission - permission() inode operation
*/
int
-shmem_permission(struct inode *inode, int mask, struct nameidata *nd)
+shmem_permission(struct dentry *dentry, int mask)
{
- return generic_permission(inode, mask, shmem_check_acl);
+ return generic_permission(dentry->d_inode, mask, shmem_check_acl);
}
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index abd4614..5401cb8 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -713,7 +713,7 @@ static struct sock *unix_find_other(struct net *net,
err = path_lookup(sunname->sun_path, LOOKUP_FOLLOW, &nd);
if (err)
goto fail;
- err = vfs_permission(&nd, MAY_WRITE);
+ err = path_permission(&nd.path, MAY_WRITE);
if (err)
goto put_fail;

diff --git a/security/dummy.c b/security/dummy.c
index f50c6c3..e5ad811 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -345,7 +345,7 @@ static int dummy_inode_follow_link (struct dentry *dentry,
return 0;
}

-static int dummy_inode_permission (struct inode *inode, int mask, struct nameidata *nd)
+static int dummy_inode_permission (struct inode *inode, int mask)
{
return 0;
}
diff --git a/security/security.c b/security/security.c
index 01f0acd..5fd5249 100644
--- a/security/security.c
+++ b/security/security.c
@@ -463,11 +463,11 @@ int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd)
return security_ops->inode_follow_link(dentry, nd);
}

-int security_inode_permission(struct inode *inode, int mask, struct nameidata *nd)
+int security_inode_permission(struct inode *inode, int mask)
{
if (unlikely(IS_PRIVATE(inode)))
return 0;
- return security_ops->inode_permission(inode, mask, nd);
+ return security_ops->inode_permission(inode, mask);
}

int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 1c864c0..491bf88 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2579,15 +2579,15 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na
return dentry_has_perm(current, NULL, dentry, FILE__READ);
}

-static int selinux_inode_permission(struct inode *inode, int mask,
- struct nameidata *nd)
+static int selinux_inode_permission(struct inode *inode, int mask)
{
int rc;

- rc = secondary_ops->inode_permission(inode, mask, nd);
+ rc = secondary_ops->inode_permission(inode, mask);
if (rc)
return rc;

+ mask &= PERMISSION_MASK;
if (!mask) {
/* No permission to check. Existence test. */
return 0;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index b5c8f92..cee792f 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -515,14 +515,12 @@ static int smack_inode_rename(struct inode *old_inode,
* smack_inode_permission - Smack version of permission()
* @inode: the inode in question
* @mask: the access requested
- * @nd: unused
*
* This is the important Smack hook.
*
* Returns 0 if access is permitted, -EACCES otherwise
*/
-static int smack_inode_permission(struct inode *inode, int mask,
- struct nameidata *nd)
+static int smack_inode_permission(struct inode *inode, int mask)
{
/*
* No permission to check. Existence test. Yup, it's there.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/