All of lore.kernel.org
 help / color / mirror / Atom feed
From: NeilBrown <neilb@suse.de>
To: Al Viro <viro@ZenIV.linux.org.uk>
Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 01/13] VFS: replace {, total_}link_count in task_struct with pointer to nameidata
Date: Mon, 16 Mar 2015 15:43:19 +1100	[thread overview]
Message-ID: <20150316044319.23648.13820.stgit@notabene.brown> (raw)
In-Reply-To: <20150316043602.23648.52734.stgit@notabene.brown>

task_struct currently contains two ad-hoc members for use by
the VFS: link_count and total_link_count.
These are only interesting to fs/namei.c, so exposing them
explicitly is poor laying - and has resulted in some questionable
code in staging/lustre.

This patches replaces those with a single pointer to 'struct
nameidata'.
This structure represents the current filename lookup of which
there can only be one per process, and is a natural place to
store link_count and total_link_count.

This will allow the current "nameidata" argument to all
follow_link operations to be removed as current->nameidata
can be used instead.

As there are occasional circumstances where pathname lookup can
recurse, such as through kern_path_locked, we always save and old
current->nameidata (if there is one) when setting a new value, and
make sure any active link_counts are preserved.

Suggested-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: NeilBrown <neilb@suse.de>
---
 drivers/staging/lustre/lustre/llite/symlink.c |   16 ++-------
 fs/namei.c                                    |   47 +++++++++++++++++++------
 include/linux/sched.h                         |    2 +
 3 files changed, 41 insertions(+), 24 deletions(-)

diff --git a/drivers/staging/lustre/lustre/llite/symlink.c b/drivers/staging/lustre/lustre/llite/symlink.c
index 686b6a574cc5..d7a1c6c48846 100644
--- a/drivers/staging/lustre/lustre/llite/symlink.c
+++ b/drivers/staging/lustre/lustre/llite/symlink.c
@@ -126,18 +126,10 @@ static void *ll_follow_link(struct dentry *dentry, struct nameidata *nd)
 	char *symname = NULL;
 
 	CDEBUG(D_VFSTRACE, "VFS Op\n");
-	/* Limit the recursive symlink depth to 5 instead of default
-	 * 8 links when kernel has 4k stack to prevent stack overflow.
-	 * For 8k stacks we need to limit it to 7 for local servers. */
-	if (THREAD_SIZE < 8192 && current->link_count >= 6) {
-		rc = -ELOOP;
-	} else if (THREAD_SIZE == 8192 && current->link_count >= 8) {
-		rc = -ELOOP;
-	} else {
-		ll_inode_size_lock(inode);
-		rc = ll_readlink_internal(inode, &request, &symname);
-		ll_inode_size_unlock(inode);
-	}
+	ll_inode_size_lock(inode);
+	rc = ll_readlink_internal(inode, &request, &symname);
+	ll_inode_size_unlock(inode);
+
 	if (rc) {
 		ptlrpc_req_finished(request);
 		request = NULL;
diff --git a/fs/namei.c b/fs/namei.c
index c83145af4bfc..184aaafffaa9 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -502,10 +502,27 @@ struct nameidata {
 	unsigned	seq, m_seq;
 	int		last_type;
 	unsigned	depth;
+	int link_count, total_link_count;
 	struct file	*base;
 	char *saved_names[MAX_NESTED_LINKS + 1];
 };
 
+static struct nameidata *set_nameidata(struct nameidata *p)
+{
+	struct nameidata *old = current->nameidata;
+	current->nameidata = p;
+	if (p) {
+		if (!old) {
+			p->link_count = 0;
+			p->total_link_count = 0;
+		} else {
+			p->link_count = old->link_count;
+			p->total_link_count = old->total_link_count;
+		}
+	}
+	return old;
+}
+
 /*
  * Path walking has 2 modes, rcu-walk and ref-walk (see
  * Documentation/filesystems/path-lookup.txt).  In situations when we can't
@@ -863,11 +880,11 @@ follow_link(struct path *link, struct nameidata *nd, void **p)
 		mntget(link->mnt);
 
 	error = -ELOOP;
-	if (unlikely(current->total_link_count >= 40))
+	if (unlikely(current->nameidata->total_link_count >= 40))
 		goto out_put_nd_path;
 
 	cond_resched();
-	current->total_link_count++;
+	current->nameidata->total_link_count++;
 
 	touch_atime(link);
 	nd_set_link(nd, NULL);
@@ -991,8 +1008,8 @@ static int follow_automount(struct path *path, unsigned flags,
 	    path->dentry->d_inode)
 		return -EISDIR;
 
-	current->total_link_count++;
-	if (current->total_link_count >= 40)
+	current->nameidata->total_link_count++;
+	if (current->nameidata->total_link_count >= 40)
 		return -ELOOP;
 
 	mnt = path->dentry->d_op->d_automount(path);
@@ -1621,7 +1638,7 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd)
 {
 	int res;
 
-	if (unlikely(current->link_count >= MAX_NESTED_LINKS)) {
+	if (unlikely(current->nameidata->link_count >= MAX_NESTED_LINKS)) {
 		path_put_conditional(path, nd);
 		path_put(&nd->path);
 		return -ELOOP;
@@ -1629,7 +1646,7 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd)
 	BUG_ON(nd->depth >= MAX_NESTED_LINKS);
 
 	nd->depth++;
-	current->link_count++;
+	current->nameidata->link_count++;
 
 	do {
 		struct path link = *path;
@@ -1642,7 +1659,7 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd)
 		put_link(nd, &link, cookie);
 	} while (res > 0);
 
-	current->link_count--;
+	current->nameidata->link_count--;
 	nd->depth--;
 	return res;
 }
@@ -1948,7 +1965,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
 	rcu_read_unlock();
 	return -ECHILD;
 done:
-	current->total_link_count = 0;
+	current->nameidata->total_link_count = 0;
 	return link_path_walk(name, nd);
 }
 
@@ -2027,7 +2044,9 @@ static int path_lookupat(int dfd, const char *name,
 static int filename_lookup(int dfd, struct filename *name,
 				unsigned int flags, struct nameidata *nd)
 {
-	int retval = path_lookupat(dfd, name->name, flags | LOOKUP_RCU, nd);
+	int retval;
+	struct nameidata *saved_nd = set_nameidata(nd);
+	retval = path_lookupat(dfd, name->name, flags | LOOKUP_RCU, nd);
 	if (unlikely(retval == -ECHILD))
 		retval = path_lookupat(dfd, name->name, flags, nd);
 	if (unlikely(retval == -ESTALE))
@@ -2036,6 +2055,7 @@ static int filename_lookup(int dfd, struct filename *name,
 
 	if (likely(!retval))
 		audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT);
+	set_nameidata(saved_nd);
 	return retval;
 }
 
@@ -2343,7 +2363,7 @@ out:
 static int
 path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags)
 {
-	struct nameidata nd;
+	struct nameidata nd, *saved = set_nameidata(&nd);
 	int err;
 
 	err = path_init(dfd, name, flags, &nd);
@@ -2366,6 +2386,7 @@ path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags
 	}
 out:
 	path_cleanup(&nd);
+	set_nameidata(saved);
 	return err;
 }
 
@@ -3217,12 +3238,14 @@ static struct file *path_openat(int dfd, struct filename *pathname,
 	struct path path;
 	int opened = 0;
 	int error;
+	struct nameidata *saved_nd;
 
 	file = get_empty_filp();
 	if (IS_ERR(file))
 		return file;
 
 	file->f_flags = op->open_flag;
+	saved_nd = set_nameidata(nd);
 
 	if (unlikely(file->f_flags & __O_TMPFILE)) {
 		error = do_tmpfile(dfd, pathname, nd, flags, op, file, &opened);
@@ -3269,6 +3292,7 @@ out:
 		}
 		file = ERR_PTR(error);
 	}
+	set_nameidata(saved_nd);
 	return file;
 }
 
@@ -4429,7 +4453,7 @@ EXPORT_SYMBOL(readlink_copy);
  */
 int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
 {
-	struct nameidata nd;
+	struct nameidata nd, *saved = set_nameidata(&nd);
 	void *cookie;
 	int res;
 
@@ -4441,6 +4465,7 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
 	res = readlink_copy(buffer, buflen, nd_get_link(&nd));
 	if (dentry->d_inode->i_op->put_link)
 		dentry->d_inode->i_op->put_link(dentry, &nd, cookie);
+	set_nameidata(saved);
 	return res;
 }
 EXPORT_SYMBOL(generic_readlink);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 6d77432e14ff..b88b9eea169a 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1447,7 +1447,7 @@ struct task_struct {
 				       it with task_lock())
 				     - initialized normally by setup_new_exec */
 /* file system info */
-	int link_count, total_link_count;
+	struct nameidata *nameidata;
 #ifdef CONFIG_SYSVIPC
 /* ipc stuff */
 	struct sysv_sem sysvsem;



  reply	other threads:[~2015-03-16  4:44 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-16  4:43 [PATCH 00/13] Support follow_link in RCU-walk. - V2 NeilBrown
2015-03-16  4:43 ` NeilBrown [this message]
2015-03-16 19:46   ` [PATCH 01/13] VFS: replace {, total_}link_count in task_struct with pointer to nameidata Al Viro
2015-03-16  4:43 ` [PATCH 02/13] VFS: make all ->follow_link handlers aware for LOOKUP_RCU NeilBrown
2015-03-16  4:43 ` [PATCH 04/13] security/selinux: check for LOOKUP_RCU in _follow_link NeilBrown
2015-03-16 21:00   ` Al Viro
2015-03-20  4:39     ` NeilBrown
2015-03-20  5:12       ` Al Viro
2015-03-16  4:43 ` [PATCH 03/13] VFS: remove nameidata args from ->follow_link and ->put_link NeilBrown
2015-03-16 20:47   ` Al Viro
2015-03-16  4:43 ` [PATCH 05/13] VFS/namei: use terminate_walk when symlink lookup fails NeilBrown
2015-03-16  4:43 ` [PATCH 12/13] XFS: allow follow_link to often succeed in RCU-walk NeilBrown
2015-03-16 22:37   ` Al Viro
2015-03-16  4:43 ` [PATCH 10/13] VFS/namei: handle LOOKUP_RCU in page_follow_link_light NeilBrown
2015-03-16 22:50   ` Al Viro
2015-03-19 22:38     ` NeilBrown
2015-03-19 23:46       ` Al Viro
2015-03-16  4:43 ` [PATCH 11/13] xfs: use RCU to free 'struct xfs_mount' NeilBrown
2015-03-16  4:43 ` [PATCH 13/13] NFS: support LOOKUP_RCU in nfs_follow_link NeilBrown
2015-03-16  4:43 ` [PATCH 06/13] VFS/namei: new flag to support RCU symlinks: LOOKUP_LINK_RCU NeilBrown
2015-03-16 22:33   ` Al Viro
2015-03-17  0:59     ` Al Viro
2015-03-16  4:43 ` [PATCH 07/13] VFS/namei: abort RCU-walk on symlink if atime needs updating NeilBrown
2015-03-16  4:43 ` [PATCH 09/13] VFS/namei: enable RCU-walk when following symlinks NeilBrown
2015-03-16 22:44   ` Al Viro
2015-03-16  4:43 ` [PATCH 08/13] VFS/namei: enhance follow_link to support RCU-walk NeilBrown
2015-03-16 19:14 ` [PATCH 00/13] Support follow_link in RCU-walk. - V2 Al Viro

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20150316044319.23648.13820.stgit@notabene.brown \
    --to=neilb@suse.de \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=viro@ZenIV.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.