]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/namei.c
vfs: do_last(): inline lookup_slow()
[karo-tx-linux.git] / fs / namei.c
index 7d694194024ac4d2459e7cc3d60014bdff64e3ba..68742e3cb98da548df319e86831ebbceca5e7870 100644 (file)
@@ -605,7 +605,7 @@ static inline void path_to_nameidata(const struct path *path,
 static inline void put_link(struct nameidata *nd, struct path *link, void *cookie)
 {
        struct inode *inode = link->dentry->d_inode;
-       if (!IS_ERR(cookie) && inode->i_op->put_link)
+       if (inode->i_op->put_link)
                inode->i_op->put_link(link->dentry, nd, cookie);
        path_put(link);
 }
@@ -613,19 +613,19 @@ static inline void put_link(struct nameidata *nd, struct path *link, void *cooki
 static __always_inline int
 follow_link(struct path *link, struct nameidata *nd, void **p)
 {
-       int error;
        struct dentry *dentry = link->dentry;
+       int error;
+       char *s;
 
        BUG_ON(nd->flags & LOOKUP_RCU);
 
        if (link->mnt == nd->path.mnt)
                mntget(link->mnt);
 
-       if (unlikely(current->total_link_count >= 40)) {
-               *p = ERR_PTR(-ELOOP); /* no ->put_link(), please */
-               path_put(&nd->path);
-               return -ELOOP;
-       }
+       error = -ELOOP;
+       if (unlikely(current->total_link_count >= 40))
+               goto out_put_nd_path;
+
        cond_resched();
        current->total_link_count++;
 
@@ -633,30 +633,37 @@ follow_link(struct path *link, struct nameidata *nd, void **p)
        nd_set_link(nd, NULL);
 
        error = security_inode_follow_link(link->dentry, nd);
-       if (error) {
-               *p = ERR_PTR(error); /* no ->put_link(), please */
-               path_put(&nd->path);
-               return error;
-       }
+       if (error)
+               goto out_put_nd_path;
 
        nd->last_type = LAST_BIND;
        *p = dentry->d_inode->i_op->follow_link(dentry, nd);
        error = PTR_ERR(*p);
-       if (!IS_ERR(*p)) {
-               char *s = nd_get_link(nd);
-               error = 0;
-               if (s)
-                       error = __vfs_follow_link(nd, s);
-               else if (nd->last_type == LAST_BIND) {
-                       nd->flags |= LOOKUP_JUMPED;
-                       nd->inode = nd->path.dentry->d_inode;
-                       if (nd->inode->i_op->follow_link) {
-                               /* stepped on a _really_ weird one */
-                               path_put(&nd->path);
-                               error = -ELOOP;
-                       }
+       if (IS_ERR(*p))
+               goto out_put_link;
+
+       error = 0;
+       s = nd_get_link(nd);
+       if (s) {
+               error = __vfs_follow_link(nd, s);
+       } else if (nd->last_type == LAST_BIND) {
+               nd->flags |= LOOKUP_JUMPED;
+               nd->inode = nd->path.dentry->d_inode;
+               if (nd->inode->i_op->follow_link) {
+                       /* stepped on a _really_ weird one */
+                       path_put(&nd->path);
+                       error = -ELOOP;
                }
        }
+       if (unlikely(error))
+               put_link(nd, link, *p);
+
+       return error;
+
+out_put_nd_path:
+       path_put(&nd->path);
+out_put_link:
+       path_put(link);
        return error;
 }
 
@@ -1383,9 +1390,10 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd)
                void *cookie;
 
                res = follow_link(&link, nd, &cookie);
-               if (!res)
-                       res = walk_component(nd, path, &nd->last,
-                                            nd->last_type, LOOKUP_FOLLOW);
+               if (res)
+                       break;
+               res = walk_component(nd, path, &nd->last,
+                                    nd->last_type, LOOKUP_FOLLOW);
                put_link(nd, &link, cookie);
        } while (res > 0);
 
@@ -1777,8 +1785,9 @@ static int path_lookupat(int dfd, const char *name,
                        struct path link = path;
                        nd->flags |= LOOKUP_PARENT;
                        err = follow_link(&link, nd, &cookie);
-                       if (!err)
-                               err = lookup_last(nd, &path);
+                       if (err)
+                               break;
+                       err = lookup_last(nd, &path);
                        put_link(nd, &link, cookie);
                }
        }
@@ -2245,9 +2254,22 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
                        if (error < 0)
                                goto exit;
 
-                       error = lookup_slow(nd, &nd->last, path);
-                       if (error < 0)
+                       BUG_ON(nd->inode != dir->d_inode);
+
+                       mutex_lock(&dir->d_inode->i_mutex);
+                       dentry = __lookup_hash(&nd->last, dir, nd);
+                       mutex_unlock(&dir->d_inode->i_mutex);
+                       error = PTR_ERR(dentry);
+                       if (IS_ERR(dentry))
                                goto exit;
+                       path->mnt = nd->path.mnt;
+                       path->dentry = dentry;
+                       error = follow_managed(path, nd->flags);
+                       if (unlikely(error < 0))
+                               goto exit_dput;
+
+                       if (error)
+                               nd->flags |= LOOKUP_JUMPED;
 
                        inode = path->dentry->d_inode;
                }
@@ -2475,9 +2497,8 @@ static struct file *path_openat(int dfd, const char *pathname,
                nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
                error = follow_link(&link, nd, &cookie);
                if (unlikely(error))
-                       filp = ERR_PTR(error);
-               else
-                       filp = do_last(nd, &path, op, pathname);
+                       goto out_filp;
+               filp = do_last(nd, &path, op, pathname);
                put_link(nd, &link, cookie);
        }
 out: