From cad69b00e8d1fda4214a6048f8e164f776b2e19a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 18 Jun 2012 10:47:04 -0400 Subject: [PATCH] --- yaml --- r: 312933 b: refs/heads/master c: b5fb63c18315c5510c1d0636179c057e0c761c77 h: refs/heads/master i: 312931: 99ff91bef258678c66cf243973b18f2e499c9300 v: v3 --- [refs] | 2 +- trunk/fs/namei.c | 27 +++++++++++++++++---------- trunk/fs/proc/base.c | 3 +-- trunk/include/linux/namei.h | 2 ++ 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/[refs] b/[refs] index 6e2a4ed9d1b6..7d16cfffa40b 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 408ef013cc9e2f94a14f7ccbbe52ddfb18437a99 +refs/heads/master: b5fb63c18315c5510c1d0636179c057e0c761c77 diff --git a/trunk/fs/namei.c b/trunk/fs/namei.c index a9b94c62c303..0e1b9c3eb36d 100644 --- a/trunk/fs/namei.c +++ b/trunk/fs/namei.c @@ -586,6 +586,21 @@ static inline void path_to_nameidata(const struct path *path, nd->path.dentry = path->dentry; } +/* + * Helper to directly jump to a known parsed path from ->follow_link, + * caller must have taken a reference to path beforehand. + */ +void nd_jump_link(struct nameidata *nd, struct path *path) +{ + path_put(&nd->path); + + nd->path = *path; + nd->inode = nd->path.dentry->d_inode; + nd->flags |= LOOKUP_JUMPED; + + BUG_ON(nd->inode->i_op->follow_link); +} + static inline void put_link(struct nameidata *nd, struct path *link, void *cookie) { struct inode *inode = link->dentry->d_inode; @@ -630,17 +645,9 @@ follow_link(struct path *link, struct nameidata *nd, void **p) 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); } - if (unlikely(error)) - put_link(nd, link, *p); return error; diff --git a/trunk/fs/proc/base.c b/trunk/fs/proc/base.c index 3bd5ac1ff018..2772208338f8 100644 --- a/trunk/fs/proc/base.c +++ b/trunk/fs/proc/base.c @@ -1438,8 +1438,7 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) if (error) goto out; - path_put(&nd->path); - nd->path = path; + nd_jump_link(nd, &path); return NULL; out: return ERR_PTR(error); diff --git a/trunk/include/linux/namei.h b/trunk/include/linux/namei.h index f5931489e150..d2ef8b34b967 100644 --- a/trunk/include/linux/namei.h +++ b/trunk/include/linux/namei.h @@ -80,6 +80,8 @@ extern int follow_up(struct path *); extern struct dentry *lock_rename(struct dentry *, struct dentry *); extern void unlock_rename(struct dentry *, struct dentry *); +extern void nd_jump_link(struct nameidata *nd, struct path *path); + static inline void nd_set_link(struct nameidata *nd, char *path) { nd->saved_names[nd->depth] = path;