Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / fs / namei.c
index c5c3826..d1ebe96 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/namei.h>
 #include <linux/fcntl.h>
 #include <linux/device_cgroup.h>
 #include <linux/fs_struct.h>
+#include <linux/posix_acl.h>
 #include <asm/uaccess.h>
 
 #include "internal.h"
+#include "mount.h"
 
 /* [Feb-1997 T. Schoebel-Theuer]
  * Fundamental changes in the pathname lookup mechanisms (namei)
@@ -136,21 +138,21 @@ static int do_getname(const char __user *filename, char *page)
        return retval;
 }
 
-static char *getname_flags(const char __user * filename, int flags)
+static char *getname_flags(const char __user *filename, int flags, int *empty)
 {
-       char *tmp, *result;
+       char *result = __getname();
+       int retval;
 
-       result = ERR_PTR(-ENOMEM);
-       tmp = __getname();
-       if (tmp)  {
-               int retval = do_getname(filename, tmp);
+       if (!result)
+               return ERR_PTR(-ENOMEM);
 
-               result = tmp;
-               if (retval < 0) {
-                       if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) {
-                               __putname(tmp);
-                               result = ERR_PTR(retval);
-                       }
+       retval = do_getname(filename, result);
+       if (retval < 0) {
+               if (retval == -ENOENT && empty)
+                       *empty = 1;
+               if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) {
+                       __putname(result);
+                       return ERR_PTR(retval);
                }
        }
        audit_getname(result);
@@ -159,7 +161,7 @@ static char *getname_flags(const char __user * filename, int flags)
 
 char *getname(const char __user * filename)
 {
-       return getname_flags(filename, 0);
+       return getname_flags(filename, 0, NULL);
 }
 
 #ifdef CONFIG_AUDITSYSCALL
@@ -173,24 +175,66 @@ void putname(const char *name)
 EXPORT_SYMBOL(putname);
 #endif
 
+static int check_acl(struct inode *inode, int mask)
+{
+#ifdef CONFIG_FS_POSIX_ACL
+       struct posix_acl *acl;
+
+       if (mask & MAY_NOT_BLOCK) {
+               acl = get_cached_acl_rcu(inode, ACL_TYPE_ACCESS);
+               if (!acl)
+                       return -EAGAIN;
+               /* no ->get_acl() calls in RCU mode... */
+               if (acl == ACL_NOT_CACHED)
+                       return -ECHILD;
+               return posix_acl_permission(inode, acl, mask & ~MAY_NOT_BLOCK);
+       }
+
+       acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
+
+       /*
+        * A filesystem can force a ACL callback by just never filling the
+        * ACL cache. But normally you'd fill the cache either at inode
+        * instantiation time, or on the first ->get_acl call.
+        *
+        * If the filesystem doesn't have a get_acl() function at all, we'll
+        * just create the negative cache entry.
+        */
+       if (acl == ACL_NOT_CACHED) {
+               if (inode->i_op->get_acl) {
+                       acl = inode->i_op->get_acl(inode, ACL_TYPE_ACCESS);
+                       if (IS_ERR(acl))
+                               return PTR_ERR(acl);
+               } else {
+                       set_cached_acl(inode, ACL_TYPE_ACCESS, NULL);
+                       return -EAGAIN;
+               }
+       }
+
+       if (acl) {
+               int error = posix_acl_permission(inode, acl, mask);
+               posix_acl_release(acl);
+               return error;
+       }
+#endif
+
+       return -EAGAIN;
+}
+
 /*
- * This does basic POSIX ACL permission checking
+ * This does the basic permission checking
  */
 static int acl_permission_check(struct inode *inode, int mask)
 {
-       int (*check_acl)(struct inode *inode, int mask);
        unsigned int mode = inode->i_mode;
 
-       mask &= MAY_READ | MAY_WRITE | MAY_EXEC | MAY_NOT_BLOCK;
-
        if (current_user_ns() != inode_userns(inode))
                goto other_perms;
 
-       if (current_fsuid() == inode->i_uid)
+       if (likely(current_fsuid() == inode->i_uid))
                mode >>= 6;
        else {
-               check_acl = inode->i_op->check_acl;
-               if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) {
+               if (IS_POSIXACL(inode) && (mode & S_IRWXG)) {
                        int error = check_acl(inode, mask);
                        if (error != -EAGAIN)
                                return error;
@@ -212,8 +256,7 @@ other_perms:
 /**
  * generic_permission -  check for access rights on a Posix-like filesystem
  * @inode:     inode to check access rights for
- * @mask:      right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
- * @flags:     IPERM_FLAG_ flags.
+ * @mask:      right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC, ...)
  *
  * Used to check for read/write/execute permissions on a file.
  * We use "fsuid" for this, letting us set arbitrary permissions
@@ -229,18 +272,27 @@ int generic_permission(struct inode *inode, int mask)
        int ret;
 
        /*
-        * Do the basic POSIX ACL permission checks.
+        * Do the basic permission checks.
         */
        ret = acl_permission_check(inode, mask);
        if (ret != -EACCES)
                return ret;
 
+       if (S_ISDIR(inode->i_mode)) {
+               /* DACs are overridable for directories */
+               if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE))
+                       return 0;
+               if (!(mask & MAY_WRITE))
+                       if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH))
+                               return 0;
+               return -EACCES;
+       }
        /*
         * Read/write DACs are always overridable.
-        * Executable DACs are overridable for all directories and
-        * for non-directories that have least one exec bit set.
+        * Executable DACs are overridable when there is
+        * at least one exec bit set.
         */
-       if (!(mask & MAY_EXEC) || execute_ok(inode))
+       if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO))
                if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE))
                        return 0;
 
@@ -248,28 +300,50 @@ int generic_permission(struct inode *inode, int mask)
         * Searching includes executable on directories, else just read.
         */
        mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
-       if (mask == MAY_READ || (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE)))
+       if (mask == MAY_READ)
                if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH))
                        return 0;
 
        return -EACCES;
 }
 
+/*
+ * We _really_ want to just do "generic_permission()" without
+ * even looking at the inode->i_op values. So we keep a cache
+ * flag in inode->i_opflags, that says "this has not special
+ * permission function, use the fast case".
+ */
+static inline int do_inode_permission(struct inode *inode, int mask)
+{
+       if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) {
+               if (likely(inode->i_op->permission))
+                       return inode->i_op->permission(inode, mask);
+
+               /* This gets set once for the inode lifetime */
+               spin_lock(&inode->i_lock);
+               inode->i_opflags |= IOP_FASTPERM;
+               spin_unlock(&inode->i_lock);
+       }
+       return generic_permission(inode, mask);
+}
+
 /**
  * inode_permission  -  check for access rights to a given inode
  * @inode:     inode to check permission on
- * @mask:      right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
+ * @mask:      right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC, ...)
  *
  * Used to check for read/write/execute permissions on an inode.
  * We use "fsuid" for this, letting us set arbitrary permissions
  * for filesystem access without changing the "normal" uids which
  * are used for other things.
+ *
+ * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask.
  */
 int inode_permission(struct inode *inode, int mask)
 {
        int retval;
 
-       if (mask & MAY_WRITE) {
+       if (unlikely(mask & MAY_WRITE)) {
                umode_t mode = inode->i_mode;
 
                /*
@@ -286,11 +360,7 @@ int inode_permission(struct inode *inode, int mask)
                        return -EACCES;
        }
 
-       if (inode->i_op->permission)
-               retval = inode->i_op->permission(inode, mask);
-       else
-               retval = generic_permission(inode, mask);
-
+       retval = do_inode_permission(inode, mask);
        if (retval)
                return retval;
 
@@ -302,46 +372,6 @@ int inode_permission(struct inode *inode, int mask)
 }
 
 /**
- * exec_permission  -  check for right to do lookups in a given directory
- * @inode:     inode to check permission on
- * @flags:     IPERM_FLAG_ flags.
- *
- * Short-cut version of inode_permission(), for calling on directories
- * during pathname resolution.  Combines parts of inode_permission()
- * and generic_permission(), and tests ONLY for MAY_EXEC permission.
- *
- * If appropriate, check DAC only.  If not appropriate, or
- * short-cut DAC fails, then call ->permission() to do more
- * complete permission check.
- */
-static inline int exec_permission(struct inode *inode, unsigned int flags)
-{
-       int ret;
-       struct user_namespace *ns = inode_userns(inode);
-       int mask = MAY_EXEC;
-       if (flags & IPERM_FLAG_RCU)
-               mask |= MAY_NOT_BLOCK;
-
-       if (inode->i_op->permission) {
-               ret = inode->i_op->permission(inode, mask);
-               if (likely(!ret))
-                       goto ok;
-       } else {
-               ret = acl_permission_check(inode, mask);
-               if (likely(!ret))
-                       goto ok;
-               if (ret != -EACCES)
-                       return ret;
-               if (ns_capable(ns, CAP_DAC_OVERRIDE) ||
-                               ns_capable(ns, CAP_DAC_READ_SEARCH))
-                       goto ok;
-       }
-       return ret;
-ok:
-       return security_inode_exec_permission(inode, flags);
-}
-
-/**
  * path_get - get a reference to a path
  * @path: path to get the reference to
  *
@@ -467,28 +497,6 @@ static inline int d_revalidate(struct dentry *dentry, struct nameidata *nd)
        return dentry->d_op->d_revalidate(dentry, nd);
 }
 
-static struct dentry *
-do_revalidate(struct dentry *dentry, struct nameidata *nd)
-{
-       int status = d_revalidate(dentry, nd);
-       if (unlikely(status <= 0)) {
-               /*
-                * The dentry failed validation.
-                * If d_revalidate returned 0 attempt to invalidate
-                * the dentry otherwise d_revalidate is asking us
-                * to return a fail status.
-                */
-               if (status < 0) {
-                       dput(dentry);
-                       dentry = ERR_PTR(status);
-               } else if (!d_invalidate(dentry)) {
-                       dput(dentry);
-                       dentry = NULL;
-               }
-       }
-       return dentry;
-}
-
 /**
  * complete_walk - successful completion of path walk
  * @nd:  pointer nameidata
@@ -634,7 +642,7 @@ follow_link(struct path *link, struct nameidata *nd, void **p)
        cond_resched();
        current->total_link_count++;
 
-       touch_atime(link->mnt, dentry);
+       touch_atime(link);
        nd_set_link(nd, NULL);
 
        error = security_inode_follow_link(link->dentry, nd);
@@ -667,36 +675,38 @@ follow_link(struct path *link, struct nameidata *nd, void **p)
 
 static int follow_up_rcu(struct path *path)
 {
-       struct vfsmount *parent;
+       struct mount *mnt = real_mount(path->mnt);
+       struct mount *parent;
        struct dentry *mountpoint;
 
-       parent = path->mnt->mnt_parent;
-       if (parent == path->mnt)
+       parent = mnt->mnt_parent;
+       if (&parent->mnt == path->mnt)
                return 0;
-       mountpoint = path->mnt->mnt_mountpoint;
+       mountpoint = mnt->mnt_mountpoint;
        path->dentry = mountpoint;
-       path->mnt = parent;
+       path->mnt = &parent->mnt;
        return 1;
 }
 
 int follow_up(struct path *path)
 {
-       struct vfsmount *parent;
+       struct mount *mnt = real_mount(path->mnt);
+       struct mount *parent;
        struct dentry *mountpoint;
 
        br_read_lock(vfsmount_lock);
-       parent = path->mnt->mnt_parent;
-       if (parent == path->mnt) {
+       parent = mnt->mnt_parent;
+       if (&parent->mnt == path->mnt) {
                br_read_unlock(vfsmount_lock);
                return 0;
        }
-       mntget(parent);
-       mountpoint = dget(path->mnt->mnt_mountpoint);
+       mntget(&parent->mnt);
+       mountpoint = dget(mnt->mnt_mountpoint);
        br_read_unlock(vfsmount_lock);
        dput(path->dentry);
        path->dentry = mountpoint;
        mntput(path->mnt);
-       path->mnt = parent;
+       path->mnt = &parent->mnt;
        return 1;
 }
 
@@ -714,23 +724,20 @@ static int follow_automount(struct path *path, unsigned flags,
        if (!path->dentry->d_op || !path->dentry->d_op->d_automount)
                return -EREMOTE;
 
-       /* We don't want to mount if someone supplied AT_NO_AUTOMOUNT
-        * and this is the terminal part of the path.
-        */
-       if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_CONTINUE))
-               return -EISDIR; /* we actually want to stop here */
-
-       /* We want to mount if someone is trying to open/create a file of any
-        * type under the mountpoint, wants to traverse through the mountpoint
-        * or wants to open the mounted directory.
+       /* We don't want to mount if someone's just doing a stat -
+        * unless they're stat'ing a directory and appended a '/' to
+        * the name.
         *
-        * We don't want to mount if someone's just doing a stat and they've
-        * set AT_SYMLINK_NOFOLLOW - unless they're stat'ing a directory and
-        * appended a '/' to the name.
+        * We do, however, want to mount if someone wants to open or
+        * create a file of any type under the mountpoint, wants to
+        * traverse through the mountpoint or wants to open the
+        * mounted directory.  Also, autofs may mark negative dentries
+        * as being automount points.  These will need the attentions
+        * of the daemon to instantiate them before they can be used.
         */
-       if (!(flags & LOOKUP_FOLLOW) &&
-           !(flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY |
-                      LOOKUP_OPEN | LOOKUP_CREATE)))
+       if (!(flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY |
+                    LOOKUP_OPEN | LOOKUP_CREATE | LOOKUP_AUTOMOUNT)) &&
+           path->dentry->d_inode)
                return -EISDIR;
 
        current->total_link_count++;
@@ -748,7 +755,7 @@ static int follow_automount(struct path *path, unsigned flags,
                 * the path being looked up; if it wasn't then the remainder of
                 * the path is inaccessible and we should say so.
                 */
-               if (PTR_ERR(mnt) == -EISDIR && (flags & LOOKUP_CONTINUE))
+               if (PTR_ERR(mnt) == -EISDIR && (flags & LOOKUP_PARENT))
                        return -EREMOTE;
                return PTR_ERR(mnt);
        }
@@ -846,7 +853,7 @@ static int follow_managed(struct path *path, unsigned flags)
                mntput(path->mnt);
        if (ret == -EISDIR)
                ret = 0;
-       return ret;
+       return ret < 0 ? ret : need_mntput;
 }
 
 int follow_down_one(struct path *path)
@@ -878,7 +885,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                               struct inode **inode)
 {
        for (;;) {
-               struct vfsmount *mounted;
+               struct mount *mounted;
                /*
                 * Don't forget we might have a non-mountpoint managed dentry
                 * that wants to block transit.
@@ -892,8 +899,9 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                mounted = __lookup_mnt(path->mnt, path->dentry, 1);
                if (!mounted)
                        break;
-               path->mnt = mounted;
-               path->dentry = mounted->mnt_root;
+               path->mnt = &mounted->mnt;
+               path->dentry = mounted->mnt.mnt_root;
+               nd->flags |= LOOKUP_JUMPED;
                nd->seq = read_seqcount_begin(&path->dentry->d_seq);
                /*
                 * Update the inode too. We don't need to re-check the
@@ -908,12 +916,12 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
 static void follow_mount_rcu(struct nameidata *nd)
 {
        while (d_mountpoint(nd->path.dentry)) {
-               struct vfsmount *mounted;
+               struct mount *mounted;
                mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry, 1);
                if (!mounted)
                        break;
-               nd->path.mnt = mounted;
-               nd->path.dentry = mounted->mnt_root;
+               nd->path.mnt = &mounted->mnt;
+               nd->path.dentry = mounted->mnt.mnt_root;
                nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
        }
 }
@@ -1046,51 +1054,65 @@ static void follow_dotdot(struct nameidata *nd)
 }
 
 /*
- * Allocate a dentry with name and parent, and perform a parent
- * directory ->lookup on it. Returns the new dentry, or ERR_PTR
- * on error. parent->d_inode->i_mutex must be held. d_lookup must
- * have verified that no child exists while under i_mutex.
+ * This looks up the name in dcache, possibly revalidates the old dentry and
+ * allocates a new one if not found or not valid.  In the need_lookup argument
+ * returns whether i_op->lookup is necessary.
+ *
+ * dir->d_inode->i_mutex must be held
  */
-static struct dentry *d_alloc_and_lookup(struct dentry *parent,
-                               struct qstr *name, struct nameidata *nd)
+static struct dentry *lookup_dcache(struct qstr *name, struct dentry *dir,
+                                   struct nameidata *nd, bool *need_lookup)
 {
-       struct inode *inode = parent->d_inode;
        struct dentry *dentry;
-       struct dentry *old;
+       int error;
 
-       /* Don't create child dentry for a dead directory. */
-       if (unlikely(IS_DEADDIR(inode)))
-               return ERR_PTR(-ENOENT);
+       *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) {
+                       error = d_revalidate(dentry, nd);
+                       if (unlikely(error <= 0)) {
+                               if (error < 0) {
+                                       dput(dentry);
+                                       return ERR_PTR(error);
+                               } else if (!d_invalidate(dentry)) {
+                                       dput(dentry);
+                                       dentry = NULL;
+                               }
+                       }
+               }
+       }
 
-       dentry = d_alloc(parent, name);
-       if (unlikely(!dentry))
-               return ERR_PTR(-ENOMEM);
+       if (!dentry) {
+               dentry = d_alloc(dir, name);
+               if (unlikely(!dentry))
+                       return ERR_PTR(-ENOMEM);
 
-       old = inode->i_op->lookup(inode, dentry, nd);
-       if (unlikely(old)) {
-               dput(dentry);
-               dentry = old;
+               *need_lookup = true;
        }
        return dentry;
 }
 
 /*
- * We already have a dentry, but require a lookup to be performed on the parent
- * directory to fill in d_inode. Returns the new dentry, or ERR_PTR on error.
- * parent->d_inode->i_mutex must be held. d_lookup must have verified that no
- * child exists while under i_mutex.
+ * Call i_op->lookup on the dentry.  The dentry must be negative but may be
+ * hashed if it was pouplated with DCACHE_NEED_LOOKUP.
+ *
+ * dir->d_inode->i_mutex must be held
  */
-static struct dentry *d_inode_lookup(struct dentry *parent, struct dentry *dentry,
-                                    struct nameidata *nd)
+static struct dentry *lookup_real(struct inode *dir, struct dentry *dentry,
+                                 struct nameidata *nd)
 {
-       struct inode *inode = parent->d_inode;
        struct dentry *old;
 
        /* Don't create child dentry for a dead directory. */
-       if (unlikely(IS_DEADDIR(inode)))
+       if (unlikely(IS_DEADDIR(dir))) {
+               dput(dentry);
                return ERR_PTR(-ENOENT);
+       }
 
-       old = inode->i_op->lookup(inode, dentry, nd);
+       old = dir->i_op->lookup(dir, dentry, nd);
        if (unlikely(old)) {
                dput(dentry);
                dentry = old;
@@ -1098,6 +1120,19 @@ static struct dentry *d_inode_lookup(struct dentry *parent, struct dentry *dentr
        return dentry;
 }
 
+static struct dentry *__lookup_hash(struct qstr *name,
+               struct dentry *base, struct nameidata *nd)
+{
+       bool need_lookup;
+       struct dentry *dentry;
+
+       dentry = lookup_dcache(name, base, nd, &need_lookup);
+       if (!need_lookup)
+               return dentry;
+
+       return lookup_real(base->d_inode, dentry, nd);
+}
+
 /*
  *  It's more convoluted than I'd like it to be, but... it's still fairly
  *  small and for now I'd prefer to have fast path as straight as possible.
@@ -1129,6 +1164,8 @@ static int do_lookup(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);
                        if (unlikely(status <= 0)) {
@@ -1137,8 +1174,6 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
                                goto unlazy;
                        }
                }
-               if (unlikely(d_need_lookup(dentry)))
-                       goto unlazy;
                path->mnt = mnt;
                path->dentry = dentry;
                if (unlikely(!__follow_mount_rcu(nd, path, inode)))
@@ -1153,38 +1188,14 @@ unlazy:
                dentry = __d_lookup(parent, name);
        }
 
-       if (dentry && unlikely(d_need_lookup(dentry))) {
+       if (unlikely(!dentry))
+               goto need_lookup;
+
+       if (unlikely(d_need_lookup(dentry))) {
                dput(dentry);
-               dentry = NULL;
-       }
-retry:
-       if (unlikely(!dentry)) {
-               struct inode *dir = parent->d_inode;
-               BUG_ON(nd->inode != dir);
-
-               mutex_lock(&dir->i_mutex);
-               dentry = d_lookup(parent, name);
-               if (likely(!dentry)) {
-                       dentry = d_alloc_and_lookup(parent, name, nd);
-                       if (IS_ERR(dentry)) {
-                               mutex_unlock(&dir->i_mutex);
-                               return PTR_ERR(dentry);
-                       }
-                       /* known good */
-                       need_reval = 0;
-                       status = 1;
-               } else if (unlikely(d_need_lookup(dentry))) {
-                       dentry = d_inode_lookup(parent, dentry, nd);
-                       if (IS_ERR(dentry)) {
-                               mutex_unlock(&dir->i_mutex);
-                               return PTR_ERR(dentry);
-                       }
-                       /* known good */
-                       need_reval = 0;
-                       status = 1;
-               }
-               mutex_unlock(&dir->i_mutex);
+               goto need_lookup;
        }
+
        if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE) && need_reval)
                status = d_revalidate(dentry, nd);
        if (unlikely(status <= 0)) {
@@ -1194,12 +1205,10 @@ retry:
                }
                if (!d_invalidate(dentry)) {
                        dput(dentry);
-                       dentry = NULL;
-                       need_reval = 1;
-                       goto retry;
+                       goto need_lookup;
                }
        }
-
+done:
        path->mnt = mnt;
        path->dentry = dentry;
        err = follow_managed(path, nd->flags);
@@ -1207,20 +1216,32 @@ retry:
                path_put_conditional(path, nd);
                return err;
        }
+       if (err)
+               nd->flags |= LOOKUP_JUMPED;
        *inode = path->dentry->d_inode;
        return 0;
+
+need_lookup:
+       BUG_ON(nd->inode != parent->d_inode);
+
+       mutex_lock(&parent->d_inode->i_mutex);
+       dentry = __lookup_hash(name, parent, nd);
+       mutex_unlock(&parent->d_inode->i_mutex);
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
+       goto done;
 }
 
 static inline int may_lookup(struct nameidata *nd)
 {
        if (nd->flags & LOOKUP_RCU) {
-               int err = exec_permission(nd->inode, IPERM_FLAG_RCU);
+               int err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK);
                if (err != -ECHILD)
                        return err;
                if (unlazy_walk(nd, NULL))
                        return -ECHILD;
        }
-       return exec_permission(nd->inode, 0);
+       return inode_permission(nd->inode, MAY_EXEC);
 }
 
 static inline int handle_dots(struct nameidata *nd, int type)
@@ -1248,6 +1269,26 @@ static void terminate_walk(struct nameidata *nd)
        }
 }
 
+/*
+ * Do we need to follow links? We _really_ want to be able
+ * to do this check without having to look at inode->i_op,
+ * so we keep a cache of "no, this doesn't need follow_link"
+ * for the common case.
+ */
+static inline int should_follow_link(struct inode *inode, int follow)
+{
+       if (unlikely(!(inode->i_opflags & IOP_NOFOLLOW))) {
+               if (likely(inode->i_op->follow_link))
+                       return follow;
+
+               /* This gets set once for the inode lifetime */
+               spin_lock(&inode->i_lock);
+               inode->i_opflags |= IOP_NOFOLLOW;
+               spin_unlock(&inode->i_lock);
+       }
+       return 0;
+}
+
 static inline int walk_component(struct nameidata *nd, struct path *path,
                struct qstr *name, int type, int follow)
 {
@@ -1270,7 +1311,7 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
                terminate_walk(nd);
                return -ENOENT;
        }
-       if (unlikely(inode->i_op->follow_link) && follow) {
+       if (should_follow_link(inode, follow)) {
                if (nd->flags & LOOKUP_RCU) {
                        if (unlikely(unlazy_walk(nd, path->dentry))) {
                                terminate_walk(nd);
@@ -1323,6 +1364,148 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd)
 }
 
 /*
+ * We really don't want to look at inode->i_op->lookup
+ * when we don't have to. So we keep a cache bit in
+ * the inode ->i_opflags field that says "yes, we can
+ * do lookup on this inode".
+ */
+static inline int can_lookup(struct inode *inode)
+{
+       if (likely(inode->i_opflags & IOP_LOOKUP))
+               return 1;
+       if (likely(!inode->i_op->lookup))
+               return 0;
+
+       /* We do this once for the lifetime of the inode */
+       spin_lock(&inode->i_lock);
+       inode->i_opflags |= IOP_LOOKUP;
+       spin_unlock(&inode->i_lock);
+       return 1;
+}
+
+/*
+ * We can do the critical dentry name comparison and hashing
+ * operations one word at a time, but we are limited to:
+ *
+ * - Architectures with fast unaligned word accesses. We could
+ *   do a "get_unaligned()" if this helps and is sufficiently
+ *   fast.
+ *
+ * - Little-endian machines (so that we can generate the mask
+ *   of low bytes efficiently). Again, we *could* do a byte
+ *   swapping load on big-endian architectures if that is not
+ *   expensive enough to make the optimization worthless.
+ *
+ * - non-CONFIG_DEBUG_PAGEALLOC configurations (so that we
+ *   do not trap on the (extremely unlikely) case of a page
+ *   crossing operation.
+ *
+ * - Furthermore, we need an efficient 64-bit compile for the
+ *   64-bit case in order to generate the "number of bytes in
+ *   the final mask". Again, that could be replaced with a
+ *   efficient population count instruction or similar.
+ */
+#ifdef CONFIG_DCACHE_WORD_ACCESS
+
+#include <asm/word-at-a-time.h>
+
+#ifdef CONFIG_64BIT
+
+static inline unsigned int fold_hash(unsigned long hash)
+{
+       hash += hash >> (8*sizeof(int));
+       return hash;
+}
+
+#else  /* 32-bit case */
+
+#define fold_hash(x) (x)
+
+#endif
+
+unsigned int full_name_hash(const unsigned char *name, unsigned int len)
+{
+       unsigned long a, mask;
+       unsigned long hash = 0;
+
+       for (;;) {
+               a = load_unaligned_zeropad(name);
+               if (len < sizeof(unsigned long))
+                       break;
+               hash += a;
+               hash *= 9;
+               name += sizeof(unsigned long);
+               len -= sizeof(unsigned long);
+               if (!len)
+                       goto done;
+       }
+       mask = ~(~0ul << len*8);
+       hash += mask & a;
+done:
+       return fold_hash(hash);
+}
+EXPORT_SYMBOL(full_name_hash);
+
+/*
+ * Calculate the length and hash of the path component, and
+ * return the length of the component;
+ */
+static inline unsigned long hash_name(const char *name, unsigned int *hashp)
+{
+       unsigned long a, mask, hash, len;
+
+       hash = a = 0;
+       len = -sizeof(unsigned long);
+       do {
+               hash = (hash + a) * 9;
+               len += sizeof(unsigned long);
+               a = load_unaligned_zeropad(name+len);
+               /* Do we have any NUL or '/' bytes in this word? */
+               mask = has_zero(a) | has_zero(a ^ REPEAT_BYTE('/'));
+       } while (!mask);
+
+       /* The mask *below* the first high bit set */
+       mask = (mask - 1) & ~mask;
+       mask >>= 7;
+       hash += a & mask;
+       *hashp = fold_hash(hash);
+
+       return len + count_masked_bytes(mask);
+}
+
+#else
+
+unsigned int full_name_hash(const unsigned char *name, unsigned int len)
+{
+       unsigned long hash = init_name_hash();
+       while (len--)
+               hash = partial_name_hash(*name++, hash);
+       return end_name_hash(hash);
+}
+EXPORT_SYMBOL(full_name_hash);
+
+/*
+ * We know there's a real path component here of at least
+ * one character.
+ */
+static inline unsigned long hash_name(const char *name, unsigned int *hashp)
+{
+       unsigned long hash = init_name_hash();
+       unsigned long len = 0, c;
+
+       c = (unsigned char)*name;
+       do {
+               len++;
+               hash = partial_name_hash(c, hash);
+               c = (unsigned char)name[len];
+       } while (c && c != '/');
+       *hashp = end_name_hash(hash);
+       return len;
+}
+
+#endif
+
+/*
  * Name resolution.
  * This is the basic name resolution function, turning a pathname into
  * the final dentry. We expect 'base' to be positive and a directory.
@@ -1334,7 +1517,6 @@ static int link_path_walk(const char *name, struct nameidata *nd)
 {
        struct path next;
        int err;
-       unsigned int lookup_flags = nd->flags;
        
        while (*name=='/')
                name++;
@@ -1343,33 +1525,22 @@ static int link_path_walk(const char *name, struct nameidata *nd)
 
        /* At this point we know we have a real path component. */
        for(;;) {
-               unsigned long hash;
                struct qstr this;
-               unsigned int c;
+               long len;
                int type;
 
-               nd->flags |= LOOKUP_CONTINUE;
-
                err = may_lookup(nd);
                if (err)
                        break;
 
+               len = hash_name(name, &this.hash);
                this.name = name;
-               c = *(const unsigned char *)name;
-
-               hash = init_name_hash();
-               do {
-                       name++;
-                       hash = partial_name_hash(c, hash);
-                       c = *(const unsigned char *)name;
-               } while (c && (c != '/'));
-               this.len = name - (const char *) this.name;
-               this.hash = end_name_hash(hash);
+               this.len = len;
 
                type = LAST_NORM;
-               if (this.name[0] == '.') switch (this.len) {
+               if (name[0] == '.') switch (len) {
                        case 2:
-                               if (this.name[1] == '.') {
+                               if (name[1] == '.') {
                                        type = LAST_DOTDOT;
                                        nd->flags |= LOOKUP_JUMPED;
                                }
@@ -1388,12 +1559,18 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                        }
                }
 
-               /* remove trailing slashes? */
-               if (!c)
+               if (!name[len])
                        goto last_component;
-               while (*++name == '/');
-               if (!*name)
+               /*
+                * If it wasn't NUL, we know it was '/'. Skip that
+                * slash, and continue until no more slashes.
+                */
+               do {
+                       len++;
+               } while (unlikely(name[len] == '/'));
+               if (!name[len])
                        goto last_component;
+               name += len;
 
                err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW);
                if (err < 0)
@@ -1404,15 +1581,13 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                        if (err)
                                return err;
                }
+               if (can_lookup(nd->inode))
+                       continue;
                err = -ENOTDIR; 
-               if (!nd->inode->i_op->lookup)
-                       break;
-               continue;
+               break;
                /* here ends the main loop */
 
 last_component:
-               /* Clear LOOKUP_CONTINUE iff it was previously unset */
-               nd->flags &= lookup_flags | ~LOOKUP_CONTINUE;
                nd->last = this;
                nd->last_type = type;
                return 0;
@@ -1495,7 +1670,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
                        if (!S_ISDIR(dentry->d_inode->i_mode))
                                goto fput_fail;
 
-                       retval = exec_permission(dentry->d_inode, 0);
+                       retval = inode_permission(dentry->d_inode, MAY_EXEC);
                        if (retval)
                                goto fput_fail;
                }
@@ -1633,53 +1808,22 @@ int kern_path(const char *name, unsigned int flags, struct path *path)
  * @mnt: pointer to vfs mount of the base directory
  * @name: pointer to file name
  * @flags: lookup flags
- * @nd: pointer to nameidata
+ * @path: pointer to struct path to fill
  */
 int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
                    const char *name, unsigned int flags,
-                   struct nameidata *nd)
+                   struct path *path)
 {
-       nd->root.dentry = dentry;
-       nd->root.mnt = mnt;
-       /* the first argument of do_path_lookup() is ignored with LOOKUP_ROOT */
-       return do_path_lookup(AT_FDCWD, name, flags | LOOKUP_ROOT, nd);
-}
-
-static struct dentry *__lookup_hash(struct qstr *name,
-               struct dentry *base, struct nameidata *nd)
-{
-       struct inode *inode = base->d_inode;
-       struct dentry *dentry;
+       struct nameidata nd;
        int err;
-
-       err = exec_permission(inode, 0);
-       if (err)
-               return ERR_PTR(err);
-
-       /*
-        * Don't bother with __d_lookup: callers are for creat as
-        * well as unlink, so a lot of the time it would cost
-        * a double lookup.
-        */
-       dentry = d_lookup(base, name);
-
-       if (dentry && d_need_lookup(dentry)) {
-               /*
-                * __lookup_hash is called with the parent dir's i_mutex already
-                * held, so we are good to go here.
-                */
-               dentry = d_inode_lookup(base, dentry, nd);
-               if (IS_ERR(dentry))
-                       return dentry;
-       }
-
-       if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE))
-               dentry = do_revalidate(dentry, nd);
-
-       if (!dentry)
-               dentry = d_alloc_and_lookup(base, name, nd);
-
-       return dentry;
+       nd.root.dentry = dentry;
+       nd.root.mnt = mnt;
+       BUG_ON(flags & LOOKUP_PARENT);
+       /* the first argument of do_path_lookup() is ignored with LOOKUP_ROOT */
+       err = do_path_lookup(AT_FDCWD, name, flags | LOOKUP_ROOT, &nd);
+       if (!err)
+               *path = nd.path;
+       return err;
 }
 
 /*
@@ -1706,24 +1850,22 @@ static struct dentry *lookup_hash(struct nameidata *nd)
 struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
 {
        struct qstr this;
-       unsigned long hash;
        unsigned int c;
+       int err;
 
        WARN_ON_ONCE(!mutex_is_locked(&base->d_inode->i_mutex));
 
        this.name = name;
        this.len = len;
+       this.hash = full_name_hash(name, len);
        if (!len)
                return ERR_PTR(-EACCES);
 
-       hash = init_name_hash();
        while (len--) {
                c = *(const unsigned char *)name++;
                if (c == '/' || c == '\0')
                        return ERR_PTR(-EACCES);
-               hash = partial_name_hash(c, hash);
        }
-       this.hash = end_name_hash(hash);
        /*
         * See if the low-level filesystem might want
         * to use its own hash..
@@ -1734,14 +1876,18 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
                        return ERR_PTR(err);
        }
 
+       err = inode_permission(base->d_inode, MAY_EXEC);
+       if (err)
+               return ERR_PTR(err);
+
        return __lookup_hash(&this, base, NULL);
 }
 
-int user_path_at(int dfd, const char __user *name, unsigned flags,
-                struct path *path)
+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);
+       char *tmp = getname_flags(name, flags, empty);
        int err = PTR_ERR(tmp);
        if (!IS_ERR(tmp)) {
 
@@ -1755,6 +1901,12 @@ int user_path_at(int dfd, const char __user *name, unsigned flags,
        return err;
 }
 
+int user_path_at(int dfd, const char __user *name, unsigned flags,
+                struct path *path)
+{
+       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)
 {
@@ -1795,6 +1947,26 @@ other_userns:
 }
 
 /*
+ * Do the directory specific tests of inode_permission() and call the
+ * may_delete inode operation.  The may_delete inode operation must do the
+ * sticky check when needed.
+ */
+static int may_delete_iop(struct inode *dir, struct inode *inode, int replace)
+{
+       int error;
+
+       if (IS_RDONLY(dir))
+               return -EROFS;
+       if (IS_IMMUTABLE(dir))
+               return -EACCES;
+       error = dir->i_op->may_delete(dir, inode, replace);
+       if (!error)
+               error = security_inode_permission(dir, MAY_WRITE | MAY_EXEC);
+
+       return error;
+}
+
+/*
  *     Check whether we can remove a link victim from directory dir, check
  *  whether the type of victim is right.
  *  1. We can't do it if dir is read-only (done in permission())
@@ -1813,7 +1985,8 @@ other_userns:
  * 10. We don't allow removal of NFS sillyrenamed files; it's handled by
  *     nfs_async_unlink().
  */
-static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
+static int may_delete(struct inode *dir, struct dentry *victim,
+                     int isdir, int replace)
 {
        int error;
 
@@ -1822,14 +1995,19 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
 
        BUG_ON(victim->d_parent->d_inode != dir);
        audit_inode_child(victim, dir);
-
-       error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
+       if (dir->i_op->may_delete)
+               error = may_delete_iop(dir, victim->d_inode, replace);
+       else {
+               error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
+               if (!error && check_sticky(dir, victim->d_inode))
+                       error = -EPERM;
+       }
        if (error)
                return error;
        if (IS_APPEND(dir))
                return -EPERM;
-       if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)||
-           IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode))
+       if (IS_APPEND(victim->d_inode) || IS_IMMUTABLE(victim->d_inode) ||
+               IS_SWAPFILE(victim->d_inode))
                return -EPERM;
        if (isdir) {
                if (!S_ISDIR(victim->d_inode->i_mode))
@@ -1845,6 +2023,25 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
        return 0;
 }
 
+/*
+ * Do the directory specific tests of inode_permission() and call the
+ * may_create inode operation.
+ */
+static int may_create_iop(struct inode *dir, int isdir)
+{
+       int error;
+
+       if (IS_RDONLY(dir))
+               return -EROFS;
+       if (IS_IMMUTABLE(dir))
+               return -EACCES;
+       error = dir->i_op->may_create(dir, isdir);
+       if (!error)
+               error = security_inode_permission(dir, MAY_WRITE | MAY_EXEC);
+
+       return error;
+}
+
 /*     Check whether we can create an object with dentry child in directory
  *  dir.
  *  1. We can't do it if child already exists (open has special treatment for
@@ -1853,13 +2050,16 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
  *  3. We should have write and exec permissions on dir
  *  4. We can't do it if dir is immutable (done in permission())
  */
-static inline int may_create(struct inode *dir, struct dentry *child)
+static inline int may_create(struct inode *dir, struct dentry *child, int isdir)
 {
        if (child->d_inode)
                return -EEXIST;
        if (IS_DEADDIR(dir))
                return -ENOENT;
-       return inode_permission(dir, MAY_WRITE | MAY_EXEC);
+       if (dir->i_op->may_create)
+               return may_create_iop(dir, isdir);
+       else
+               return inode_permission(dir, MAY_WRITE | MAY_EXEC);
 }
 
 /*
@@ -1904,10 +2104,10 @@ void unlock_rename(struct dentry *p1, struct dentry *p2)
        }
 }
 
-int vfs_create(struct inode *dir, struct dentry *dentry, int mode,
+int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
                struct nameidata *nd)
 {
-       int error = may_create(dir, dentry);
+       int error = may_create(dir, dentry, 0);
 
        if (error)
                return error;
@@ -1974,10 +2174,7 @@ static int may_open(struct path *path, int acc_mode, int flag)
        if (flag & O_NOATIME && !inode_owner_or_capable(inode))
                return -EPERM;
 
-       /*
-        * Ensure there are no outstanding leases on the file.
-        */
-       return break_lease(inode, flag);
+       return 0;
 }
 
 static int handle_truncate(struct file *filp)
@@ -2002,27 +2199,10 @@ static int handle_truncate(struct file *filp)
        return error;
 }
 
-/*
- * Note that while the flag value (low two bits) for sys_open means:
- *     00 - read-only
- *     01 - write-only
- *     10 - read-write
- *     11 - special
- * it is changed into
- *     00 - no permissions needed
- *     01 - read-permission
- *     10 - write-permission
- *     11 - read-write
- * for the internal routines (ie open_namei()/follow_link() etc)
- * This is more logical, and also allows the 00 "no perm needed"
- * to be used for symlinks (where the permissions are checked
- * later).
- *
-*/
 static inline int open_to_namei_flags(int flag)
 {
-       if ((flag+1) & O_ACCMODE)
-               flag++;
+       if ((flag & O_ACCMODE) == 3)
+               flag--;
        return flag;
 }
 
@@ -2085,7 +2265,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
                /* sayonara */
                error = complete_walk(nd);
                if (error)
-                       return ERR_PTR(-ECHILD);
+                       return ERR_PTR(error);
 
                error = -ENOTDIR;
                if (nd->flags & LOOKUP_DIRECTORY) {
@@ -2097,6 +2277,10 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
        }
 
        /* create side of things */
+       /*
+        * This will *only* deal with leaving RCU mode - LOOKUP_JUMPED has been
+        * cleared when we got to the last component we are about to look up
+        */
        error = complete_walk(nd);
        if (error)
                return ERR_PTR(error);
@@ -2121,8 +2305,8 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
 
        /* Negative dentry, just create the file */
        if (!dentry->d_inode) {
-               int mode = op->mode;
-               if (!IS_POSIXACL(dir->d_inode))
+               umode_t mode = op->mode;
+               if (!IS_ACL(dir->d_inode))
                        mode &= ~current_umask();
                /*
                 * This write is needed to ensure that a
@@ -2165,6 +2349,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
        if (error < 0)
                goto exit_dput;
 
+       if (error)
+               nd->flags |= LOOKUP_JUMPED;
+
        error = -ENOENT;
        if (!path->dentry->d_inode)
                goto exit_dput;
@@ -2174,6 +2361,10 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
 
        path_to_nameidata(path, nd);
        nd->inode = path->dentry->d_inode;
+       /* Why this, you ask?  _Now_ we might have grown LOOKUP_JUMPED... */
+       error = complete_walk(nd);
+       if (error)
+               return ERR_PTR(error);
        error = -EISDIR;
        if (S_ISDIR(nd->inode->i_mode))
                goto exit;
@@ -2317,35 +2508,29 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
        return file;
 }
 
-/**
- * lookup_create - lookup a dentry, creating it if it doesn't exist
- * @nd: nameidata info
- * @is_dir: directory flag
- *
- * Simple function to lookup and return a dentry and create it
- * if it doesn't exist.  Is SMP-safe.
- *
- * Returns with nd->path.dentry->d_inode->i_mutex locked.
- */
-struct dentry *lookup_create(struct nameidata *nd, int is_dir)
+struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path, int is_dir)
 {
        struct dentry *dentry = ERR_PTR(-EEXIST);
+       struct nameidata nd;
+       int error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd);
+       if (error)
+               return ERR_PTR(error);
 
-       mutex_lock_nested(&nd->path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
        /*
         * Yucky last component or no last component at all?
         * (foo/., foo/.., /////)
         */
-       if (nd->last_type != LAST_NORM)
-               goto fail;
-       nd->flags &= ~LOOKUP_PARENT;
-       nd->flags |= LOOKUP_CREATE | LOOKUP_EXCL;
-       nd->intent.open.flags = O_EXCL;
+       if (nd.last_type != LAST_NORM)
+               goto out;
+       nd.flags &= ~LOOKUP_PARENT;
+       nd.flags |= LOOKUP_CREATE | LOOKUP_EXCL;
+       nd.intent.open.flags = O_EXCL;
 
        /*
         * Do the final lookup.
         */
-       dentry = lookup_hash(nd);
+       mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
+       dentry = lookup_hash(&nd);
        if (IS_ERR(dentry))
                goto fail;
 
@@ -2357,22 +2542,39 @@ struct dentry *lookup_create(struct nameidata *nd, int is_dir)
         * all is fine. Let's be bastards - you had / on the end, you've
         * been asking for (non-existent) directory. -ENOENT for you.
         */
-       if (unlikely(!is_dir && nd->last.name[nd->last.len])) {
+       if (unlikely(!is_dir && nd.last.name[nd.last.len])) {
                dput(dentry);
                dentry = ERR_PTR(-ENOENT);
+               goto fail;
        }
+       *path = nd.path;
        return dentry;
 eexist:
        dput(dentry);
        dentry = ERR_PTR(-EEXIST);
 fail:
+       mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+out:
+       path_put(&nd.path);
        return dentry;
 }
-EXPORT_SYMBOL_GPL(lookup_create);
+EXPORT_SYMBOL(kern_path_create);
 
-int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir)
 {
-       int error = may_create(dir, dentry);
+       char *tmp = getname(pathname);
+       struct dentry *res;
+       if (IS_ERR(tmp))
+               return ERR_CAST(tmp);
+       res = kern_path_create(dfd, tmp, path, is_dir);
+       putname(tmp);
+       return res;
+}
+EXPORT_SYMBOL(user_path_create);
+
+int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
+{
+       int error = may_create(dir, dentry, 0);
 
        if (error)
                return error;
@@ -2398,7 +2600,7 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
        return error;
 }
 
-static int may_mknod(mode_t mode)
+static int may_mknod(umode_t mode)
 {
        switch (mode & S_IFMT) {
        case S_IFREG:
@@ -2415,69 +2617,62 @@ static int may_mknod(mode_t mode)
        }
 }
 
-SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode,
+SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
                unsigned, dev)
 {
-       int error;
-       char *tmp;
        struct dentry *dentry;
-       struct nameidata nd;
+       struct path path;
+       int error;
 
        if (S_ISDIR(mode))
                return -EPERM;
 
-       error = user_path_parent(dfd, filename, &nd, &tmp);
-       if (error)
-               return error;
+       dentry = user_path_create(dfd, filename, &path, 0);
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
 
-       dentry = lookup_create(&nd, 0);
-       if (IS_ERR(dentry)) {
-               error = PTR_ERR(dentry);
-               goto out_unlock;
-       }
-       if (!IS_POSIXACL(nd.path.dentry->d_inode))
+       if (!IS_ACL(path.dentry->d_inode))
                mode &= ~current_umask();
        error = may_mknod(mode);
        if (error)
                goto out_dput;
-       error = mnt_want_write(nd.path.mnt);
+       error = mnt_want_write(path.mnt);
        if (error)
                goto out_dput;
-       error = security_path_mknod(&nd.path, dentry, mode, dev);
+       error = security_path_mknod(&path, dentry, mode, dev);
        if (error)
                goto out_drop_write;
        switch (mode & S_IFMT) {
                case 0: case S_IFREG:
-                       error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd);
+                       error = vfs_create(path.dentry->d_inode,dentry,mode,NULL);
                        break;
                case S_IFCHR: case S_IFBLK:
-                       error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,
+                       error = vfs_mknod(path.dentry->d_inode,dentry,mode,
                                        new_decode_dev(dev));
                        break;
                case S_IFIFO: case S_IFSOCK:
-                       error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0);
+                       error = vfs_mknod(path.dentry->d_inode,dentry,mode,0);
                        break;
        }
 out_drop_write:
-       mnt_drop_write(nd.path.mnt);
+       mnt_drop_write(path.mnt);
 out_dput:
        dput(dentry);
-out_unlock:
-       mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
-       path_put(&nd.path);
-       putname(tmp);
+       mutex_unlock(&path.dentry->d_inode->i_mutex);
+       path_put(&path);
 
        return error;
 }
 
-SYSCALL_DEFINE3(mknod, const char __user *, filename, int, mode, unsigned, dev)
+SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, dev)
 {
        return sys_mknodat(AT_FDCWD, filename, mode, dev);
 }
 
-int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
-       int error = may_create(dir, dentry);
+       int error = may_create(dir, dentry, 1);
+       unsigned max_links = dir->i_sb->s_max_links;
 
        if (error)
                return error;
@@ -2490,57 +2685,51 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        if (error)
                return error;
 
+       if (max_links && dir->i_nlink >= max_links)
+               return -EMLINK;
+
        error = dir->i_op->mkdir(dir, dentry, mode);
        if (!error)
                fsnotify_mkdir(dir, dentry);
        return error;
 }
 
-SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, int, mode)
+SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
 {
-       int error = 0;
-       char * tmp;
        struct dentry *dentry;
-       struct nameidata nd;
-
-       error = user_path_parent(dfd, pathname, &nd, &tmp);
-       if (error)
-               goto out_err;
+       struct path path;
+       int error;
 
-       dentry = lookup_create(&nd, 1);
-       error = PTR_ERR(dentry);
+       dentry = user_path_create(dfd, pathname, &path, 1);
        if (IS_ERR(dentry))
-               goto out_unlock;
+               return PTR_ERR(dentry);
 
-       if (!IS_POSIXACL(nd.path.dentry->d_inode))
+       if (!IS_ACL(path.dentry->d_inode))
                mode &= ~current_umask();
-       error = mnt_want_write(nd.path.mnt);
+       error = mnt_want_write(path.mnt);
        if (error)
                goto out_dput;
-       error = security_path_mkdir(&nd.path, dentry, mode);
+       error = security_path_mkdir(&path, dentry, mode);
        if (error)
                goto out_drop_write;
-       error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
+       error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
 out_drop_write:
-       mnt_drop_write(nd.path.mnt);
+       mnt_drop_write(path.mnt);
 out_dput:
        dput(dentry);
-out_unlock:
-       mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
-       path_put(&nd.path);
-       putname(tmp);
-out_err:
+       mutex_unlock(&path.dentry->d_inode->i_mutex);
+       path_put(&path);
        return error;
 }
 
-SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)
+SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode)
 {
        return sys_mkdirat(AT_FDCWD, pathname, mode);
 }
 
 /*
  * The dentry_unhash() helper will try to drop the dentry early: we
- * should have a usage count of 2 if we're the only user of this
+ * should have a usage count of 1 if we're the only user of this
  * dentry, and if that is true (possibly after pruning the dcache),
  * then we drop the dentry now.
  *
@@ -2564,7 +2753,7 @@ void dentry_unhash(struct dentry *dentry)
 
 int vfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
-       int error = may_delete(dir, dentry, 1);
+       int error = may_delete(dir, dentry, 1, 0);
 
        if (error)
                return error;
@@ -2572,6 +2761,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
        if (!dir->i_op->rmdir)
                return -EPERM;
 
+       dget(dentry);
        mutex_lock(&dentry->d_inode->i_mutex);
 
        error = -EBUSY;
@@ -2592,6 +2782,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
 
 out:
        mutex_unlock(&dentry->d_inode->i_mutex);
+       dput(dentry);
        if (!error)
                d_delete(dentry);
        return error;
@@ -2657,7 +2848,7 @@ SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
 
 int vfs_unlink(struct inode *dir, struct dentry *dentry)
 {
-       int error = may_delete(dir, dentry, 0);
+       int error = may_delete(dir, dentry, 0, 0);
 
        if (error)
                return error;
@@ -2766,7 +2957,7 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname)
 
 int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
 {
-       int error = may_create(dir, dentry);
+       int error = may_create(dir, dentry, 0);
 
        if (error)
                return error;
@@ -2789,38 +2980,31 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
 {
        int error;
        char *from;
-       char *to;
        struct dentry *dentry;
-       struct nameidata nd;
+       struct path path;
 
        from = getname(oldname);
        if (IS_ERR(from))
                return PTR_ERR(from);
 
-       error = user_path_parent(newdfd, newname, &nd, &to);
-       if (error)
-               goto out_putname;
-
-       dentry = lookup_create(&nd, 0);
+       dentry = user_path_create(newdfd, newname, &path, 0);
        error = PTR_ERR(dentry);
        if (IS_ERR(dentry))
-               goto out_unlock;
+               goto out_putname;
 
-       error = mnt_want_write(nd.path.mnt);
+       error = mnt_want_write(path.mnt);
        if (error)
                goto out_dput;
-       error = security_path_symlink(&nd.path, dentry, from);
+       error = security_path_symlink(&path, dentry, from);
        if (error)
                goto out_drop_write;
-       error = vfs_symlink(nd.path.dentry->d_inode, dentry, from);
+       error = vfs_symlink(path.dentry->d_inode, dentry, from);
 out_drop_write:
-       mnt_drop_write(nd.path.mnt);
+       mnt_drop_write(path.mnt);
 out_dput:
        dput(dentry);
-out_unlock:
-       mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
-       path_put(&nd.path);
-       putname(to);
+       mutex_unlock(&path.dentry->d_inode->i_mutex);
+       path_put(&path);
 out_putname:
        putname(from);
        return error;
@@ -2834,12 +3018,13 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn
 int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
 {
        struct inode *inode = old_dentry->d_inode;
+       unsigned max_links = dir->i_sb->s_max_links;
        int error;
 
        if (!inode)
                return -ENOENT;
 
-       error = may_create(dir, new_dentry);
+       error = may_create(dir, new_dentry, S_ISDIR(inode->i_mode));
        if (error)
                return error;
 
@@ -2864,6 +3049,8 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
        /* Make sure we don't allow creating hardlink to an unlinked file */
        if (inode->i_nlink == 0)
                error =  -ENOENT;
+       else if (max_links && inode->i_nlink >= max_links)
+               error = -EMLINK;
        else
                error = dir->i_op->link(old_dentry, dir, new_dentry);
        mutex_unlock(&inode->i_mutex);
@@ -2885,11 +3072,9 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
                int, newdfd, const char __user *, newname, int, flags)
 {
        struct dentry *new_dentry;
-       struct nameidata nd;
-       struct path old_path;
+       struct path old_path, new_path;
        int how = 0;
        int error;
-       char *to;
 
        if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
                return -EINVAL;
@@ -2911,32 +3096,27 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
        if (error)
                return error;
 
-       error = user_path_parent(newdfd, newname, &nd, &to);
-       if (error)
-               goto out;
-       error = -EXDEV;
-       if (old_path.mnt != nd.path.mnt)
-               goto out_release;
-       new_dentry = lookup_create(&nd, 0);
+       new_dentry = user_path_create(newdfd, newname, &new_path, 0);
        error = PTR_ERR(new_dentry);
        if (IS_ERR(new_dentry))
-               goto out_unlock;
-       error = mnt_want_write(nd.path.mnt);
+               goto out;
+
+       error = -EXDEV;
+       if (old_path.mnt != new_path.mnt)
+               goto out_dput;
+       error = mnt_want_write(new_path.mnt);
        if (error)
                goto out_dput;
-       error = security_path_link(old_path.dentry, &nd.path, new_dentry);
+       error = security_path_link(old_path.dentry, &new_path, new_dentry);
        if (error)
                goto out_drop_write;
-       error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry);
+       error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry);
 out_drop_write:
-       mnt_drop_write(nd.path.mnt);
+       mnt_drop_write(new_path.mnt);
 out_dput:
        dput(new_dentry);
-out_unlock:
-       mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
-out_release:
-       path_put(&nd.path);
-       putname(to);
+       mutex_unlock(&new_path.dentry->d_inode->i_mutex);
+       path_put(&new_path);
 out:
        path_put(&old_path);
 
@@ -2980,6 +3160,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
 {
        int error = 0;
        struct inode *target = new_dentry->d_inode;
+       unsigned max_links = new_dir->i_sb->s_max_links;
 
        /*
         * If we are going to change the parent - check write permissions,
@@ -2995,6 +3176,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
        if (error)
                return error;
 
+       dget(new_dentry);
        if (target)
                mutex_lock(&target->i_mutex);
 
@@ -3002,6 +3184,11 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
        if (d_mountpoint(old_dentry) || d_mountpoint(new_dentry))
                goto out;
 
+       error = -EMLINK;
+       if (max_links && !target && new_dir != old_dir &&
+           new_dir->i_nlink >= max_links)
+               goto out;
+
        if (target)
                shrink_dcache_parent(new_dentry);
        error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
@@ -3015,6 +3202,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
 out:
        if (target)
                mutex_unlock(&target->i_mutex);
+       dput(new_dentry);
        if (!error)
                if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
                        d_move(old_dentry,new_dentry);
@@ -3064,14 +3252,14 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (old_dentry->d_inode == new_dentry->d_inode)
                return 0;
  
-       error = may_delete(old_dir, old_dentry, is_dir);
+       error = may_delete(old_dir, old_dentry, is_dir, 0);
        if (error)
                return error;
 
        if (!new_dentry->d_inode)
-               error = may_create(new_dir, new_dentry);
+               error = may_create(new_dir, new_dentry, is_dir);
        else
-               error = may_delete(new_dir, new_dentry, is_dir);
+               error = may_delete(new_dir, new_dentry, is_dir, 1);
        if (error)
                return error;
 
@@ -3299,9 +3487,9 @@ retry:
        if (err)
                goto fail;
 
-       kaddr = kmap_atomic(page, KM_USER0);
+       kaddr = kmap_atomic(page);
        memcpy(kaddr, symname, len-1);
-       kunmap_atomic(kaddr, KM_USER0);
+       kunmap_atomic(kaddr);
 
        err = pagecache_write_end(NULL, mapping, 0, len-1, len-1,
                                                        page, fsdata);
@@ -3342,7 +3530,6 @@ EXPORT_SYMBOL(page_readlink);
 EXPORT_SYMBOL(__page_symlink);
 EXPORT_SYMBOL(page_symlink);
 EXPORT_SYMBOL(page_symlink_inode_operations);
-EXPORT_SYMBOL(kern_path_parent);
 EXPORT_SYMBOL(kern_path);
 EXPORT_SYMBOL(vfs_path_lookup);
 EXPORT_SYMBOL(inode_permission);