Revert "input: touch: raydium: V61.7 code drop"
[linux-3.10.git] / fs / namei.c
index d4d15bb..cccaf77 100644 (file)
  * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
  * PATH_MAX includes the nul terminator --RR.
  */
-static char *getname_flags(const char __user *filename, int flags, int *empty)
+void final_putname(struct filename *name)
 {
-       char *result = __getname(), *err;
+       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;
        int len;
+       long max;
+       char *kname;
+
+       result = audit_reusename(filename);
+       if (result)
+               return result;
 
+       result = __getname();
        if (unlikely(!result))
                return ERR_PTR(-ENOMEM);
 
-       len = strncpy_from_user(result, filename, PATH_MAX);
-       err = ERR_PTR(len);
-       if (unlikely(len < 0))
+       /*
+        * First, try to embed the struct filename inside the names_cache
+        * allocation
+        */
+       kname = (char *)result + sizeof(*result);
+       result->name = kname;
+       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)) {
@@ -140,30 +192,32 @@ static char *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(result);
+       final_putname(result);
        return err;
 }
 
-char *getname(const char __user * filename)
+struct filename *
+getname(const char __user * filename)
 {
        return getname_flags(filename, 0, NULL);
 }
+EXPORT_SYMBOL(getname);
 
 #ifdef CONFIG_AUDITSYSCALL
-void putname(const char *name)
+void putname(struct filename *name)
 {
        if (unlikely(!audit_dummy_context()))
-               audit_putname(name);
-       else
-               __putname(name);
+               return audit_putname(name);
+       final_putname(name);
 }
-EXPORT_SYMBOL(putname);
 #endif
 
 static int check_acl(struct inode *inode, int mask)
@@ -352,6 +406,7 @@ int __inode_permission(struct inode *inode, int mask)
 /**
  * sb_permission - Check superblock-level permissions
  * @sb: Superblock of inode to check permission on
+ * @inode: Inode to check permission on
  * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
  *
  * Separate out file-system wide checks from inode-specific permission checks.
@@ -396,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);
@@ -409,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);
@@ -427,6 +482,18 @@ EXPORT_SYMBOL(path_put);
  * to restart the path walk from the beginning in ref-walk mode.
  */
 
+static inline void lock_rcu_walk(void)
+{
+       br_read_lock(&vfsmount_lock);
+       rcu_read_lock();
+}
+
+static inline void unlock_rcu_walk(void)
+{
+       rcu_read_unlock();
+       br_read_unlock(&vfsmount_lock);
+}
+
 /**
  * unlazy_walk - try to switch to ref-walk mode.
  * @nd: nameidata pathwalk data
@@ -480,8 +547,7 @@ static int unlazy_walk(struct nameidata *nd, struct dentry *dentry)
        }
        mntget(nd->path.mnt);
 
-       rcu_read_unlock();
-       br_read_unlock(&vfsmount_lock);
+       unlock_rcu_walk();
        nd->flags &= ~LOOKUP_RCU;
        return 0;
 
@@ -522,28 +588,22 @@ static int complete_walk(struct nameidata *nd)
                spin_lock(&dentry->d_lock);
                if (unlikely(!__d_rcu_to_refcount(dentry, nd->seq))) {
                        spin_unlock(&dentry->d_lock);
-                       rcu_read_unlock();
-                       br_read_unlock(&vfsmount_lock);
+                       unlock_rcu_walk();
                        return -ECHILD;
                }
                BUG_ON(nd->inode != dentry->d_inode);
                spin_unlock(&dentry->d_lock);
                mntget(nd->path.mnt);
-               rcu_read_unlock();
-               br_read_unlock(&vfsmount_lock);
+               unlock_rcu_walk();
        }
 
        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;
 
@@ -629,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)
@@ -641,6 +699,122 @@ static inline void put_link(struct nameidata *nd, struct path *link, void *cooki
        path_put(link);
 }
 
+int sysctl_protected_symlinks __read_mostly = 0;
+int sysctl_protected_hardlinks __read_mostly = 0;
+
+/**
+ * may_follow_link - Check symlink following for unsafe situations
+ * @link: The path of the symlink
+ * @nd: nameidata pathwalk data
+ *
+ * In the case of the sysctl_protected_symlinks sysctl being enabled,
+ * CAP_DAC_OVERRIDE needs to be specifically ignored if the symlink is
+ * in a sticky world-writable directory. This is to protect privileged
+ * processes from failing races against path names that may change out
+ * from under them by way of other users creating malicious symlinks.
+ * It will permit symlinks to be followed only when outside a sticky
+ * world-writable directory, or when the uid of the symlink and follower
+ * match, or when the directory owner matches the symlink's owner.
+ *
+ * Returns 0 if following the symlink is allowed, -ve on error.
+ */
+static inline int may_follow_link(struct path *link, struct nameidata *nd)
+{
+       const struct inode *inode;
+       const struct inode *parent;
+
+       if (!sysctl_protected_symlinks)
+               return 0;
+
+       /* Allowed if owner and follower match. */
+       inode = link->dentry->d_inode;
+       if (uid_eq(current_cred()->fsuid, inode->i_uid))
+               return 0;
+
+       /* Allowed if parent directory not sticky and world-writable. */
+       parent = nd->path.dentry->d_inode;
+       if ((parent->i_mode & (S_ISVTX|S_IWOTH)) != (S_ISVTX|S_IWOTH))
+               return 0;
+
+       /* Allowed if parent directory and link owner match. */
+       if (uid_eq(parent->i_uid, inode->i_uid))
+               return 0;
+
+       audit_log_link_denied("follow_link", link);
+       path_put_conditional(link, nd);
+       path_put(&nd->path);
+       return -EACCES;
+}
+
+/**
+ * safe_hardlink_source - Check for safe hardlink conditions
+ * @inode: the source inode to hardlink from
+ *
+ * Return false if at least one of the following conditions:
+ *    - inode is not a regular file
+ *    - inode is setuid
+ *    - inode is setgid and group-exec
+ *    - access failure for read and write
+ *
+ * Otherwise returns true.
+ */
+static bool safe_hardlink_source(struct inode *inode)
+{
+       umode_t mode = inode->i_mode;
+
+       /* Special files should not get pinned to the filesystem. */
+       if (!S_ISREG(mode))
+               return false;
+
+       /* Setuid files should not get pinned to the filesystem. */
+       if (mode & S_ISUID)
+               return false;
+
+       /* Executable setgid files should not get pinned to the filesystem. */
+       if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
+               return false;
+
+       /* Hardlinking to unreadable or unwritable sources is dangerous. */
+       if (inode_permission(inode, MAY_READ | MAY_WRITE))
+               return false;
+
+       return true;
+}
+
+/**
+ * may_linkat - Check permissions for creating a hardlink
+ * @link: the source to hardlink from
+ *
+ * Block hardlink when all of:
+ *  - sysctl_protected_hardlinks enabled
+ *  - fsuid does not match inode
+ *  - hardlink source is unsafe (see safe_hardlink_source() above)
+ *  - not CAP_FOWNER
+ *
+ * Returns 0 if successful, -ve on error.
+ */
+static int may_linkat(struct path *link)
+{
+       const struct cred *cred;
+       struct inode *inode;
+
+       if (!sysctl_protected_hardlinks)
+               return 0;
+
+       cred = current_cred();
+       inode = link->dentry->d_inode;
+
+       /* Source inode owner (or CAP_FOWNER) can hardlink all they like,
+        * otherwise, it must be a safe source.
+        */
+       if (uid_eq(cred->fsuid, inode->i_uid) || safe_hardlink_source(inode) ||
+           capable(CAP_FOWNER))
+               return 0;
+
+       audit_log_link_denied("linkat", link);
+       return -EPERM;
+}
+
 static __always_inline int
 follow_link(struct path *link, struct nameidata *nd, void **p)
 {
@@ -684,6 +858,7 @@ follow_link(struct path *link, struct nameidata *nd, void **p)
        return error;
 
 out_put_nd_path:
+       *p = NULL;
        path_put(&nd->path);
        path_put(link);
        return error;
@@ -985,8 +1160,7 @@ failed:
        nd->flags &= ~LOOKUP_RCU;
        if (!(nd->flags & LOOKUP_ROOT))
                nd->root.mnt = NULL;
-       rcu_read_unlock();
-       br_read_unlock(&vfsmount_lock);
+       unlock_rcu_walk();
        return -ECHILD;
 }
 
@@ -1095,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) {
@@ -1164,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;
@@ -1180,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;
 
@@ -1203,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)) {
@@ -1224,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)) {
@@ -1265,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;
@@ -1275,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);
@@ -1323,8 +1487,7 @@ static void terminate_walk(struct nameidata *nd)
                nd->flags &= ~LOOKUP_RCU;
                if (!(nd->flags & LOOKUP_ROOT))
                        nd->root.mnt = NULL;
-               rcu_read_unlock();
-               br_read_unlock(&vfsmount_lock);
+               unlock_rcu_walk();
        }
 }
 
@@ -1349,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;
@@ -1358,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;
 
@@ -1424,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);
 
@@ -1632,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.
@@ -1642,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;
 
@@ -1654,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;
@@ -1673,8 +1833,6 @@ static int path_init(int dfd, const char *name, unsigned int flags,
                     struct nameidata *nd, struct file **fp)
 {
        int retval = 0;
-       int fput_needed;
-       struct file *file;
 
        nd->last_type = LAST_ROOT; /* if there are only slashes... */
        nd->flags = flags | LOOKUP_JUMPED;
@@ -1682,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)
@@ -1691,8 +1849,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
                nd->path = nd->root;
                nd->inode = inode;
                if (flags & LOOKUP_RCU) {
-                       br_read_lock(&vfsmount_lock);
-                       rcu_read_lock();
+                       lock_rcu_walk();
                        nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
                } else {
                        path_get(&nd->path);
@@ -1704,8 +1861,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
 
        if (*name=='/') {
                if (flags & LOOKUP_RCU) {
-                       br_read_lock(&vfsmount_lock);
-                       rcu_read_lock();
+                       lock_rcu_walk();
                        set_root_rcu(nd);
                } else {
                        set_root(nd);
@@ -1717,8 +1873,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
                        struct fs_struct *fs = current->fs;
                        unsigned seq;
 
-                       br_read_lock(&vfsmount_lock);
-                       rcu_read_lock();
+                       lock_rcu_walk();
 
                        do {
                                seq = read_seqcount_begin(&fs->seq);
@@ -1729,45 +1884,36 @@ 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;
 
-               file = fget_raw_light(dfd, &fput_needed);
-               retval = -EBADF;
-               if (!file)
-                       goto out_fail;
+               if (!f.file)
+                       return -EBADF;
 
-               dentry = file->f_path.dentry;
+               dentry = f.file->f_path.dentry;
 
                if (*name) {
-                       retval = -ENOTDIR;
-                       if (!S_ISDIR(dentry->d_inode->i_mode))
-                               goto fput_fail;
-
-                       retval = inode_permission(dentry->d_inode, MAY_EXEC);
-                       if (retval)
-                               goto fput_fail;
+                       if (!can_lookup(dentry->d_inode)) {
+                               fdput(f);
+                               return -ENOTDIR;
+                       }
                }
 
-               nd->path = file->f_path;
+               nd->path = f.file->f_path;
                if (flags & LOOKUP_RCU) {
-                       if (fput_needed)
-                               *fp = file;
+                       if (f.need_put)
+                               *fp = f.file;
                        nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
-                       br_read_lock(&vfsmount_lock);
-                       rcu_read_lock();
+                       lock_rcu_walk();
                } else {
-                       path_get(&file->f_path);
-                       fput_light(file, fput_needed);
+                       path_get(&nd->path);
+                       fdput(f);
                }
        }
 
        nd->inode = nd->path.dentry->d_inode;
        return 0;
-
-fput_fail:
-       fput_light(file, fput_needed);
-out_fail:
-       return retval;
 }
 
 static inline int lookup_last(struct nameidata *nd, struct path *path)
@@ -1776,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. */
@@ -1815,6 +1960,9 @@ static int path_lookupat(int dfd, const char *name,
                while (err > 0) {
                        void *cookie;
                        struct path link = path;
+                       err = may_follow_link(&link, nd);
+                       if (unlikely(err))
+                               break;
                        nd->flags |= LOOKUP_PARENT;
                        err = follow_link(&link, nd, &cookie);
                        if (err)
@@ -1828,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;
                }
@@ -1844,24 +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)) {
-               if (unlikely(!audit_dummy_context())) {
-                       if (nd->path.dentry && nd->inode)
-                               audit_inode(name, nd->path.dentry);
-               }
-       }
+       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)
 {
@@ -1953,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')
@@ -1979,13 +2137,13 @@ int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
                 struct path *path, int *empty)
 {
        struct nameidata nd;
-       char *tmp = getname_flags(name, flags, empty);
+       struct filename *tmp = getname_flags(name, flags, empty);
        int err = PTR_ERR(tmp);
        if (!IS_ERR(tmp)) {
 
                BUG_ON(flags & LOOKUP_PARENT);
 
-               err = do_path_lookup(dfd, tmp, flags, &nd);
+               err = filename_lookup(dfd, tmp, flags, &nd);
                putname(tmp);
                if (!err)
                        *path = nd.path;
@@ -1999,22 +2157,32 @@ int user_path_at(int dfd, const char __user *name, unsigned flags,
        return user_path_at_empty(dfd, name, flags, path, NULL);
 }
 
-static int user_path_parent(int dfd, const char __user *path,
-                       struct nameidata *nd, char **name)
+/*
+ * 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,
+                unsigned int flags)
 {
-       char *s = getname(path);
+       struct filename *s = getname(path);
        int error;
 
+       /* only LOOKUP_REVAL is allowed in extra flags */
+       flags &= LOOKUP_REVAL;
+
        if (IS_ERR(s))
-               return PTR_ERR(s);
+               return s;
 
-       error = do_path_lookup(dfd, s, LOOKUP_PARENT, nd);
-       if (error)
+       error = filename_lookup(dfd, s, flags | LOOKUP_PARENT, nd);
+       if (error) {
                putname(s);
-       else
-               *name = s;
+               return ERR_PTR(error);
+       }
 
-       return error;
+       return s;
 }
 
 /*
@@ -2061,7 +2229,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
                return -ENOENT;
 
        BUG_ON(victim->d_parent->d_inode != dir);
-       audit_inode_child(victim, dir);
+       audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
 
        error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
        if (error)
@@ -2095,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))
@@ -2274,7 +2443,7 @@ static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode)
 static int atomic_open(struct nameidata *nd, struct dentry *dentry,
                        struct path *path, struct file *file,
                        const struct open_flags *op,
-                       bool *want_write, bool need_lookup,
+                       bool got_write, bool need_lookup,
                        int *opened)
 {
        struct inode *dir =  nd->path.dentry->d_inode;
@@ -2293,11 +2462,11 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
                goto out;
        }
 
-       mode = op->mode & S_IALLUGO;
+       mode = op->mode;
        if ((open_flag & O_CREAT) && !IS_POSIXACL(dir))
                mode &= ~current_umask();
 
-       if (open_flag & O_EXCL) {
+       if ((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT)) {
                open_flag &= ~O_TRUNC;
                *opened |= FILE_CREATED;
        }
@@ -2311,12 +2480,9 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
         * Another problem is returing the "right" error value (e.g. for an
         * O_EXCL open we want to return EEXIST not EROFS).
         */
-       if ((open_flag & (O_CREAT | O_TRUNC)) ||
-           (open_flag & O_ACCMODE) != O_RDONLY) {
-               error = mnt_want_write(nd->path.mnt);
-               if (!error) {
-                       *want_write = true;
-               } else if (!(open_flag & O_CREAT)) {
+       if (((open_flag & (O_CREAT | O_TRUNC)) ||
+           (open_flag & O_ACCMODE) != O_RDONLY) && unlikely(!got_write)) {
+               if (!(open_flag & O_CREAT)) {
                        /*
                         * No O_CREATE -> atomicity not a requirement -> fall
                         * back to lookup + open
@@ -2324,17 +2490,17 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
                        goto no_open;
                } else if (open_flag & (O_EXCL | O_TRUNC)) {
                        /* Fall back and fail with the right error */
-                       create_error = error;
+                       create_error = -EROFS;
                        goto no_open;
                } else {
                        /* No side effects, safe to clear O_CREAT */
-                       create_error = error;
+                       create_error = -EROFS;
                        open_flag &= ~O_CREAT;
                }
        }
 
        if (open_flag & O_CREAT) {
-               error = may_o_create(&nd->path, dentry, op->mode);
+               error = may_o_create(&nd->path, dentry, mode);
                if (error) {
                        create_error = error;
                        if (open_flag & O_EXCL)
@@ -2371,6 +2537,10 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
                        dput(dentry);
                        dentry = file->f_path.dentry;
                }
+               if (create_error && dentry->d_inode == NULL) {
+                       error = create_error;
+                       goto out;
+               }
                goto looked_up;
        }
 
@@ -2435,7 +2605,7 @@ looked_up:
 static int lookup_open(struct nameidata *nd, struct path *path,
                        struct file *file,
                        const struct open_flags *op,
-                       bool *want_write, int *opened)
+                       bool got_write, int *opened)
 {
        struct dentry *dir = nd->path.dentry;
        struct inode *dir_inode = dir->d_inode;
@@ -2453,7 +2623,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
                goto out_no_open;
 
        if ((nd->flags & LOOKUP_OPEN) && dir_inode->i_op->atomic_open) {
-               return atomic_open(nd, dentry, path, file, op, want_write,
+               return atomic_open(nd, dentry, path, file, op, got_write,
                                   need_lookup, opened);
        }
 
@@ -2477,10 +2647,10 @@ static int lookup_open(struct nameidata *nd, struct path *path,
                 * a permanent write count is taken through
                 * the 'struct file' in finish_open().
                 */
-               error = mnt_want_write(nd->path.mnt);
-               if (error)
+               if (!got_write) {
+                       error = -EROFS;
                        goto out_dput;
-               *want_write = true;
+               }
                *opened |= FILE_CREATED;
                error = security_path_mknod(&nd->path, dentry, mode, 0);
                if (error)
@@ -2505,12 +2675,12 @@ 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;
        bool will_truncate = (open_flag & O_TRUNC) != 0;
-       bool want_write = false;
+       bool got_write = false;
        int acc_mode = op->acc_mode;
        struct inode *inode;
        bool symlink_ok = false;
@@ -2532,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);
+               audit_inode(name, nd->path.dentry, 0);
                if (open_flag & O_CREAT) {
                        error = -EISDIR;
                        goto out;
@@ -2542,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);
+               audit_inode(name, dir, 0);
                goto finish_open;
        }
 
@@ -2552,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;
 
@@ -2571,7 +2741,7 @@ static int do_last(struct nameidata *nd, struct path *path,
                if (error)
                        return error;
 
-               audit_inode(pathname, dir);
+               audit_inode(name, dir, LOOKUP_PARENT);
                error = -EISDIR;
                /* trailing slashes? */
                if (nd->last.name[nd->last.len])
@@ -2579,8 +2749,18 @@ static int do_last(struct nameidata *nd, struct path *path,
        }
 
 retry_lookup:
+       if (op->open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) {
+               error = mnt_want_write(nd->path.mnt);
+               if (!error)
+                       got_write = true;
+               /*
+                * do _not_ fail yet - we might not need that or fail with
+                * a different error; let lookup_open() decide; we'll be
+                * dropping this one anyway.
+                */
+       }
        mutex_lock(&dir->d_inode->i_mutex);
-       error = lookup_open(nd, path, file, op, &want_write, opened);
+       error = lookup_open(nd, path, file, op, got_write, opened);
        mutex_unlock(&dir->d_inode->i_mutex);
 
        if (error <= 0) {
@@ -2588,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);
+               audit_inode(name, file->f_path.dentry, 0);
                goto opened;
        }
 
@@ -2605,22 +2785,23 @@ retry_lookup:
        }
 
        /*
-        * It already exists.
+        * create/update audit record if it already exists.
         */
-       audit_inode(pathname, path->dentry);
+       if (path->dentry->d_inode)
+               audit_inode(name, path->dentry, 0);
 
        /*
         * If atomic_open() acquired write access it is dropped now due to
         * possible mount and symlink following (this might be optimized away if
         * necessary...)
         */
-       if (want_write) {
+       if (got_write) {
                mnt_drop_write(nd->path.mnt);
-               want_write = false;
+               got_write = false;
        }
 
        error = -EEXIST;
-       if (open_flag & O_EXCL)
+       if ((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT))
                goto exit_dput;
 
        error = follow_managed(path, nd->flags);
@@ -2670,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);
+       audit_inode(name, nd->path.dentry, 0);
 finish_open:
        if (!S_ISREG(nd->inode->i_mode))
                will_truncate = false;
@@ -2681,7 +2862,7 @@ finish_open:
                error = mnt_want_write(nd->path.mnt);
                if (error)
                        goto out;
-               want_write = true;
+               got_write = true;
        }
 finish_open_created:
        error = may_open(&nd->path, acc_mode, open_flag);
@@ -2708,7 +2889,7 @@ opened:
                        goto exit_fput;
        }
 out:
-       if (want_write)
+       if (got_write)
                mnt_drop_write(nd->path.mnt);
        path_put(&save_parent);
        terminate_walk(nd);
@@ -2732,15 +2913,15 @@ stale_open:
        nd->inode = dir->d_inode;
        save_parent.mnt = NULL;
        save_parent.dentry = NULL;
-       if (want_write) {
+       if (got_write) {
                mnt_drop_write(nd->path.mnt);
-               want_write = false;
+               got_write = false;
        }
        retried = true;
        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;
@@ -2750,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;
 
@@ -2774,6 +2955,9 @@ static struct file *path_openat(int dfd, const char *pathname,
                        error = -ELOOP;
                        break;
                }
+               error = may_follow_link(&link, nd);
+               if (unlikely(error))
+                       break;
                nd->flags |= LOOKUP_PARENT;
                nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
                error = follow_link(&link, nd, &cookie);
@@ -2803,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;
@@ -2822,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;
@@ -2831,19 +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 error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd);
+       int err2;
+       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);
 
@@ -2856,16 +3052,19 @@ struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path
        nd.flags &= ~LOOKUP_PARENT;
        nd.flags |= LOOKUP_CREATE | LOOKUP_EXCL;
 
+       /* don't fail immediately if it's r/o, at least try to report other errors */
+       err2 = mnt_want_write(nd.path.mnt);
        /*
         * Do the final lookup.
         */
        mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
        dentry = lookup_hash(&nd);
        if (IS_ERR(dentry))
-               goto fail;
+               goto unlock;
 
+       error = -EEXIST;
        if (dentry->d_inode)
-               goto eexist;
+               goto fail;
        /*
         * Special case - lookup gave negative, but... we had foo/bar/
         * From the vfs_mknod() POV we just have a negative dentry -
@@ -2873,30 +3072,45 @@ struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path
         * been asking for (non-existent) directory. -ENOENT for you.
         */
        if (unlikely(!is_dir && nd.last.name[nd.last.len])) {
-               dput(dentry);
-               dentry = ERR_PTR(-ENOENT);
+               error = -ENOENT;
+               goto fail;
+       }
+       if (unlikely(err2)) {
+               error = err2;
                goto fail;
        }
        *path = nd.path;
        return dentry;
-eexist:
-       dput(dentry);
-       dentry = ERR_PTR(-EEXIST);
 fail:
+       dput(dentry);
+       dentry = ERR_PTR(error);
+unlock:
        mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+       if (!err2)
+               mnt_drop_write(nd.path.mnt);
 out:
        path_put(&nd.path);
        return dentry;
 }
 EXPORT_SYMBOL(kern_path_create);
 
-struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir)
+void done_path_create(struct path *path, struct dentry *dentry)
+{
+       dput(dentry);
+       mutex_unlock(&path->dentry->d_inode->i_mutex);
+       mnt_drop_write(path->mnt);
+       path_put(path);
+}
+EXPORT_SYMBOL(done_path_create);
+
+struct dentry *user_path_create(int dfd, const char __user *pathname,
+                               struct path *path, unsigned int lookup_flags)
 {
-       char *tmp = getname(pathname);
+       struct filename *tmp = getname(pathname);
        struct dentry *res;
        if (IS_ERR(tmp))
                return ERR_CAST(tmp);
-       res = kern_path_create(dfd, tmp, path, is_dir);
+       res = kern_path_create(dfd, tmp->name, path, lookup_flags);
        putname(tmp);
        return res;
 }
@@ -2952,25 +3166,21 @@ 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;
 
-       if (S_ISDIR(mode))
-               return -EPERM;
-
-       dentry = user_path_create(dfd, filename, &path, 0);
+       error = may_mknod(mode);
+       if (error)
+               return error;
+retry:
+       dentry = user_path_create(dfd, filename, &path, lookup_flags);
        if (IS_ERR(dentry))
                return PTR_ERR(dentry);
 
        if (!IS_POSIXACL(path.dentry->d_inode))
                mode &= ~current_umask();
-       error = may_mknod(mode);
-       if (error)
-               goto out_dput;
-       error = mnt_want_write(path.mnt);
-       if (error)
-               goto out_dput;
        error = security_path_mknod(&path, dentry, mode, dev);
        if (error)
-               goto out_drop_write;
+               goto out;
        switch (mode & S_IFMT) {
                case 0: case S_IFREG:
                        error = vfs_create(path.dentry->d_inode,dentry,mode,true);
@@ -2983,13 +3193,12 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
                        error = vfs_mknod(path.dentry->d_inode,dentry,mode,0);
                        break;
        }
-out_drop_write:
-       mnt_drop_write(path.mnt);
-out_dput:
-       dput(dentry);
-       mutex_unlock(&path.dentry->d_inode->i_mutex);
-       path_put(&path);
-
+out:
+       done_path_create(&path, dentry);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
        return error;
 }
 
@@ -3028,26 +3237,23 @@ 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);
 
        if (!IS_POSIXACL(path.dentry->d_inode))
                mode &= ~current_umask();
-       error = mnt_want_write(path.mnt);
-       if (error)
-               goto out_dput;
        error = security_path_mkdir(&path, dentry, mode);
-       if (error)
-               goto out_drop_write;
-       error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
-out_drop_write:
-       mnt_drop_write(path.mnt);
-out_dput:
-       dput(dentry);
-       mutex_unlock(&path.dentry->d_inode->i_mutex);
-       path_put(&path);
+       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;
 }
 
@@ -3120,13 +3326,14 @@ out:
 static long do_rmdir(int dfd, const char __user *pathname)
 {
        int error = 0;
-       char * name;
+       struct filename *name;
        struct dentry *dentry;
        struct nameidata nd;
-
-       error = user_path_parent(dfd, pathname, &nd, &name);
-       if (error)
-               return error;
+       unsigned int lookup_flags = 0;
+retry:
+       name = user_path_parent(dfd, pathname, &nd, lookup_flags);
+       if (IS_ERR(name))
+               return PTR_ERR(name);
 
        switch(nd.last_type) {
        case LAST_DOTDOT:
@@ -3141,6 +3348,9 @@ static long do_rmdir(int dfd, const char __user *pathname)
        }
 
        nd.flags &= ~LOOKUP_PARENT;
+       error = mnt_want_write(nd.path.mnt);
+       if (error)
+               goto exit1;
 
        mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
        dentry = lookup_hash(&nd);
@@ -3151,22 +3361,22 @@ static long do_rmdir(int dfd, const char __user *pathname)
                error = -ENOENT;
                goto exit3;
        }
-       error = mnt_want_write(nd.path.mnt);
-       if (error)
-               goto exit3;
        error = security_path_rmdir(&nd.path, dentry);
        if (error)
-               goto exit4;
+               goto exit3;
        error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
-exit4:
-       mnt_drop_write(nd.path.mnt);
 exit3:
        dput(dentry);
 exit2:
        mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+       mnt_drop_write(nd.path.mnt);
 exit1:
        path_put(&nd.path);
        putname(name);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
        return error;
 }
 
@@ -3216,20 +3426,24 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
 static long do_unlinkat(int dfd, const char __user *pathname)
 {
        int error;
-       char *name;
+       struct filename *name;
        struct dentry *dentry;
        struct nameidata nd;
        struct inode *inode = NULL;
-
-       error = user_path_parent(dfd, pathname, &nd, &name);
-       if (error)
-               return error;
+       unsigned int lookup_flags = 0;
+retry:
+       name = user_path_parent(dfd, pathname, &nd, lookup_flags);
+       if (IS_ERR(name))
+               return PTR_ERR(name);
 
        error = -EISDIR;
        if (nd.last_type != LAST_NORM)
                goto exit1;
 
        nd.flags &= ~LOOKUP_PARENT;
+       error = mnt_want_write(nd.path.mnt);
+       if (error)
+               goto exit1;
 
        mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
        dentry = lookup_hash(&nd);
@@ -3242,24 +3456,25 @@ static long do_unlinkat(int dfd, const char __user *pathname)
                if (!inode)
                        goto slashes;
                ihold(inode);
-               error = mnt_want_write(nd.path.mnt);
-               if (error)
-                       goto exit2;
                error = security_path_unlink(&nd.path, dentry);
                if (error)
-                       goto exit3;
+                       goto exit2;
                error = vfs_unlink(nd.path.dentry->d_inode, dentry);
-exit3:
-               mnt_drop_write(nd.path.mnt);
-       exit2:
+exit2:
                dput(dentry);
        }
        mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
        if (inode)
                iput(inode);    /* truncate the inode here */
+       mnt_drop_write(nd.path.mnt);
 exit1:
        path_put(&nd.path);
        putname(name);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               inode = NULL;
+               goto retry;
+       }
        return error;
 
 slashes:
@@ -3308,32 +3523,28 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
                int, newdfd, const char __user *, newname)
 {
        int error;
-       char *from;
+       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;
 
-       error = mnt_want_write(path.mnt);
-       if (error)
-               goto out_dput;
-       error = security_path_symlink(&path, dentry, from);
-       if (error)
-               goto out_drop_write;
-       error = vfs_symlink(path.dentry->d_inode, dentry, from);
-out_drop_write:
-       mnt_drop_write(path.mnt);
-out_dput:
-       dput(dentry);
-       mutex_unlock(&path.dentry->d_inode->i_mutex);
-       path_put(&path);
+       error = security_path_symlink(&path, dentry, from->name);
+       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;
@@ -3420,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;
@@ -3433,19 +3645,19 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
        error = -EXDEV;
        if (old_path.mnt != new_path.mnt)
                goto out_dput;
-       error = mnt_want_write(new_path.mnt);
-       if (error)
+       error = may_linkat(&old_path);
+       if (unlikely(error))
                goto out_dput;
        error = security_path_link(old_path.dentry, &new_path, new_dentry);
        if (error)
-               goto out_drop_write;
+               goto out_dput;
        error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry);
-out_drop_write:
-       mnt_drop_write(new_path.mnt);
 out_dput:
-       dput(new_dentry);
-       mutex_unlock(&new_path.dentry->d_inode->i_mutex);
-       path_put(&new_path);
+       done_path_create(&new_path, new_dentry);
+       if (retry_estale(error, how)) {
+               how |= LOOKUP_REVAL;
+               goto retry;
+       }
 out:
        path_put(&old_path);
 
@@ -3616,17 +3828,23 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
        struct dentry *old_dentry, *new_dentry;
        struct dentry *trap;
        struct nameidata oldnd, newnd;
-       char *from;
-       char *to;
+       struct filename *from;
+       struct filename *to;
+       unsigned int lookup_flags = 0;
+       bool should_retry = false;
        int error;
-
-       error = user_path_parent(olddfd, oldname, &oldnd, &from);
-       if (error)
+retry:
+       from = user_path_parent(olddfd, oldname, &oldnd, lookup_flags);
+       if (IS_ERR(from)) {
+               error = PTR_ERR(from);
                goto exit;
+       }
 
-       error = user_path_parent(newdfd, newname, &newnd, &to);
-       if (error)
+       to = user_path_parent(newdfd, newname, &newnd, lookup_flags);
+       if (IS_ERR(to)) {
+               error = PTR_ERR(to);
                goto exit1;
+       }
 
        error = -EXDEV;
        if (oldnd.path.mnt != newnd.path.mnt)
@@ -3641,6 +3859,10 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
        if (newnd.last_type != LAST_NORM)
                goto exit2;
 
+       error = mnt_want_write(oldnd.path.mnt);
+       if (error)
+               goto exit2;
+
        oldnd.flags &= ~LOOKUP_PARENT;
        newnd.flags &= ~LOOKUP_PARENT;
        newnd.flags |= LOOKUP_RENAME_TARGET;
@@ -3676,29 +3898,32 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
        if (new_dentry == trap)
                goto exit5;
 
-       error = mnt_want_write(oldnd.path.mnt);
-       if (error)
-               goto exit5;
        error = security_path_rename(&oldnd.path, old_dentry,
                                     &newnd.path, new_dentry);
        if (error)
-               goto exit6;
+               goto exit5;
        error = vfs_rename(old_dir->d_inode, old_dentry,
                                   new_dir->d_inode, new_dentry);
-exit6:
-       mnt_drop_write(oldnd.path.mnt);
 exit5:
        dput(new_dentry);
 exit4:
        dput(old_dentry);
 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;
 }
@@ -3849,8 +4074,7 @@ EXPORT_SYMBOL(user_path_at);
 EXPORT_SYMBOL(follow_down_one);
 EXPORT_SYMBOL(follow_down);
 EXPORT_SYMBOL(follow_up);
-EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
-EXPORT_SYMBOL(getname);
+EXPORT_SYMBOL(get_write_access); /* nfsd */
 EXPORT_SYMBOL(lock_rename);
 EXPORT_SYMBOL(lookup_one_len);
 EXPORT_SYMBOL(page_follow_link_light);