From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755662AbbDTSTS (ORCPT ); Mon, 20 Apr 2015 14:19:18 -0400 Received: from zeniv.linux.org.uk ([195.92.253.2]:34740 "EHLO ZenIV.linux.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751309AbbDTSNL (ORCPT ); Mon, 20 Apr 2015 14:13:11 -0400 From: Al Viro To: Linus Torvalds Cc: Neil Brown , linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [PATCH 08/24] namei.c: separate the parts of follow_link() that find the link body Date: Mon, 20 Apr 2015 19:12:52 +0100 Message-Id: <1429553588-24764-8-git-send-email-viro@ZenIV.linux.org.uk> X-Mailer: git-send-email 1.7.7.6 In-Reply-To: <20150420181222.GK889@ZenIV.linux.org.uk> References: <20150420181222.GK889@ZenIV.linux.org.uk> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Al Viro Calling conventions for ->follow_link() are rather unfortunate. It would be better to have it return ERR_PTR(error) on error, NULL on jumps and link body for normal symlinks. What we currently return (opaque pointer used by ->put_link() once we are done) should've been given to analogue (and replacement) of nd_set_link(). For now let's just split a piece of fs/namei.c:follow_link() that does obtaining the link body into a separate function. When we get around to changing ->follow_link() API, the changes will be contained in that sucker. follow_link() itself converted to calling get_link() and then doing the body traversal (if any). The next step will expand follow_link() call in link_path_walk() and this helps to keep the size down... Signed-off-by: Al Viro --- fs/namei.c | 79 +++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index a1f6271..e07bf5c 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -871,21 +871,23 @@ static int may_linkat(struct path *link) return -EPERM; } -static __always_inline int -follow_link(struct path *link, struct nameidata *nd, void **p) +static __always_inline char * +get_link(struct path *link, struct nameidata *nd, void **p) { struct dentry *dentry = link->dentry; + struct inode *inode = dentry->d_inode; + void *cookie; int error; - char *s; + char *res; BUG_ON(nd->flags & LOOKUP_RCU); if (link->mnt == nd->path.mnt) mntget(link->mnt); - error = -ELOOP; + res = ERR_PTR(-ELOOP); if (unlikely(nd->total_link_count >= 40)) - goto out_put_nd_path; + goto out; cond_resched(); nd->total_link_count++; @@ -893,44 +895,53 @@ follow_link(struct path *link, struct nameidata *nd, void **p) touch_atime(link); nd_set_link(NULL); - error = security_inode_follow_link(link->dentry); + error = security_inode_follow_link(dentry); + res = ERR_PTR(error); if (error) - goto out_put_nd_path; + goto out; nd->last_type = LAST_BIND; - *p = dentry->d_inode->i_op->follow_link(dentry); - error = PTR_ERR(*p); - if (IS_ERR(*p)) - goto out_put_nd_path; + res = cookie = inode->i_op->follow_link(dentry); + if (IS_ERR(cookie)) + goto out; - error = 0; - s = nd_get_link(nd); - if (s) { - if (unlikely(IS_ERR(s))) { - path_put(&nd->path); - put_link(nd, link, *p); - return PTR_ERR(s); - } - if (*s == '/') { - if (!nd->root.mnt) - set_root(nd); - path_put(&nd->path); - nd->path = nd->root; - path_get(&nd->root); - nd->flags |= LOOKUP_JUMPED; - } - nd->inode = nd->path.dentry->d_inode; - error = link_path_walk(s, nd); - if (unlikely(error)) - put_link(nd, link, *p); + res = nd_get_link(nd); + if (!IS_ERR(res)) { + *p = cookie; + return res; } - return error; - -out_put_nd_path: + if (inode->i_op->put_link) + inode->i_op->put_link(dentry, res, cookie); +out: *p = NULL; path_put(&nd->path); path_put(link); + return res; +} + +static __always_inline int +follow_link(struct path *link, struct nameidata *nd, void **p) +{ + char *s = get_link(link, nd, p); + int error; + + if (unlikely(IS_ERR(s))) + return PTR_ERR(s); + if (unlikely(!s)) + return 0; + if (*s == '/') { + if (!nd->root.mnt) + set_root(nd); + path_put(&nd->path); + nd->path = nd->root; + path_get(&nd->root); + nd->flags |= LOOKUP_JUMPED; + } + nd->inode = nd->path.dentry->d_inode; + error = link_path_walk(s, nd); + if (unlikely(error)) + put_link(nd, link, *p); return error; } -- 2.1.4