lkml.org 
[lkml]   [2008]   [May]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[git patch] vfs: permission API cleanup (v2)
    From
    Date
    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.

    \
     
     \ /
      Last update: 2008-05-22 18:53    [W:0.261 / U:90.784 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site