fold handle_mounts() into step_into()
[linux-2.6-microblaze.git] / fs / namei.c
index db6565c..8a673f4 100644 (file)
@@ -1208,14 +1208,9 @@ EXPORT_SYMBOL(follow_up);
  * - return -EISDIR to tell follow_managed() to stop and return the path we
  *   were called with.
  */
-static int follow_automount(struct path *path, struct nameidata *nd,
-                           bool *need_mntput)
+static int follow_automount(struct path *path, int *count, unsigned lookup_flags)
 {
-       struct vfsmount *mnt;
-       int err;
-
-       if (!path->dentry->d_op || !path->dentry->d_op->d_automount)
-               return -EREMOTE;
+       struct dentry *dentry = path->dentry;
 
        /* We don't want to mount if someone's just doing a stat -
         * unless they're stat'ing a directory and appended a '/' to
@@ -1228,54 +1223,15 @@ static int follow_automount(struct path *path, struct nameidata *nd,
         * as being automount points.  These will need the attentions
         * of the daemon to instantiate them before they can be used.
         */
-       if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY |
+       if (!(lookup_flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY |
                           LOOKUP_OPEN | LOOKUP_CREATE | LOOKUP_AUTOMOUNT)) &&
-           path->dentry->d_inode)
+           dentry->d_inode)
                return -EISDIR;
 
-       nd->total_link_count++;
-       if (nd->total_link_count >= 40)
+       if (count && (*count)++ >= MAXSYMLINKS)
                return -ELOOP;
 
-       mnt = path->dentry->d_op->d_automount(path);
-       if (IS_ERR(mnt)) {
-               /*
-                * The filesystem is allowed to return -EISDIR here to indicate
-                * it doesn't want to automount.  For instance, autofs would do
-                * this so that its userspace daemon can mount on this dentry.
-                *
-                * However, we can only permit this if it's a terminal point in
-                * 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 && (nd->flags & LOOKUP_PARENT))
-                       return -EREMOTE;
-               return PTR_ERR(mnt);
-       }
-
-       if (!mnt) /* mount collision */
-               return 0;
-
-       if (!*need_mntput) {
-               /* lock_mount() may release path->mnt on error */
-               mntget(path->mnt);
-               *need_mntput = true;
-       }
-       err = finish_automount(mnt, path);
-
-       switch (err) {
-       case -EBUSY:
-               /* Someone else made a mount here whilst we were busy */
-               return 0;
-       case 0:
-               path_put(path);
-               path->mnt = mnt;
-               path->dentry = dget(mnt->mnt_root);
-               return 0;
-       default:
-               return err;
-       }
-
+       return finish_automount(dentry->d_op->d_automount(path), path);
 }
 
 /*
@@ -1333,7 +1289,8 @@ static int follow_managed(struct path *path, struct nameidata *nd)
 
                /* Handle an automount point */
                if (flags & DCACHE_NEED_AUTOMOUNT) {
-                       ret = follow_automount(path, nd, &need_mntput);
+                       ret = follow_automount(path, &nd->total_link_count,
+                                               nd->flags);
                        if (ret < 0)
                                break;
                        continue;
@@ -1428,6 +1385,34 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                !(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT);
 }
 
+static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry,
+                         struct path *path, struct inode **inode,
+                         unsigned int *seqp)
+{
+       int ret;
+
+       path->mnt = nd->path.mnt;
+       path->dentry = dentry;
+       if (nd->flags & LOOKUP_RCU) {
+               unsigned int seq = *seqp;
+               if (unlikely(!*inode))
+                       return -ENOENT;
+               if (likely(__follow_mount_rcu(nd, path, inode, seqp)))
+                       return 1;
+               if (unlazy_child(nd, dentry, seq))
+                       return -ECHILD;
+               // *path might've been clobbered by __follow_mount_rcu()
+               path->mnt = nd->path.mnt;
+               path->dentry = dentry;
+       }
+       ret = follow_managed(path, nd);
+       if (likely(ret >= 0)) {
+               *inode = d_backing_inode(path->dentry);
+               *seqp = 0; /* out of RCU mode, so the value doesn't matter */
+       }
+       return ret;
+}
+
 static int follow_dotdot_rcu(struct nameidata *nd)
 {
        struct inode *inode = nd->inode;
@@ -1643,14 +1628,12 @@ static struct dentry *__lookup_hash(const struct qstr *name,
        return dentry;
 }
 
-static int lookup_fast(struct nameidata *nd,
-                      struct path *path, struct inode **inode,
-                      unsigned *seqp)
+static struct dentry *lookup_fast(struct nameidata *nd,
+                                 struct inode **inode,
+                                 unsigned *seqp)
 {
-       struct vfsmount *mnt = nd->path.mnt;
        struct dentry *dentry, *parent = nd->path.dentry;
        int status = 1;
-       int err;
 
        /*
         * Rename seqlock is not required here because in the off chance
@@ -1659,12 +1642,11 @@ static int lookup_fast(struct nameidata *nd,
         */
        if (nd->flags & LOOKUP_RCU) {
                unsigned seq;
-               bool negative;
                dentry = __d_lookup_rcu(parent, &nd->last, &seq);
                if (unlikely(!dentry)) {
                        if (unlazy_walk(nd))
-                               return -ECHILD;
-                       return 0;
+                               return ERR_PTR(-ECHILD);
+                       return NULL;
                }
 
                /*
@@ -1672,9 +1654,8 @@ static int lookup_fast(struct nameidata *nd,
                 * the dentry name information from lookup.
                 */
                *inode = d_backing_inode(dentry);
-               negative = d_is_negative(dentry);
                if (unlikely(read_seqcount_retry(&dentry->d_seq, seq)))
-                       return -ECHILD;
+                       return ERR_PTR(-ECHILD);
 
                /*
                 * This sequence count validates that the parent had no
@@ -1684,46 +1665,30 @@ static int lookup_fast(struct nameidata *nd,
                 *  enough, we can use __read_seqcount_retry here.
                 */
                if (unlikely(__read_seqcount_retry(&parent->d_seq, nd->seq)))
-                       return -ECHILD;
+                       return ERR_PTR(-ECHILD);
 
                *seqp = seq;
                status = d_revalidate(dentry, nd->flags);
-               if (likely(status > 0)) {
-                       /*
-                        * Note: do negative dentry check after revalidation in
-                        * case that drops it.
-                        */
-                       if (unlikely(negative))
-                               return -ENOENT;
-                       path->mnt = mnt;
-                       path->dentry = dentry;
-                       if (likely(__follow_mount_rcu(nd, path, inode, seqp)))
-                               return 1;
-               }
+               if (likely(status > 0))
+                       return dentry;
                if (unlazy_child(nd, dentry, seq))
-                       return -ECHILD;
+                       return ERR_PTR(-ECHILD);
                if (unlikely(status == -ECHILD))
                        /* we'd been told to redo it in non-rcu mode */
                        status = d_revalidate(dentry, nd->flags);
        } else {
                dentry = __d_lookup(parent, &nd->last);
                if (unlikely(!dentry))
-                       return 0;
+                       return NULL;
                status = d_revalidate(dentry, nd->flags);
        }
        if (unlikely(status <= 0)) {
                if (!status)
                        d_invalidate(dentry);
                dput(dentry);
-               return status;
+               return ERR_PTR(status);
        }
-
-       path->mnt = mnt;
-       path->dentry = dentry;
-       err = follow_managed(path, nd);
-       if (likely(err > 0))
-               *inode = d_backing_inode(path->dentry);
-       return err;
+       return dentry;
 }
 
 /* Fast lookup failed, do it the slow way */
@@ -1862,7 +1827,7 @@ static int pick_link(struct nameidata *nd, struct path *link,
        return 1;
 }
 
-enum {WALK_FOLLOW = 1, WALK_MORE = 2};
+enum {WALK_FOLLOW = 1, WALK_MORE = 2, WALK_NOFOLLOW = 4};
 
 /*
  * Do we need to follow links? We _really_ want to be able
@@ -1870,30 +1835,34 @@ enum {WALK_FOLLOW = 1, WALK_MORE = 2};
  * so we keep a cache of "no, this doesn't need follow_link"
  * for the common case.
  */
-static inline int step_into(struct nameidata *nd, struct path *path,
-                           int flags, struct inode *inode, unsigned seq)
+static int step_into(struct nameidata *nd, int flags,
+                    struct dentry *dentry, struct inode *inode, unsigned seq)
 {
-       if (!(flags & WALK_MORE) && nd->depth)
-               put_link(nd);
-       if (likely(!d_is_symlink(path->dentry)) ||
-          !(flags & WALK_FOLLOW || nd->flags & LOOKUP_FOLLOW)) {
+       struct path path;
+       int err = handle_mounts(nd, dentry, &path, &inode, &seq);
+
+       if (err < 0)
+               return err;
+       if (likely(!d_is_symlink(path.dentry)) ||
+          !((flags & WALK_FOLLOW) || (nd->flags & LOOKUP_FOLLOW)) ||
+          (flags & WALK_NOFOLLOW)) {
                /* not a symlink or should not follow */
-               path_to_nameidata(path, nd);
+               path_to_nameidata(&path, nd);
                nd->inode = inode;
                nd->seq = seq;
                return 0;
        }
        /* make sure that d_is_symlink above matches inode */
        if (nd->flags & LOOKUP_RCU) {
-               if (read_seqcount_retry(&path->dentry->d_seq, seq))
+               if (read_seqcount_retry(&path.dentry->d_seq, seq))
                        return -ECHILD;
        }
-       return pick_link(nd, path, inode, seq);
+       return pick_link(nd, &path, inode, seq);
 }
 
 static int walk_component(struct nameidata *nd, int flags)
 {
-       struct path path;
+       struct dentry *dentry;
        struct inode *inode;
        unsigned seq;
        int err;
@@ -1903,30 +1872,22 @@ static int walk_component(struct nameidata *nd, int flags)
         * parent relationships.
         */
        if (unlikely(nd->last_type != LAST_NORM)) {
-               err = handle_dots(nd, nd->last_type);
                if (!(flags & WALK_MORE) && nd->depth)
                        put_link(nd);
+               err = handle_dots(nd, nd->last_type);
                return err;
        }
-       err = lookup_fast(nd, &path, &inode, &seq);
-       if (unlikely(err <= 0)) {
-               if (err < 0)
-                       return err;
-               path.dentry = lookup_slow(&nd->last, nd->path.dentry,
-                                         nd->flags);
-               if (IS_ERR(path.dentry))
-                       return PTR_ERR(path.dentry);
-
-               path.mnt = nd->path.mnt;
-               err = follow_managed(&path, nd);
-               if (unlikely(err < 0))
-                       return err;
-
-               seq = 0;        /* we are already out of RCU mode */
-               inode = d_backing_inode(path.dentry);
+       dentry = lookup_fast(nd, &inode, &seq);
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
+       if (unlikely(!dentry)) {
+               dentry = lookup_slow(&nd->last, nd->path.dentry, nd->flags);
+               if (IS_ERR(dentry))
+                       return PTR_ERR(dentry);
        }
-
-       return step_into(nd, &path, flags, inode, seq);
+       if (!(flags & WALK_MORE) && nd->depth)
+               put_link(nd);
+       return step_into(nd, flags, dentry, inode, seq);
 }
 
 /*
@@ -2393,31 +2354,10 @@ static inline int lookup_last(struct nameidata *nd)
 
 static int handle_lookup_down(struct nameidata *nd)
 {
-       struct path path = nd->path;
-       struct inode *inode = nd->inode;
-       unsigned seq = nd->seq;
-       int err;
-
-       if (nd->flags & LOOKUP_RCU) {
-               /*
-                * don't bother with unlazy_walk on failure - we are
-                * at the very beginning of walk, so we lose nothing
-                * if we simply redo everything in non-RCU mode
-                */
-               if (unlikely(!__follow_mount_rcu(nd, &path, &inode, &seq)))
-                       return -ECHILD;
-       } else {
-               dget(path.dentry);
-               err = follow_managed(&path, nd);
-               if (unlikely(err < 0))
-                       return err;
-               inode = d_backing_inode(path.dentry);
-               seq = 0;
-       }
-       path_to_nameidata(&path, nd);
-       nd->inode = inode;
-       nd->seq = seq;
-       return 0;
+       if (!(nd->flags & LOOKUP_RCU))
+               dget(nd->path.dentry);
+       return step_into(nd, WALK_NOFOLLOW,
+                       nd->path.dentry, nd->inode, nd->seq);
 }
 
 /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
@@ -3127,10 +3067,10 @@ static int may_o_create(const struct path *dir, struct dentry *dentry, umode_t m
  *
  * Returns an error code otherwise.
  */
-static int atomic_open(struct nameidata *nd, struct dentry *dentry,
-                       struct path *path, struct file *file,
-                       const struct open_flags *op,
-                       int open_flag, umode_t mode)
+static struct dentry *atomic_open(struct nameidata *nd, struct dentry *dentry,
+                                 struct file *file,
+                                 const struct open_flags *op,
+                                 int open_flag, umode_t mode)
 {
        struct dentry *const DENTRY_NOT_SET = (void *) -1UL;
        struct inode *dir =  nd->path.dentry->d_inode;
@@ -3171,17 +3111,15 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
                        }
                        if (file->f_mode & FMODE_CREATED)
                                fsnotify_create(dir, dentry);
-                       if (unlikely(d_is_negative(dentry))) {
+                       if (unlikely(d_is_negative(dentry)))
                                error = -ENOENT;
-                       } else {
-                               path->dentry = dentry;
-                               path->mnt = nd->path.mnt;
-                               return 0;
-                       }
                }
        }
-       dput(dentry);
-       return error;
+       if (error) {
+               dput(dentry);
+               dentry = ERR_PTR(error);
+       }
+       return dentry;
 }
 
 /*
@@ -3199,10 +3137,9 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
  *
  * An error code is returned on failure.
  */
-static int lookup_open(struct nameidata *nd, struct path *path,
-                       struct file *file,
-                       const struct open_flags *op,
-                       bool got_write)
+static struct dentry *lookup_open(struct nameidata *nd, struct file *file,
+                                 const struct open_flags *op,
+                                 bool got_write)
 {
        struct dentry *dir = nd->path.dentry;
        struct inode *dir_inode = dir->d_inode;
@@ -3213,7 +3150,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
        DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
 
        if (unlikely(IS_DEADDIR(dir_inode)))
-               return -ENOENT;
+               return ERR_PTR(-ENOENT);
 
        file->f_mode &= ~FMODE_CREATED;
        dentry = d_lookup(dir, &nd->last);
@@ -3221,7 +3158,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
                if (!dentry) {
                        dentry = d_alloc_parallel(dir, &nd->last, &wq);
                        if (IS_ERR(dentry))
-                               return PTR_ERR(dentry);
+                               return dentry;
                }
                if (d_in_lookup(dentry))
                        break;
@@ -3237,7 +3174,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
        }
        if (dentry->d_inode) {
                /* Cached positive dentry: will open in f_op->open */
-               goto out_no_open;
+               return dentry;
        }
 
        /*
@@ -3276,11 +3213,10 @@ static int lookup_open(struct nameidata *nd, struct path *path,
        }
 
        if (dir_inode->i_op->atomic_open) {
-               error = atomic_open(nd, dentry, path, file, op, open_flag,
-                                   mode);
-               if (unlikely(error == -ENOENT) && create_error)
-                       error = create_error;
-               return error;
+               dentry = atomic_open(nd, dentry, file, op, open_flag, mode);
+               if (unlikely(create_error) && dentry == ERR_PTR(-ENOENT))
+                       dentry = ERR_PTR(create_error);
+               return dentry;
        }
 
 no_open:
@@ -3316,14 +3252,11 @@ no_open:
                error = create_error;
                goto out_dput;
        }
-out_no_open:
-       path->dentry = dentry;
-       path->mnt = nd->path.mnt;
-       return 0;
+       return dentry;
 
 out_dput:
        dput(dentry);
-       return error;
+       return ERR_PTR(error);
 }
 
 /*
@@ -3341,13 +3274,15 @@ static int do_last(struct nameidata *nd,
        int acc_mode = op->acc_mode;
        unsigned seq;
        struct inode *inode;
-       struct path path;
+       struct dentry *dentry;
        int error;
 
        nd->flags &= ~LOOKUP_PARENT;
        nd->flags |= op->intent;
 
        if (nd->last_type != LAST_NORM) {
+               if (nd->depth)
+                       put_link(nd);
                error = handle_dots(nd, nd->last_type);
                if (unlikely(error))
                        return error;
@@ -3358,13 +3293,12 @@ static int do_last(struct nameidata *nd,
                if (nd->last.name[nd->last.len])
                        nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
                /* we _can_ be in RCU mode here */
-               error = lookup_fast(nd, &path, &inode, &seq);
-               if (likely(error > 0))
+               dentry = lookup_fast(nd, &inode, &seq);
+               if (IS_ERR(dentry))
+                       return PTR_ERR(dentry);
+               if (likely(dentry))
                        goto finish_lookup;
 
-               if (error < 0)
-                       return error;
-
                BUG_ON(nd->inode != dir->d_inode);
                BUG_ON(nd->flags & LOOKUP_RCU);
        } else {
@@ -3398,14 +3332,16 @@ static int do_last(struct nameidata *nd,
                inode_lock(dir->d_inode);
        else
                inode_lock_shared(dir->d_inode);
-       error = lookup_open(nd, &path, file, op, got_write);
+       dentry = lookup_open(nd, file, op, got_write);
        if (open_flag & O_CREAT)
                inode_unlock(dir->d_inode);
        else
                inode_unlock_shared(dir->d_inode);
 
-       if (error)
+       if (IS_ERR(dentry)) {
+               error = PTR_ERR(dentry);
                goto out;
+       }
 
        if (file->f_mode & FMODE_OPENED) {
                if ((file->f_mode & FMODE_CREATED) ||
@@ -3413,6 +3349,7 @@ static int do_last(struct nameidata *nd,
                        will_truncate = false;
 
                audit_inode(nd->name, file->f_path.dentry, 0);
+               dput(dentry);
                goto opened;
        }
 
@@ -3421,7 +3358,8 @@ static int do_last(struct nameidata *nd,
                open_flag &= ~O_TRUNC;
                will_truncate = false;
                acc_mode = 0;
-               path_to_nameidata(&path, nd);
+               dput(nd->path.dentry);
+               nd->path.dentry = dentry;
                goto finish_open_created;
        }
 
@@ -3435,26 +3373,17 @@ static int do_last(struct nameidata *nd,
                got_write = false;
        }
 
-       error = follow_managed(&path, nd);
-       if (unlikely(error < 0))
+finish_lookup:
+       if (nd->depth)
+               put_link(nd);
+       error = step_into(nd, 0, dentry, inode, seq);
+       if (unlikely(error))
                return error;
 
-       /*
-        * create/update audit record if it already exists.
-        */
-       audit_inode(nd->name, path.dentry, 0);
-
        if (unlikely((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT))) {
-               path_to_nameidata(&path, nd);
+               audit_inode(nd->name, nd->path.dentry, 0);
                return -EEXIST;
        }
-
-       seq = 0;        /* out of RCU mode, so the value doesn't matter */
-       inode = d_backing_inode(path.dentry);
-finish_lookup:
-       error = step_into(nd, &path, 0, inode, seq);
-       if (unlikely(error))
-               return error;
 finish_open:
        /* Why this, you ask?  _Now_ we might have grown LOOKUP_JUMPED... */
        error = complete_walk(nd);