Revert "input: touch: raydium: V61.7 code drop"
[linux-3.10.git] / fs / namei.c
index 5dbc3f8..cccaf77 100644 (file)
  */
 void final_putname(struct filename *name)
 {
-       __putname(name->name);
-       kfree(name);
+       if (name->separate) {
+               __putname(name->name);
+               kfree(name);
+       } else {
+               __putname(name);
+       }
 }
 
+#define EMBEDDED_NAME_MAX      (PATH_MAX - sizeof(struct filename))
+
 static struct filename *
 getname_flags(const char __user *filename, int flags, int *empty)
 {
        struct filename *result, *err;
-       char *kname;
        int len;
+       long max;
+       char *kname;
 
        result = audit_reusename(filename);
        if (result)
                return result;
 
-       /* FIXME: create dedicated slabcache? */
-       result = kzalloc(sizeof(*result), GFP_KERNEL);
+       result = __getname();
        if (unlikely(!result))
                return ERR_PTR(-ENOMEM);
 
-       kname = __getname();
-       if (unlikely(!kname)) {
-               err = ERR_PTR(-ENOMEM);
-               goto error_free_name;
-       }
-
+       /*
+        * First, try to embed the struct filename inside the names_cache
+        * allocation
+        */
+       kname = (char *)result + sizeof(*result);
        result->name = kname;
-       result->uptr = filename;
-       len = strncpy_from_user(kname, filename, PATH_MAX);
+       result->separate = false;
+       max = EMBEDDED_NAME_MAX;
+
+recopy:
+       len = strncpy_from_user(kname, filename, max);
        if (unlikely(len < 0)) {
                err = ERR_PTR(len);
                goto error;
        }
 
+       /*
+        * Uh-oh. We have a name that's approaching PATH_MAX. Allocate a
+        * separate struct filename so we can dedicate the entire
+        * names_cache allocation for the pathname, and re-do the copy from
+        * userland.
+        */
+       if (len == EMBEDDED_NAME_MAX && max == EMBEDDED_NAME_MAX) {
+               kname = (char *)result;
+
+               result = kzalloc(sizeof(*result), GFP_KERNEL);
+               if (!result) {
+                       err = ERR_PTR(-ENOMEM);
+                       result = (struct filename *)kname;
+                       goto error;
+               }
+               result->name = kname;
+               result->separate = true;
+               max = PATH_MAX;
+               goto recopy;
+       }
+
        /* The empty path is special. */
        if (unlikely(!len)) {
                if (empty)
@@ -163,15 +192,15 @@ getname_flags(const char __user *filename, int flags, int *empty)
        }
 
        err = ERR_PTR(-ENAMETOOLONG);
-       if (likely(len < PATH_MAX)) {
-               audit_getname(result);
-               return result;
-       }
+       if (unlikely(len >= PATH_MAX))
+               goto error;
+
+       result->uptr = filename;
+       audit_getname(result);
+       return result;
 
 error:
-       __putname(kname);
-error_free_name:
-       kfree(result);
+       final_putname(result);
        return err;
 }
 
@@ -422,7 +451,7 @@ int inode_permission(struct inode *inode, int mask)
  *
  * Given a path increment the reference count to the dentry and the vfsmount.
  */
-void path_get(struct path *path)
+void path_get(const struct path *path)
 {
        mntget(path->mnt);
        dget(path->dentry);
@@ -435,7 +464,7 @@ EXPORT_SYMBOL(path_get);
  *
  * Given a path decrement the reference count to the dentry and the vfsmount.
  */
-void path_put(struct path *path)
+void path_put(const struct path *path)
 {
        dput(path->dentry);
        mntput(path->mnt);
@@ -571,14 +600,10 @@ static int complete_walk(struct nameidata *nd)
        if (likely(!(nd->flags & LOOKUP_JUMPED)))
                return 0;
 
-       if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE)))
+       if (likely(!(dentry->d_flags & DCACHE_OP_WEAK_REVALIDATE)))
                return 0;
 
-       if (likely(!(dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)))
-               return 0;
-
-       /* Note: we do not d_invalidate() */
-       status = d_revalidate(dentry, nd->flags);
+       status = dentry->d_op->d_weak_revalidate(dentry, nd->flags);
        if (status > 0)
                return 0;
 
@@ -664,8 +689,6 @@ void nd_jump_link(struct nameidata *nd, struct path *path)
        nd->path = *path;
        nd->inode = nd->path.dentry->d_inode;
        nd->flags |= LOOKUP_JUMPED;
-
-       BUG_ON(nd->inode->i_op->follow_link);
 }
 
 static inline void put_link(struct nameidata *nd, struct path *link, void *cookie)
@@ -676,8 +699,8 @@ static inline void put_link(struct nameidata *nd, struct path *link, void *cooki
        path_put(link);
 }
 
-int sysctl_protected_symlinks __read_mostly = 1;
-int sysctl_protected_hardlinks __read_mostly = 1;
+int sysctl_protected_symlinks __read_mostly = 0;
+int sysctl_protected_hardlinks __read_mostly = 0;
 
 /**
  * may_follow_link - Check symlink following for unsafe situations
@@ -1246,9 +1269,7 @@ static struct dentry *lookup_dcache(struct qstr *name, struct dentry *dir,
        *need_lookup = false;
        dentry = d_lookup(dir, name);
        if (dentry) {
-               if (d_need_lookup(dentry)) {
-                       *need_lookup = true;
-               } else if (dentry->d_flags & DCACHE_OP_REVALIDATE) {
+               if (dentry->d_flags & DCACHE_OP_REVALIDATE) {
                        error = d_revalidate(dentry, flags);
                        if (unlikely(error <= 0)) {
                                if (error < 0) {
@@ -1315,7 +1336,7 @@ static struct dentry *__lookup_hash(struct qstr *name,
  *  small and for now I'd prefer to have fast path as straight as possible.
  *  It _is_ time-critical.
  */
-static int lookup_fast(struct nameidata *nd, struct qstr *name,
+static int lookup_fast(struct nameidata *nd,
                       struct path *path, struct inode **inode)
 {
        struct vfsmount *mnt = nd->path.mnt;
@@ -1331,7 +1352,7 @@ static int lookup_fast(struct nameidata *nd, struct qstr *name,
         */
        if (nd->flags & LOOKUP_RCU) {
                unsigned seq;
-               dentry = __d_lookup_rcu(parent, name, &seq, nd->inode);
+               dentry = __d_lookup_rcu(parent, &nd->last, &seq, nd->inode);
                if (!dentry)
                        goto unlazy;
 
@@ -1354,8 +1375,6 @@ static int lookup_fast(struct nameidata *nd, struct qstr *name,
                        return -ECHILD;
                nd->seq = seq;
 
-               if (unlikely(d_need_lookup(dentry)))
-                       goto unlazy;
                if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) {
                        status = d_revalidate(dentry, nd->flags);
                        if (unlikely(status <= 0)) {
@@ -1375,17 +1394,12 @@ unlazy:
                if (unlazy_walk(nd, dentry))
                        return -ECHILD;
        } else {
-               dentry = __d_lookup(parent, name);
+               dentry = __d_lookup(parent, &nd->last);
        }
 
        if (unlikely(!dentry))
                goto need_lookup;
 
-       if (unlikely(d_need_lookup(dentry))) {
-               dput(dentry);
-               goto need_lookup;
-       }
-
        if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE) && need_reval)
                status = d_revalidate(dentry, nd->flags);
        if (unlikely(status <= 0)) {
@@ -1416,8 +1430,7 @@ need_lookup:
 }
 
 /* Fast lookup failed, do it the slow way */
-static int lookup_slow(struct nameidata *nd, struct qstr *name,
-                      struct path *path)
+static int lookup_slow(struct nameidata *nd, struct path *path)
 {
        struct dentry *dentry, *parent;
        int err;
@@ -1426,7 +1439,7 @@ static int lookup_slow(struct nameidata *nd, struct qstr *name,
        BUG_ON(nd->inode != parent->d_inode);
 
        mutex_lock(&parent->d_inode->i_mutex);
-       dentry = __lookup_hash(name, parent, nd->flags);
+       dentry = __lookup_hash(&nd->last, parent, nd->flags);
        mutex_unlock(&parent->d_inode->i_mutex);
        if (IS_ERR(dentry))
                return PTR_ERR(dentry);
@@ -1499,7 +1512,7 @@ static inline int should_follow_link(struct inode *inode, int follow)
 }
 
 static inline int walk_component(struct nameidata *nd, struct path *path,
-               struct qstr *name, int type, int follow)
+               int follow)
 {
        struct inode *inode;
        int err;
@@ -1508,14 +1521,14 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
         * to be able to know about the current root directory and
         * parent relationships.
         */
-       if (unlikely(type != LAST_NORM))
-               return handle_dots(nd, type);
-       err = lookup_fast(nd, name, path, &inode);
+       if (unlikely(nd->last_type != LAST_NORM))
+               return handle_dots(nd, nd->last_type);
+       err = lookup_fast(nd, path, &inode);
        if (unlikely(err)) {
                if (err < 0)
                        goto out_err;
 
-               err = lookup_slow(nd, name, path);
+               err = lookup_slow(nd, path);
                if (err < 0)
                        goto out_err;
 
@@ -1574,8 +1587,7 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd)
                res = follow_link(&link, nd, &cookie);
                if (res)
                        break;
-               res = walk_component(nd, path, &nd->last,
-                                    nd->last_type, LOOKUP_FOLLOW);
+               res = walk_component(nd, path, LOOKUP_FOLLOW);
                put_link(nd, &link, cookie);
        } while (res > 0);
 
@@ -1782,8 +1794,11 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                        }
                }
 
+               nd->last = this;
+               nd->last_type = type;
+
                if (!name[len])
-                       goto last_component;
+                       return 0;
                /*
                 * If it wasn't NUL, we know it was '/'. Skip that
                 * slash, and continue until no more slashes.
@@ -1792,10 +1807,11 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                        len++;
                } while (unlikely(name[len] == '/'));
                if (!name[len])
-                       goto last_component;
+                       return 0;
+
                name += len;
 
-               err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW);
+               err = walk_component(nd, &next, LOOKUP_FOLLOW);
                if (err < 0)
                        return err;
 
@@ -1804,16 +1820,10 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                        if (err)
                                return err;
                }
-               if (can_lookup(nd->inode))
-                       continue;
-               err = -ENOTDIR; 
-               break;
-               /* here ends the main loop */
-
-last_component:
-               nd->last = this;
-               nd->last_type = type;
-               return 0;
+               if (!can_lookup(nd->inode)) {
+                       err = -ENOTDIR; 
+                       break;
+               }
        }
        terminate_walk(nd);
        return err;
@@ -1830,7 +1840,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
        if (flags & LOOKUP_ROOT) {
                struct inode *inode = nd->root.dentry->d_inode;
                if (*name) {
-                       if (!inode->i_op->lookup)
+                       if (!can_lookup(inode))
                                return -ENOTDIR;
                        retval = inode_permission(inode, MAY_EXEC);
                        if (retval)
@@ -1874,6 +1884,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
                        get_fs_pwd(current->fs, &nd->path);
                }
        } else {
+               /* Caller must check execute permissions on the starting path component */
                struct fd f = fdget_raw(dfd);
                struct dentry *dentry;
 
@@ -1883,16 +1894,10 @@ static int path_init(int dfd, const char *name, unsigned int flags,
                dentry = f.file->f_path.dentry;
 
                if (*name) {
-                       if (!S_ISDIR(dentry->d_inode->i_mode)) {
+                       if (!can_lookup(dentry->d_inode)) {
                                fdput(f);
                                return -ENOTDIR;
                        }
-
-                       retval = inode_permission(dentry->d_inode, MAY_EXEC);
-                       if (retval) {
-                               fdput(f);
-                               return retval;
-                       }
                }
 
                nd->path = f.file->f_path;
@@ -1917,8 +1922,7 @@ static inline int lookup_last(struct nameidata *nd, struct path *path)
                nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
 
        nd->flags &= ~LOOKUP_PARENT;
-       return walk_component(nd, path, &nd->last, nd->last_type,
-                                       nd->flags & LOOKUP_FOLLOW);
+       return walk_component(nd, path, nd->flags & LOOKUP_FOLLOW);
 }
 
 /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
@@ -1972,7 +1976,7 @@ static int path_lookupat(int dfd, const char *name,
                err = complete_walk(nd);
 
        if (!err && nd->flags & LOOKUP_DIRECTORY) {
-               if (!nd->inode->i_op->lookup) {
+               if (!can_lookup(nd->inode)) {
                        path_put(&nd->path);
                        err = -ENOTDIR;
                }
@@ -1988,20 +1992,29 @@ static int path_lookupat(int dfd, const char *name,
        return err;
 }
 
-static int do_path_lookup(int dfd, const char *name,
+static int filename_lookup(int dfd, struct filename *name,
                                unsigned int flags, struct nameidata *nd)
 {
-       int retval = path_lookupat(dfd, name, flags | LOOKUP_RCU, nd);
+       int retval = path_lookupat(dfd, name->name, flags | LOOKUP_RCU, nd);
        if (unlikely(retval == -ECHILD))
-               retval = path_lookupat(dfd, name, flags, nd);
+               retval = path_lookupat(dfd, name->name, flags, nd);
        if (unlikely(retval == -ESTALE))
-               retval = path_lookupat(dfd, name, flags | LOOKUP_REVAL, nd);
+               retval = path_lookupat(dfd, name->name,
+                                               flags | LOOKUP_REVAL, nd);
 
        if (likely(!retval))
                audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT);
        return retval;
 }
 
+static int do_path_lookup(int dfd, const char *name,
+                               unsigned int flags, struct nameidata *nd)
+{
+       struct filename filename = { .name = name };
+
+       return filename_lookup(dfd, &filename, flags, nd);
+}
+
 /* does lookup, returns the object with parent locked */
 struct dentry *kern_path_locked(const char *name, struct path *path)
 {
@@ -2093,6 +2106,11 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
        if (!len)
                return ERR_PTR(-EACCES);
 
+       if (unlikely(name[0] == '.')) {
+               if (len < 2 || (len == 2 && name[1] == '.'))
+                       return ERR_PTR(-EACCES);
+       }
+
        while (len--) {
                c = *(const unsigned char *)name++;
                if (c == '/' || c == '\0')
@@ -2125,7 +2143,7 @@ int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
 
                BUG_ON(flags & LOOKUP_PARENT);
 
-               err = do_path_lookup(dfd, tmp->name, flags, &nd);
+               err = filename_lookup(dfd, tmp, flags, &nd);
                putname(tmp);
                if (!err)
                        *path = nd.path;
@@ -2139,16 +2157,26 @@ int user_path_at(int dfd, const char __user *name, unsigned flags,
        return user_path_at_empty(dfd, name, flags, path, NULL);
 }
 
+/*
+ * NB: most callers don't do anything directly with the reference to the
+ *     to struct filename, but the nd->last pointer points into the name string
+ *     allocated by getname. So we must hold the reference to it until all
+ *     path-walking is complete.
+ */
 static struct filename *
-user_path_parent(int dfd, const char __user *path, struct nameidata *nd)
+user_path_parent(int dfd, const char __user *path, struct nameidata *nd,
+                unsigned int flags)
 {
        struct filename *s = getname(path);
        int error;
 
+       /* only LOOKUP_REVAL is allowed in extra flags */
+       flags &= LOOKUP_REVAL;
+
        if (IS_ERR(s))
                return s;
 
-       error = do_path_lookup(dfd, s->name, LOOKUP_PARENT, nd);
+       error = filename_lookup(dfd, s, flags | LOOKUP_PARENT, nd);
        if (error) {
                putname(s);
                return ERR_PTR(error);
@@ -2235,6 +2263,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
  */
 static inline int may_create(struct inode *dir, struct dentry *child)
 {
+       audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE);
        if (child->d_inode)
                return -EEXIST;
        if (IS_DEADDIR(dir))
@@ -2646,7 +2675,7 @@ out_dput:
  */
 static int do_last(struct nameidata *nd, struct path *path,
                   struct file *file, const struct open_flags *op,
-                  int *opened, const char *pathname)
+                  int *opened, struct filename *name)
 {
        struct dentry *dir = nd->path.dentry;
        int open_flag = op->open_flag;
@@ -2673,7 +2702,7 @@ static int do_last(struct nameidata *nd, struct path *path,
                error = complete_walk(nd);
                if (error)
                        return error;
-               audit_inode(pathname, nd->path.dentry, 0);
+               audit_inode(name, nd->path.dentry, 0);
                if (open_flag & O_CREAT) {
                        error = -EISDIR;
                        goto out;
@@ -2683,7 +2712,7 @@ static int do_last(struct nameidata *nd, struct path *path,
                error = complete_walk(nd);
                if (error)
                        return error;
-               audit_inode(pathname, dir, 0);
+               audit_inode(name, dir, 0);
                goto finish_open;
        }
 
@@ -2693,7 +2722,7 @@ static int do_last(struct nameidata *nd, struct path *path,
                if (open_flag & O_PATH && !(nd->flags & LOOKUP_FOLLOW))
                        symlink_ok = true;
                /* we _can_ be in RCU mode here */
-               error = lookup_fast(nd, &nd->last, path, &inode);
+               error = lookup_fast(nd, path, &inode);
                if (likely(!error))
                        goto finish_lookup;
 
@@ -2712,7 +2741,7 @@ static int do_last(struct nameidata *nd, struct path *path,
                if (error)
                        return error;
 
-               audit_inode(pathname, dir, 0);
+               audit_inode(name, dir, LOOKUP_PARENT);
                error = -EISDIR;
                /* trailing slashes? */
                if (nd->last.name[nd->last.len])
@@ -2739,10 +2768,10 @@ retry_lookup:
                        goto out;
 
                if ((*opened & FILE_CREATED) ||
-                   !S_ISREG(file->f_path.dentry->d_inode->i_mode))
+                   !S_ISREG(file_inode(file)->i_mode))
                        will_truncate = false;
 
-               audit_inode(pathname, file->f_path.dentry, 0);
+               audit_inode(name, file->f_path.dentry, 0);
                goto opened;
        }
 
@@ -2759,7 +2788,7 @@ retry_lookup:
         * create/update audit record if it already exists.
         */
        if (path->dentry->d_inode)
-               audit_inode(pathname, path->dentry, 0);
+               audit_inode(name, path->dentry, 0);
 
        /*
         * If atomic_open() acquired write access it is dropped now due to
@@ -2822,9 +2851,9 @@ finish_lookup:
        if ((open_flag & O_CREAT) && S_ISDIR(nd->inode->i_mode))
                goto out;
        error = -ENOTDIR;
-       if ((nd->flags & LOOKUP_DIRECTORY) && !nd->inode->i_op->lookup)
+       if ((nd->flags & LOOKUP_DIRECTORY) && !can_lookup(nd->inode))
                goto out;
-       audit_inode(pathname, nd->path.dentry, 0);
+       audit_inode(name, nd->path.dentry, 0);
 finish_open:
        if (!S_ISREG(nd->inode->i_mode))
                will_truncate = false;
@@ -2892,7 +2921,7 @@ stale_open:
        goto retry_lookup;
 }
 
-static struct file *path_openat(int dfd, const char *pathname,
+static struct file *path_openat(int dfd, struct filename *pathname,
                struct nameidata *nd, const struct open_flags *op, int flags)
 {
        struct file *base = NULL;
@@ -2902,17 +2931,17 @@ static struct file *path_openat(int dfd, const char *pathname,
        int error;
 
        file = get_empty_filp();
-       if (!file)
-               return ERR_PTR(-ENFILE);
+       if (IS_ERR(file))
+               return file;
 
        file->f_flags = op->open_flag;
 
-       error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base);
+       error = path_init(dfd, pathname->name, flags | LOOKUP_PARENT, nd, &base);
        if (unlikely(error))
                goto out;
 
        current->total_link_count = 0;
-       error = link_path_walk(pathname, nd);
+       error = link_path_walk(pathname->name, nd);
        if (unlikely(error))
                goto out;
 
@@ -2958,7 +2987,7 @@ out:
        return file;
 }
 
-struct file *do_filp_open(int dfd, const char *pathname,
+struct file *do_filp_open(int dfd, struct filename *pathname,
                const struct open_flags *op, int flags)
 {
        struct nameidata nd;
@@ -2977,6 +3006,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
 {
        struct nameidata nd;
        struct file *file;
+       struct filename filename = { .name = name };
 
        nd.root.mnt = mnt;
        nd.root.dentry = dentry;
@@ -2986,20 +3016,30 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
        if (dentry->d_inode->i_op->follow_link && op->intent & LOOKUP_OPEN)
                return ERR_PTR(-ELOOP);
 
-       file = path_openat(-1, name, &nd, op, flags | LOOKUP_RCU);
+       file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_RCU);
        if (unlikely(file == ERR_PTR(-ECHILD)))
-               file = path_openat(-1, name, &nd, op, flags);
+               file = path_openat(-1, &filename, &nd, op, flags);
        if (unlikely(file == ERR_PTR(-ESTALE)))
-               file = path_openat(-1, name, &nd, op, flags | LOOKUP_REVAL);
+               file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_REVAL);
        return file;
 }
 
-struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path, int is_dir)
+struct dentry *kern_path_create(int dfd, const char *pathname,
+                               struct path *path, unsigned int lookup_flags)
 {
        struct dentry *dentry = ERR_PTR(-EEXIST);
        struct nameidata nd;
        int err2;
-       int error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd);
+       int error;
+       bool is_dir = (lookup_flags & LOOKUP_DIRECTORY);
+
+       /*
+        * Note that only LOOKUP_REVAL and LOOKUP_DIRECTORY matter here. Any
+        * other flags passed in are ignored!
+        */
+       lookup_flags &= LOOKUP_REVAL;
+
+       error = do_path_lookup(dfd, pathname, LOOKUP_PARENT|lookup_flags, &nd);
        if (error)
                return ERR_PTR(error);
 
@@ -3063,13 +3103,14 @@ void done_path_create(struct path *path, struct dentry *dentry)
 }
 EXPORT_SYMBOL(done_path_create);
 
-struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir)
+struct dentry *user_path_create(int dfd, const char __user *pathname,
+                               struct path *path, unsigned int lookup_flags)
 {
        struct filename *tmp = getname(pathname);
        struct dentry *res;
        if (IS_ERR(tmp))
                return ERR_CAST(tmp);
-       res = kern_path_create(dfd, tmp->name, path, is_dir);
+       res = kern_path_create(dfd, tmp->name, path, lookup_flags);
        putname(tmp);
        return res;
 }
@@ -3125,12 +3166,13 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
        struct dentry *dentry;
        struct path path;
        int error;
+       unsigned int lookup_flags = 0;
 
        error = may_mknod(mode);
        if (error)
                return error;
-
-       dentry = user_path_create(dfd, filename, &path, 0);
+retry:
+       dentry = user_path_create(dfd, filename, &path, lookup_flags);
        if (IS_ERR(dentry))
                return PTR_ERR(dentry);
 
@@ -3153,6 +3195,10 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
        }
 out:
        done_path_create(&path, dentry);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
        return error;
 }
 
@@ -3191,8 +3237,10 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
        struct dentry *dentry;
        struct path path;
        int error;
+       unsigned int lookup_flags = LOOKUP_DIRECTORY;
 
-       dentry = user_path_create(dfd, pathname, &path, 1);
+retry:
+       dentry = user_path_create(dfd, pathname, &path, lookup_flags);
        if (IS_ERR(dentry))
                return PTR_ERR(dentry);
 
@@ -3202,6 +3250,10 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
        if (!error)
                error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
        done_path_create(&path, dentry);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
        return error;
 }
 
@@ -3277,8 +3329,9 @@ static long do_rmdir(int dfd, const char __user *pathname)
        struct filename *name;
        struct dentry *dentry;
        struct nameidata nd;
-
-       name = user_path_parent(dfd, pathname, &nd);
+       unsigned int lookup_flags = 0;
+retry:
+       name = user_path_parent(dfd, pathname, &nd, lookup_flags);
        if (IS_ERR(name))
                return PTR_ERR(name);
 
@@ -3320,6 +3373,10 @@ exit2:
 exit1:
        path_put(&nd.path);
        putname(name);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
        return error;
 }
 
@@ -3373,8 +3430,9 @@ static long do_unlinkat(int dfd, const char __user *pathname)
        struct dentry *dentry;
        struct nameidata nd;
        struct inode *inode = NULL;
-
-       name = user_path_parent(dfd, pathname, &nd);
+       unsigned int lookup_flags = 0;
+retry:
+       name = user_path_parent(dfd, pathname, &nd, lookup_flags);
        if (IS_ERR(name))
                return PTR_ERR(name);
 
@@ -3412,6 +3470,11 @@ exit2:
 exit1:
        path_put(&nd.path);
        putname(name);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               inode = NULL;
+               goto retry;
+       }
        return error;
 
 slashes:
@@ -3463,12 +3526,13 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
        struct filename *from;
        struct dentry *dentry;
        struct path path;
+       unsigned int lookup_flags = 0;
 
        from = getname(oldname);
        if (IS_ERR(from))
                return PTR_ERR(from);
-
-       dentry = user_path_create(newdfd, newname, &path, 0);
+retry:
+       dentry = user_path_create(newdfd, newname, &path, lookup_flags);
        error = PTR_ERR(dentry);
        if (IS_ERR(dentry))
                goto out_putname;
@@ -3477,6 +3541,10 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
        if (!error)
                error = vfs_symlink(path.dentry->d_inode, dentry, from->name);
        done_path_create(&path, dentry);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
 out_putname:
        putname(from);
        return error;
@@ -3563,12 +3631,13 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
 
        if (flags & AT_SYMLINK_FOLLOW)
                how |= LOOKUP_FOLLOW;
-
+retry:
        error = user_path_at(olddfd, oldname, how, &old_path);
        if (error)
                return error;
 
-       new_dentry = user_path_create(newdfd, newname, &new_path, 0);
+       new_dentry = user_path_create(newdfd, newname, &new_path,
+                                       (how & LOOKUP_REVAL));
        error = PTR_ERR(new_dentry);
        if (IS_ERR(new_dentry))
                goto out;
@@ -3585,6 +3654,10 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
        error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry);
 out_dput:
        done_path_create(&new_path, new_dentry);
+       if (retry_estale(error, how)) {
+               how |= LOOKUP_REVAL;
+               goto retry;
+       }
 out:
        path_put(&old_path);
 
@@ -3757,15 +3830,17 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
        struct nameidata oldnd, newnd;
        struct filename *from;
        struct filename *to;
+       unsigned int lookup_flags = 0;
+       bool should_retry = false;
        int error;
-
-       from = user_path_parent(olddfd, oldname, &oldnd);
+retry:
+       from = user_path_parent(olddfd, oldname, &oldnd, lookup_flags);
        if (IS_ERR(from)) {
                error = PTR_ERR(from);
                goto exit;
        }
 
-       to = user_path_parent(newdfd, newname, &newnd);
+       to = user_path_parent(newdfd, newname, &newnd, lookup_flags);
        if (IS_ERR(to)) {
                error = PTR_ERR(to);
                goto exit1;
@@ -3837,11 +3912,18 @@ exit3:
        unlock_rename(new_dir, old_dir);
        mnt_drop_write(oldnd.path.mnt);
 exit2:
+       if (retry_estale(error, lookup_flags))
+               should_retry = true;
        path_put(&newnd.path);
        putname(to);
 exit1:
        path_put(&oldnd.path);
        putname(from);
+       if (should_retry) {
+               should_retry = false;
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
 exit:
        return error;
 }