Correct .gbs.conf settings
[platform/adaptation/renesas_rcar/renesas_kernel.git] / fs / namei.c
index 2f730ef..0dd72c8 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/device_cgroup.h>
 #include <linux/fs_struct.h>
 #include <linux/posix_acl.h>
+#include <linux/hash.h>
 #include <asm/uaccess.h>
 
 #include "internal.h"
@@ -332,10 +333,11 @@ int generic_permission(struct inode *inode, int mask)
 
        if (S_ISDIR(inode->i_mode)) {
                /* DACs are overridable for directories */
-               if (inode_capable(inode, CAP_DAC_OVERRIDE))
+               if (capable_wrt_inode_uidgid(inode, CAP_DAC_OVERRIDE))
                        return 0;
                if (!(mask & MAY_WRITE))
-                       if (inode_capable(inode, CAP_DAC_READ_SEARCH))
+                       if (capable_wrt_inode_uidgid(inode,
+                                                    CAP_DAC_READ_SEARCH))
                                return 0;
                return -EACCES;
        }
@@ -345,7 +347,7 @@ int generic_permission(struct inode *inode, int mask)
         * at least one exec bit set.
         */
        if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO))
-               if (inode_capable(inode, CAP_DAC_OVERRIDE))
+               if (capable_wrt_inode_uidgid(inode, CAP_DAC_OVERRIDE))
                        return 0;
 
        /*
@@ -353,7 +355,7 @@ int generic_permission(struct inode *inode, int mask)
         */
        mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
        if (mask == MAY_READ)
-               if (inode_capable(inode, CAP_DAC_READ_SEARCH))
+               if (capable_wrt_inode_uidgid(inode, CAP_DAC_READ_SEARCH))
                        return 0;
 
        return -EACCES;
@@ -640,24 +642,22 @@ static int complete_walk(struct nameidata *nd)
 
 static __always_inline void set_root(struct nameidata *nd)
 {
-       if (!nd->root.mnt)
-               get_fs_root(current->fs, &nd->root);
+       get_fs_root(current->fs, &nd->root);
 }
 
 static int link_path_walk(const char *, struct nameidata *);
 
-static __always_inline void set_root_rcu(struct nameidata *nd)
+static __always_inline unsigned set_root_rcu(struct nameidata *nd)
 {
-       if (!nd->root.mnt) {
-               struct fs_struct *fs = current->fs;
-               unsigned seq;
+       struct fs_struct *fs = current->fs;
+       unsigned seq, res;
 
-               do {
-                       seq = read_seqcount_begin(&fs->seq);
-                       nd->root = fs->root;
-                       nd->seq = __read_seqcount_begin(&nd->root.dentry->d_seq);
-               } while (read_seqcount_retry(&fs->seq, seq));
-       }
+       do {
+               seq = read_seqcount_begin(&fs->seq);
+               nd->root = fs->root;
+               res = __read_seqcount_begin(&nd->root.dentry->d_seq);
+       } while (read_seqcount_retry(&fs->seq, seq));
+       return res;
 }
 
 static void path_put_conditional(struct path *path, struct nameidata *nd)
@@ -857,7 +857,8 @@ follow_link(struct path *link, struct nameidata *nd, void **p)
                        return PTR_ERR(s);
                }
                if (*s == '/') {
-                       set_root(nd);
+                       if (!nd->root.mnt)
+                               set_root(nd);
                        path_put(&nd->path);
                        nd->path = nd->root;
                        path_get(&nd->root);
@@ -1109,7 +1110,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                        return false;
 
                if (!d_mountpoint(path->dentry))
-                       break;
+                       return true;
 
                mounted = __lookup_mnt(path->mnt, path->dentry);
                if (!mounted)
@@ -1125,25 +1126,13 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                 */
                *inode = path->dentry->d_inode;
        }
-       return true;
-}
-
-static void follow_mount_rcu(struct nameidata *nd)
-{
-       while (d_mountpoint(nd->path.dentry)) {
-               struct mount *mounted;
-               mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
-               if (!mounted)
-                       break;
-               nd->path.mnt = &mounted->mnt;
-               nd->path.dentry = mounted->mnt.mnt_root;
-               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
-       }
+       return read_seqretry(&mount_lock, nd->m_seq);
 }
 
 static int follow_dotdot_rcu(struct nameidata *nd)
 {
-       set_root_rcu(nd);
+       if (!nd->root.mnt)
+               set_root_rcu(nd);
 
        while (1) {
                if (nd->path.dentry == nd->root.dentry &&
@@ -1166,7 +1155,17 @@ static int follow_dotdot_rcu(struct nameidata *nd)
                        break;
                nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
        }
-       follow_mount_rcu(nd);
+       while (d_mountpoint(nd->path.dentry)) {
+               struct mount *mounted;
+               mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
+               if (!mounted)
+                       break;
+               nd->path.mnt = &mounted->mnt;
+               nd->path.dentry = mounted->mnt.mnt_root;
+               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
+               if (!read_seqretry(&mount_lock, nd->m_seq))
+                       goto failed;
+       }
        nd->inode = nd->path.dentry->d_inode;
        return 0;
 
@@ -1245,7 +1244,8 @@ static void follow_mount(struct path *path)
 
 static void follow_dotdot(struct nameidata *nd)
 {
-       set_root(nd);
+       if (!nd->root.mnt)
+               set_root(nd);
 
        while(1) {
                struct dentry *old = nd->path.dentry;
@@ -1540,7 +1540,7 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
                inode = path->dentry->d_inode;
        }
        err = -ENOENT;
-       if (!inode)
+       if (!inode || d_is_negative(path->dentry))
                goto out_path_put;
 
        if (should_follow_link(path->dentry, follow)) {
@@ -1626,8 +1626,7 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd)
 
 static inline unsigned int fold_hash(unsigned long hash)
 {
-       hash += hash >> (8*sizeof(int));
-       return hash;
+       return hash_64(hash, 32);
 }
 
 #else  /* 32-bit case */
@@ -1799,7 +1798,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                        if (err)
                                return err;
                }
-               if (!d_is_directory(nd->path.dentry)) {
+               if (!d_can_lookup(nd->path.dentry)) {
                        err = -ENOTDIR; 
                        break;
                }
@@ -1820,7 +1819,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
                struct dentry *root = nd->root.dentry;
                struct inode *inode = root->d_inode;
                if (*name) {
-                       if (!d_is_directory(root))
+                       if (!d_can_lookup(root))
                                return -ENOTDIR;
                        retval = inode_permission(inode, MAY_EXEC);
                        if (retval)
@@ -1844,7 +1843,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
        if (*name=='/') {
                if (flags & LOOKUP_RCU) {
                        rcu_read_lock();
-                       set_root_rcu(nd);
+                       nd->seq = set_root_rcu(nd);
                } else {
                        set_root(nd);
                        path_get(&nd->root);
@@ -1876,7 +1875,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
                dentry = f.file->f_path.dentry;
 
                if (*name) {
-                       if (!d_is_directory(dentry)) {
+                       if (!d_can_lookup(dentry)) {
                                fdput(f);
                                return -ENOTDIR;
                        }
@@ -1958,7 +1957,7 @@ static int path_lookupat(int dfd, const char *name,
                err = complete_walk(nd);
 
        if (!err && nd->flags & LOOKUP_DIRECTORY) {
-               if (!d_is_directory(nd->path.dentry)) {
+               if (!d_can_lookup(nd->path.dentry)) {
                        path_put(&nd->path);
                        err = -ENOTDIR;
                }
@@ -2243,15 +2242,16 @@ mountpoint_last(struct nameidata *nd, struct path *path)
        mutex_unlock(&dir->d_inode->i_mutex);
 
 done:
-       if (!dentry->d_inode) {
+       if (!dentry->d_inode || d_is_negative(dentry)) {
                error = -ENOENT;
                dput(dentry);
                goto out;
        }
        path->dentry = dentry;
-       path->mnt = mntget(nd->path.mnt);
+       path->mnt = nd->path.mnt;
        if (should_follow_link(dentry, nd->flags & LOOKUP_FOLLOW))
                return 1;
+       mntget(path->mnt);
        follow_mount(path);
        error = 0;
 out:
@@ -2373,7 +2373,7 @@ static inline int check_sticky(struct inode *dir, struct inode *inode)
                return 0;
        if (uid_eq(dir->i_uid, fsuid))
                return 0;
-       return !inode_capable(inode, CAP_FOWNER);
+       return !capable_wrt_inode_uidgid(inode, CAP_FOWNER);
 }
 
 /*
@@ -2417,11 +2417,11 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
            IS_IMMUTABLE(inode) || IS_SWAPFILE(inode))
                return -EPERM;
        if (isdir) {
-               if (!d_is_directory(victim) && !d_is_autodir(victim))
+               if (!d_is_dir(victim))
                        return -ENOTDIR;
                if (IS_ROOT(victim))
                        return -EBUSY;
-       } else if (d_is_directory(victim) || d_is_autodir(victim))
+       } else if (d_is_dir(victim))
                return -EISDIR;
        if (IS_DEADDIR(dir))
                return -ENOENT;
@@ -2985,7 +2985,7 @@ retry_lookup:
 finish_lookup:
        /* we _can_ be in RCU mode here */
        error = -ENOENT;
-       if (d_is_negative(path->dentry)) {
+       if (!inode || d_is_negative(path->dentry)) {
                path_to_nameidata(path, nd);
                goto out;
        }
@@ -3019,11 +3019,10 @@ finish_open:
        }
        audit_inode(name, nd->path.dentry, 0);
        error = -EISDIR;
-       if ((open_flag & O_CREAT) &&
-           (d_is_directory(nd->path.dentry) || d_is_autodir(nd->path.dentry)))
+       if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry))
                goto out;
        error = -ENOTDIR;
-       if ((nd->flags & LOOKUP_DIRECTORY) && !d_is_directory(nd->path.dentry))
+       if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry))
                goto out;
        if (!S_ISREG(nd->inode->i_mode))
                will_truncate = false;
@@ -3129,7 +3128,8 @@ static int do_tmpfile(int dfd, struct filename *pathname,
        if (error)
                goto out2;
        audit_inode(pathname, nd->path.dentry, 0);
-       error = may_open(&nd->path, op->acc_mode, op->open_flag);
+       /* Don't check for other permissions, the inode was just created */
+       error = may_open(&nd->path, MAY_OPEN, op->open_flag);
        if (error)
                goto out2;
        file->f_path.mnt = nd->path.mnt;
@@ -3747,7 +3747,7 @@ exit1:
 slashes:
        if (d_is_negative(dentry))
                error = -ENOENT;
-       else if (d_is_directory(dentry) || d_is_autodir(dentry))
+       else if (d_is_dir(dentry))
                error = -EISDIR;
        else
                error = -ENOTDIR;
@@ -4126,7 +4126,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
               struct inode **delegated_inode)
 {
        int error;
-       int is_dir = d_is_directory(old_dentry) || d_is_autodir(old_dentry);
+       int is_dir = d_is_dir(old_dentry);
        const unsigned char *old_name;
 
        if (old_dentry->d_inode == new_dentry->d_inode)
@@ -4219,7 +4219,7 @@ retry_deleg:
        if (d_is_negative(old_dentry))
                goto exit4;
        /* unless the source is a directory trailing slashes give -ENOTDIR */
-       if (!d_is_directory(old_dentry) && !d_is_autodir(old_dentry)) {
+       if (!d_is_dir(old_dentry)) {
                error = -ENOTDIR;
                if (oldnd.last.name[oldnd.last.len])
                        goto exit4;