Commit def4af30 authored by Al Viro's avatar Al Viro

Get rid of symlink body copying

Now that nd->last stays around until ->put_link() is called, we can
just postpone that ->put_link() in do_filp_open() a bit and don't
bother with copying.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 3866248e
...@@ -498,8 +498,6 @@ static int link_path_walk(const char *, struct nameidata *); ...@@ -498,8 +498,6 @@ static int link_path_walk(const char *, struct nameidata *);
static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link) static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
{ {
int res = 0;
char *name;
if (IS_ERR(link)) if (IS_ERR(link))
goto fail; goto fail;
...@@ -510,22 +508,7 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l ...@@ -510,22 +508,7 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l
path_get(&nd->root); path_get(&nd->root);
} }
res = link_path_walk(link, nd); return link_path_walk(link, nd);
if (nd->depth || res || nd->last_type!=LAST_NORM)
return res;
/*
* If it is an iterative symlinks resolution in open_namei() we
* have to copy the last component. And all that crap because of
* bloody create() on broken symlinks. Furrfu...
*/
name = __getname();
if (unlikely(!name)) {
path_put(&nd->path);
return -ENOMEM;
}
strcpy(name, nd->last.name);
nd->last.name = name;
return 0;
fail: fail:
path_put(&nd->path); path_put(&nd->path);
return PTR_ERR(link); return PTR_ERR(link);
...@@ -547,10 +530,10 @@ static inline void path_to_nameidata(struct path *path, struct nameidata *nd) ...@@ -547,10 +530,10 @@ static inline void path_to_nameidata(struct path *path, struct nameidata *nd)
nd->path.dentry = path->dentry; nd->path.dentry = path->dentry;
} }
static __always_inline int __do_follow_link(struct path *path, struct nameidata *nd) static __always_inline int
__do_follow_link(struct path *path, struct nameidata *nd, void **p)
{ {
int error; int error;
void *cookie;
struct dentry *dentry = path->dentry; struct dentry *dentry = path->dentry;
touch_atime(path->mnt, dentry); touch_atime(path->mnt, dentry);
...@@ -562,9 +545,9 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata ...@@ -562,9 +545,9 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata
} }
mntget(path->mnt); mntget(path->mnt);
nd->last_type = LAST_BIND; nd->last_type = LAST_BIND;
cookie = dentry->d_inode->i_op->follow_link(dentry, nd); *p = dentry->d_inode->i_op->follow_link(dentry, nd);
error = PTR_ERR(cookie); error = PTR_ERR(*p);
if (!IS_ERR(cookie)) { if (!IS_ERR(*p)) {
char *s = nd_get_link(nd); char *s = nd_get_link(nd);
error = 0; error = 0;
if (s) if (s)
...@@ -574,8 +557,6 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata ...@@ -574,8 +557,6 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata
if (error) if (error)
path_put(&nd->path); path_put(&nd->path);
} }
if (dentry->d_inode->i_op->put_link)
dentry->d_inode->i_op->put_link(dentry, nd, cookie);
} }
return error; return error;
} }
...@@ -589,6 +570,7 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata ...@@ -589,6 +570,7 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata
*/ */
static inline int do_follow_link(struct path *path, struct nameidata *nd) static inline int do_follow_link(struct path *path, struct nameidata *nd)
{ {
void *cookie;
int err = -ELOOP; int err = -ELOOP;
if (current->link_count >= MAX_NESTED_LINKS) if (current->link_count >= MAX_NESTED_LINKS)
goto loop; goto loop;
...@@ -602,7 +584,9 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd) ...@@ -602,7 +584,9 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd)
current->link_count++; current->link_count++;
current->total_link_count++; current->total_link_count++;
nd->depth++; nd->depth++;
err = __do_follow_link(path, nd); err = __do_follow_link(path, nd, &cookie);
if (!IS_ERR(cookie) && path->dentry->d_inode->i_op->put_link)
path->dentry->d_inode->i_op->put_link(path->dentry, nd, cookie);
path_put(path); path_put(path);
current->link_count--; current->link_count--;
nd->depth--; nd->depth--;
...@@ -1847,6 +1831,9 @@ reval: ...@@ -1847,6 +1831,9 @@ reval:
nd.flags |= LOOKUP_EXCL; nd.flags |= LOOKUP_EXCL;
filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
while (unlikely(!filp)) { /* trailing symlink */ while (unlikely(!filp)) { /* trailing symlink */
struct path holder;
struct inode *inode;
void *cookie;
error = -ELOOP; error = -ELOOP;
if ((open_flag & O_NOFOLLOW) || count++ == 32) if ((open_flag & O_NOFOLLOW) || count++ == 32)
goto exit_dput; goto exit_dput;
...@@ -1865,18 +1852,24 @@ reval: ...@@ -1865,18 +1852,24 @@ reval:
error = security_inode_follow_link(path.dentry, &nd); error = security_inode_follow_link(path.dentry, &nd);
if (error) if (error)
goto exit_dput; goto exit_dput;
error = __do_follow_link(&path, &nd); error = __do_follow_link(&path, &nd, &cookie);
path_put(&path); if (unlikely(error)) {
if (error) {
/* nd.path had been dropped */ /* nd.path had been dropped */
inode = path.dentry->d_inode;
if (!IS_ERR(cookie) && inode->i_op->put_link)
inode->i_op->put_link(path.dentry, &nd, cookie);
path_put(&path);
release_open_intent(&nd); release_open_intent(&nd);
filp = ERR_PTR(error); filp = ERR_PTR(error);
goto out; goto out;
} }
holder = path;
nd.flags &= ~LOOKUP_PARENT; nd.flags &= ~LOOKUP_PARENT;
filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
if (nd.last_type == LAST_NORM) inode = holder.dentry->d_inode;
__putname(nd.last.name); if (inode->i_op->put_link)
inode->i_op->put_link(holder.dentry, &nd, cookie);
path_put(&holder);
} }
out: out:
if (nd.root.mnt) if (nd.root.mnt)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment