From af26eae1ae5e21d657d7b59b4d02c1d3e985cfb7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 26 Dec 2009 07:16:40 -0500 Subject: [PATCH] --- yaml --- r: 185929 b: refs/heads/master c: 806b681cbe588bebe8fe47dd24da62f2d1c55851 h: refs/heads/master i: 185927: 0c2661248a4912ba5841f5be36101cb37435784d v: v3 --- [refs] | 2 +- trunk/fs/namei.c | 83 ++++++++++++++++++++++-------------------------- 2 files changed, 39 insertions(+), 46 deletions(-) diff --git a/[refs] b/[refs] index 55d9798fbd68..c3847f65b4cd 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 10fa8e62f2bc33c452516585911f151d88389e4c +refs/heads/master: 806b681cbe588bebe8fe47dd24da62f2d1c55851 diff --git a/trunk/fs/namei.c b/trunk/fs/namei.c index 675a712137f1..08da937b1ee2 100644 --- a/trunk/fs/namei.c +++ b/trunk/fs/namei.c @@ -1844,17 +1844,38 @@ struct file *do_filp_open(int dfd, const char *pathname, if (open_flag & O_EXCL) nd.flags |= LOOKUP_EXCL; filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); - if (!filp) - goto do_link; - goto out; - -exit_dput: - path_put_conditional(&path, &nd); - if (!IS_ERR(nd.intent.open.file)) - release_open_intent(&nd); -exit_parent: - path_put(&nd.path); - filp = ERR_PTR(error); + while (unlikely(!filp)) { /* trailing symlink */ + error = -ELOOP; + if ((open_flag & O_NOFOLLOW) || count++ == 32) + goto exit_dput; + /* + * This is subtle. Instead of calling do_follow_link() we do + * the thing by hands. The reason is that this way we have zero + * link_count and path_walk() (called from ->follow_link) + * honoring LOOKUP_PARENT. After that we have the parent and + * last component, i.e. we are in the same situation as after + * the first path_walk(). Well, almost - if the last component + * is normal we get its copy stored in nd->last.name and we will + * have to putname() it when we are done. Procfs-like symlinks + * just set LAST_BIND. + */ + nd.flags |= LOOKUP_PARENT; + error = security_inode_follow_link(path.dentry, &nd); + if (error) + goto exit_dput; + error = __do_follow_link(&path, &nd); + path_put(&path); + if (error) { + /* nd.path had been dropped */ + release_open_intent(&nd); + filp = ERR_PTR(error); + goto out; + } + nd.flags &= ~LOOKUP_PARENT; + filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); + if (nd.last_type == LAST_NORM) + __putname(nd.last.name); + } out: if (nd.root.mnt) path_put(&nd.root); @@ -1864,41 +1885,13 @@ struct file *do_filp_open(int dfd, const char *pathname, } return filp; -do_link: - error = -ELOOP; - if ((open_flag & O_NOFOLLOW) || count++ == 32) - goto exit_dput; - /* - * This is subtle. Instead of calling do_follow_link() we do the - * thing by hands. The reason is that this way we have zero link_count - * and path_walk() (called from ->follow_link) honoring LOOKUP_PARENT. - * After that we have the parent and last component, i.e. - * we are in the same situation as after the first path_walk(). - * Well, almost - if the last component is normal we get its copy - * stored in nd->last.name and we will have to putname() it when we - * are done. Procfs-like symlinks just set LAST_BIND. - */ - nd.flags |= LOOKUP_PARENT; - error = security_inode_follow_link(path.dentry, &nd); - if (error) - goto exit_dput; - error = __do_follow_link(&path, &nd); - path_put(&path); - if (error) { - /* Does someone understand code flow here? Or it is only - * me so stupid? Anathema to whoever designed this non-sense - * with "intent.open". - */ +exit_dput: + path_put_conditional(&path, &nd); + if (!IS_ERR(nd.intent.open.file)) release_open_intent(&nd); - filp = ERR_PTR(error); - goto out; - } - nd.flags &= ~LOOKUP_PARENT; - filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); - if (nd.last_type == LAST_NORM) - __putname(nd.last.name); - if (!filp) - goto do_link; +exit_parent: + path_put(&nd.path); + filp = ERR_PTR(error); goto out; }