All of lore.kernel.org
 help / color / mirror / Atom feed
From: Linus Torvalds <torvalds@linux-foundation.org>
To: Al Viro <viro@zeniv.linux.org.uk>
Cc: Jia He <justin.he@arm.com>, Petr Mladek <pmladek@suse.com>,
	Steven Rostedt <rostedt@goodmis.org>,
	Sergey Senozhatsky <senozhatsky@chromium.org>,
	Andy Shevchenko <andriy.shevchenko@linux.intel.com>,
	Rasmus Villemoes <linux@rasmusvillemoes.dk>,
	Jonathan Corbet <corbet@lwn.net>, Al Viro <viro@ftp.linux.org.uk>,
	Heiko Carstens <hca@linux.ibm.com>,
	Vasily Gorbik <gor@linux.ibm.com>,
	Christian Borntraeger <borntraeger@de.ibm.com>,
	"Eric W . Biederman" <ebiederm@xmission.com>,
	"Darrick J. Wong" <darrick.wong@oracle.com>,
	"Peter Zijlstra (Intel)" <peterz@infradead.org>,
	Ira Weiny <ira.weiny@intel.com>,
	Eric Biggers <ebiggers@google.com>,
	"Ahmed S. Darwish" <a.darwish@linutronix.de>,
	"open list:DOCUMENTATION" <linux-doc@vger.kernel.org>,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	linux-s390 <linux-s390@vger.kernel.org>,
	linux-fsdevel <linux-fsdevel@vger.kernel.org>
Subject: Re: [PATCH RFC 1/3] fs: introduce helper d_path_fast()
Date: Sat, 8 May 2021 13:39:45 -0700	[thread overview]
Message-ID: <CAHk-=whZhNXiOGgw8mXG+PTpGvxnRG1v5_GjtjHpoYXd2Fn_Ow@mail.gmail.com> (raw)
In-Reply-To: <YJbivrA4Awp4FXo8@zeniv-ca.linux.org.uk>

[-- Attachment #1: Type: text/plain, Size: 829 bytes --]

On Sat, May 8, 2021 at 12:13 PM Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> Potentiallty delicate question is how to pass bptr/blen to the caller
> of that helper...

So I was thinking something like this patch..

THIS IS TOTALLY UNTESTED!

I've basically introduced a "struct prepend_buffer" that acts as that
"end,len" pair and that gets passed around. It builds cleanly for me,
which actually makes me fairly happy that it might even be close
right, because the calling conventions would catch any mistake.

It looks superficially sane to me, but again - untested.

The patch ended up being bigger than I expected, but it's all fairly
straightforward - just munging the calling conventions.

Oh, and I did extract out the core of "prepend_path()" into
"prepend_entries()" just to show how it would work.

              Linus

[-- Attachment #2: patch.diff --]
[-- Type: text/x-patch, Size: 11058 bytes --]

 fs/d_path.c | 227 ++++++++++++++++++++++++++++++++----------------------------
 1 file changed, 123 insertions(+), 104 deletions(-)

diff --git a/fs/d_path.c b/fs/d_path.c
index 270d62133996..47eb29524271 100644
--- a/fs/d_path.c
+++ b/fs/d_path.c
@@ -8,13 +8,18 @@
 #include <linux/prefetch.h>
 #include "mount.h"
 
-static int prepend(char **buffer, int *buflen, const char *str, int namelen)
+struct prepend_buffer {
+	char *ptr;
+	int len;
+};
+
+static int prepend(struct prepend_buffer *b, const char *str, int namelen)
 {
-	*buflen -= namelen;
-	if (*buflen < 0)
+	b->len -= namelen;
+	if (b->len < 0)
 		return -ENAMETOOLONG;
-	*buffer -= namelen;
-	memcpy(*buffer, str, namelen);
+	b->ptr -= namelen;
+	memcpy(b->ptr, str, namelen);
 	return 0;
 }
 
@@ -35,16 +40,16 @@ static int prepend(char **buffer, int *buflen, const char *str, int namelen)
  *
  * Load acquire is needed to make sure that we see that terminating NUL.
  */
-static int prepend_name(char **buffer, int *buflen, const struct qstr *name)
+static int prepend_name(struct prepend_buffer *b, const struct qstr *name)
 {
 	const char *dname = smp_load_acquire(&name->name); /* ^^^ */
 	u32 dlen = READ_ONCE(name->len);
 	char *p;
 
-	*buflen -= dlen + 1;
-	if (*buflen < 0)
+	b->len -= dlen + 1;
+	if (b->len < 0)
 		return -ENAMETOOLONG;
-	p = *buffer -= dlen + 1;
+	p = b->ptr -= dlen + 1;
 	*p++ = '/';
 	while (dlen--) {
 		char c = *dname++;
@@ -55,6 +60,50 @@ static int prepend_name(char **buffer, int *buflen, const struct qstr *name)
 	return 0;
 }
 
+static inline int prepend_entries(struct prepend_buffer *b, const struct path *path, const struct path *root, struct mount *mnt)
+{
+	struct dentry *dentry = path->dentry;
+	struct vfsmount *vfsmnt = path->mnt;
+
+	while (dentry != root->dentry || vfsmnt != root->mnt) {
+		int error;
+		struct dentry * parent;
+
+		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
+			struct mount *parent = READ_ONCE(mnt->mnt_parent);
+			struct mnt_namespace *mnt_ns;
+
+			/* Escaped? */
+			if (dentry != vfsmnt->mnt_root)
+				return 3;
+
+			/* Global root? */
+			if (mnt != parent) {
+				dentry = READ_ONCE(mnt->mnt_mountpoint);
+				mnt = parent;
+				vfsmnt = &mnt->mnt;
+				continue;
+			}
+			mnt_ns = READ_ONCE(mnt->mnt_ns);
+			/* open-coded is_mounted() to use local mnt_ns */
+			if (!IS_ERR_OR_NULL(mnt_ns) && !is_anon_ns(mnt_ns))
+				return 1;	// absolute root
+
+			return 2;		// detached or not attached yet
+			break;
+		}
+		parent = dentry->d_parent;
+		prefetch(parent);
+		error = prepend_name(b, &dentry->d_name);
+		if (error)
+			break;
+
+		dentry = parent;
+	}
+	return 0;
+}
+
+
 /**
  * prepend_path - Prepend path string to a buffer
  * @path: the dentry/vfsmount to report
@@ -74,15 +123,12 @@ static int prepend_name(char **buffer, int *buflen, const struct qstr *name)
  */
 static int prepend_path(const struct path *path,
 			const struct path *root,
-			char **buffer, int *buflen)
+			struct prepend_buffer *orig)
 {
-	struct dentry *dentry;
-	struct vfsmount *vfsmnt;
 	struct mount *mnt;
 	int error = 0;
 	unsigned seq, m_seq = 0;
-	char *bptr;
-	int blen;
+	struct prepend_buffer b;
 
 	rcu_read_lock();
 restart_mnt:
@@ -90,50 +136,12 @@ static int prepend_path(const struct path *path,
 	seq = 0;
 	rcu_read_lock();
 restart:
-	bptr = *buffer;
-	blen = *buflen;
-	error = 0;
-	dentry = path->dentry;
-	vfsmnt = path->mnt;
-	mnt = real_mount(vfsmnt);
+	b = *orig;
+	mnt = real_mount(path->mnt);
 	read_seqbegin_or_lock(&rename_lock, &seq);
-	while (dentry != root->dentry || vfsmnt != root->mnt) {
-		struct dentry * parent;
 
-		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
-			struct mount *parent = READ_ONCE(mnt->mnt_parent);
-			struct mnt_namespace *mnt_ns;
+	error = prepend_entries(&b, path, root, mnt);
 
-			/* Escaped? */
-			if (dentry != vfsmnt->mnt_root) {
-				bptr = *buffer;
-				blen = *buflen;
-				error = 3;
-				break;
-			}
-			/* Global root? */
-			if (mnt != parent) {
-				dentry = READ_ONCE(mnt->mnt_mountpoint);
-				mnt = parent;
-				vfsmnt = &mnt->mnt;
-				continue;
-			}
-			mnt_ns = READ_ONCE(mnt->mnt_ns);
-			/* open-coded is_mounted() to use local mnt_ns */
-			if (!IS_ERR_OR_NULL(mnt_ns) && !is_anon_ns(mnt_ns))
-				error = 1;	// absolute root
-			else
-				error = 2;	// detached or not attached yet
-			break;
-		}
-		parent = dentry->d_parent;
-		prefetch(parent);
-		error = prepend_name(&bptr, &blen, &dentry->d_name);
-		if (error)
-			break;
-
-		dentry = parent;
-	}
 	if (!(seq & 1))
 		rcu_read_unlock();
 	if (need_seqretry(&rename_lock, seq)) {
@@ -150,14 +158,17 @@ static int prepend_path(const struct path *path,
 	}
 	done_seqretry(&mount_lock, m_seq);
 
-	if (error >= 0 && bptr == *buffer) {
-		if (--blen < 0)
+	// Escaped? No path
+	if (error == 3)
+		b = *orig;
+
+	if (error >= 0 && b.ptr == orig->ptr) {
+		if (--b.len < 0)
 			error = -ENAMETOOLONG;
 		else
-			*--bptr = '/';
+			*--b.ptr = '/';
 	}
-	*buffer = bptr;
-	*buflen = blen;
+	*orig = b;
 	return error;
 }
 
@@ -181,34 +192,34 @@ char *__d_path(const struct path *path,
 	       const struct path *root,
 	       char *buf, int buflen)
 {
-	char *res = buf + buflen;
+	struct prepend_buffer b = { buf + buflen, buflen };
 	int error;
 
-	prepend(&res, &buflen, "\0", 1);
-	error = prepend_path(path, root, &res, &buflen);
+	prepend(&b, "\0", 1);
+	error = prepend_path(path, root, &b);
 
 	if (error < 0)
 		return ERR_PTR(error);
 	if (error > 0)
 		return NULL;
-	return res;
+	return b.ptr;
 }
 
 char *d_absolute_path(const struct path *path,
 	       char *buf, int buflen)
 {
 	struct path root = {};
-	char *res = buf + buflen;
+	struct prepend_buffer b = { buf + buflen, buflen };
 	int error;
 
-	prepend(&res, &buflen, "\0", 1);
-	error = prepend_path(path, &root, &res, &buflen);
+	prepend(&b, "\0", 1);
+	error = prepend_path(path, &root, &b);
 
 	if (error > 1)
 		error = -EINVAL;
 	if (error < 0)
 		return ERR_PTR(error);
-	return res;
+	return b.ptr;
 }
 
 /*
@@ -216,21 +227,21 @@ char *d_absolute_path(const struct path *path,
  */
 static int path_with_deleted(const struct path *path,
 			     const struct path *root,
-			     char **buf, int *buflen)
+			     struct prepend_buffer *b)
 {
-	prepend(buf, buflen, "\0", 1);
+	prepend(b, "\0", 1);
 	if (d_unlinked(path->dentry)) {
-		int error = prepend(buf, buflen, " (deleted)", 10);
+		int error = prepend(b, " (deleted)", 10);
 		if (error)
 			return error;
 	}
 
-	return prepend_path(path, root, buf, buflen);
+	return prepend_path(path, root, b);
 }
 
-static int prepend_unreachable(char **buffer, int *buflen)
+static int prepend_unreachable(struct prepend_buffer *b)
 {
-	return prepend(buffer, buflen, "(unreachable)", 13);
+	return prepend(b, "(unreachable)", 13);
 }
 
 static void get_fs_root_rcu(struct fs_struct *fs, struct path *root)
@@ -261,7 +272,7 @@ static void get_fs_root_rcu(struct fs_struct *fs, struct path *root)
  */
 char *d_path(const struct path *path, char *buf, int buflen)
 {
-	char *res = buf + buflen;
+	struct prepend_buffer b = { buf + buflen, buflen };
 	struct path root;
 	int error;
 
@@ -282,12 +293,12 @@ char *d_path(const struct path *path, char *buf, int buflen)
 
 	rcu_read_lock();
 	get_fs_root_rcu(current->fs, &root);
-	error = path_with_deleted(path, &root, &res, &buflen);
+	error = path_with_deleted(path, &root, &b);
 	rcu_read_unlock();
 
 	if (error < 0)
-		res = ERR_PTR(error);
-	return res;
+		return ERR_PTR(error);
+	return b.ptr;
 }
 EXPORT_SYMBOL(d_path);
 
@@ -314,13 +325,14 @@ char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen,
 
 char *simple_dname(struct dentry *dentry, char *buffer, int buflen)
 {
-	char *end = buffer + buflen;
+	struct prepend_buffer b = { buffer + buflen, buflen };
+
 	/* these dentries are never renamed, so d_lock is not needed */
-	if (prepend(&end, &buflen, " (deleted)", 11) ||
-	    prepend(&end, &buflen, dentry->d_name.name, dentry->d_name.len) ||
-	    prepend(&end, &buflen, "/", 1))  
-		end = ERR_PTR(-ENAMETOOLONG);
-	return end;
+	if (prepend(&b, " (deleted)", 11) ||
+	    prepend(&b, dentry->d_name.name, dentry->d_name.len) ||
+	    prepend(&b, "/", 1))
+		return ERR_PTR(-ENAMETOOLONG);
+	return b.ptr;
 }
 
 /*
@@ -329,8 +341,9 @@ char *simple_dname(struct dentry *dentry, char *buffer, int buflen)
 static char *__dentry_path(const struct dentry *d, char *buf, int buflen)
 {
 	const struct dentry *dentry;
-	char *end, *retval;
-	int len, seq = 0;
+	struct prepend_buffer b;
+	char *retval;
+	int seq = 0;
 	int error = 0;
 
 	if (buflen < 2)
@@ -339,22 +352,22 @@ static char *__dentry_path(const struct dentry *d, char *buf, int buflen)
 	rcu_read_lock();
 restart:
 	dentry = d;
-	end = buf + buflen;
-	len = buflen;
-	prepend(&end, &len, "\0", 1);
+	b.ptr = buf + buflen;
+	b.len = buflen;
+	prepend(&b, "\0", 1);
 	/* Get '/' right */
-	retval = end-1;
+	retval = b.ptr-1;
 	*retval = '/';
 	read_seqbegin_or_lock(&rename_lock, &seq);
 	while (!IS_ROOT(dentry)) {
 		const struct dentry *parent = dentry->d_parent;
 
 		prefetch(parent);
-		error = prepend_name(&end, &len, &dentry->d_name);
+		error = prepend_name(&b, &dentry->d_name);
 		if (error)
 			break;
 
-		retval = end;
+		retval = b.ptr;
 		dentry = parent;
 	}
 	if (!(seq & 1))
@@ -379,16 +392,23 @@ EXPORT_SYMBOL(dentry_path_raw);
 
 char *dentry_path(const struct dentry *dentry, char *buf, int buflen)
 {
-	char *p = NULL;
+	struct prepend_buffer b = { buf + buflen, buflen };
 	char *retval;
+	char *p = NULL;
 
 	if (d_unlinked(dentry)) {
-		p = buf + buflen;
-		if (prepend(&p, &buflen, "//deleted", 10) != 0)
+		if (prepend(&b, "//deleted", 10) != 0)
 			goto Elong;
-		buflen++;
+
+		// save away beginning of "//deleted" string
+		// and let "__dentry_path()" overwrite one byte
+		// with the terminating NUL that we'll restore
+		// below.
+		p = b.ptr;
+		b.ptr++;
+		b.len++;
 	}
-	retval = __dentry_path(dentry, buf, buflen);
+	retval = __dentry_path(dentry, b.ptr, b.len);
 	if (!IS_ERR(retval) && p)
 		*p = '/';	/* restore '/' overriden with '\0' */
 	return retval;
@@ -441,11 +461,10 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
 	error = -ENOENT;
 	if (!d_unlinked(pwd.dentry)) {
 		unsigned long len;
-		char *cwd = page + PATH_MAX;
-		int buflen = PATH_MAX;
+		struct prepend_buffer b = { page + PATH_MAX, PATH_MAX };
 
-		prepend(&cwd, &buflen, "\0", 1);
-		error = prepend_path(&pwd, &root, &cwd, &buflen);
+		prepend(&b, "\0", 1);
+		error = prepend_path(&pwd, &root, &b);
 		rcu_read_unlock();
 
 		if (error < 0)
@@ -453,16 +472,16 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
 
 		/* Unreachable from current root */
 		if (error > 0) {
-			error = prepend_unreachable(&cwd, &buflen);
+			error = prepend_unreachable(&b);
 			if (error)
 				goto out;
 		}
 
 		error = -ERANGE;
-		len = PATH_MAX + page - cwd;
+		len = PATH_MAX + page - b.ptr;
 		if (len <= size) {
 			error = len;
-			if (copy_to_user(buf, cwd, len))
+			if (copy_to_user(buf, b.ptr, len))
 				error = -EFAULT;
 		}
 	} else {

  reply	other threads:[~2021-05-08 20:40 UTC|newest]

Thread overview: 75+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-08 12:25 [PATCH RFC 0/3] make '%pD' print full path for file Jia He
2021-05-08 12:25 ` [PATCH RFC 1/3] fs: introduce helper d_path_fast() Jia He
2021-05-08 15:30   ` Linus Torvalds
2021-05-08 19:13     ` Al Viro
2021-05-08 20:39       ` Linus Torvalds [this message]
2021-05-08 21:05         ` Al Viro
2021-05-08 22:17           ` Linus Torvalds
2021-05-08 22:46             ` Al Viro
2021-05-08 22:48               ` Linus Torvalds
2021-05-08 23:15               ` Al Viro
2021-05-08 23:18                 ` Al Viro
2021-05-09 22:58                 ` Eric W. Biederman
2021-05-10 12:51                   ` Christian Brauner
2021-05-10  7:20                 ` Christian Brauner
2021-05-08 22:42           ` Linus Torvalds
2021-05-08 22:47             ` Linus Torvalds
2021-05-09  2:28               ` Al Viro
2021-05-09  2:53                 ` Linus Torvalds
2021-05-19  0:43                   ` [PATCHSET] d_path cleanups Al Viro
2021-05-19  0:48                     ` [PATCH 01/14] d_path: "\0" is {0,0}, not {0} Al Viro
2021-05-19  0:48                       ` [PATCH 02/14] d_path: saner calling conventions for __dentry_path() Al Viro
2021-06-25  9:32                         ` Justin He
2021-07-07  4:52                           ` Justin He
2021-05-19  0:48                       ` [PATCH 03/14] d_path: regularize handling of root dentry in __dentry_path() Al Viro
2021-07-07  4:50                         ` Justin He
2021-05-19  0:48                       ` [PATCH 04/14] d_path: get rid of path_with_deleted() Al Viro
2021-05-19  0:48                       ` [PATCH 05/14] getcwd(2): saner logics around prepend_path() call Al Viro
2021-07-07  7:41                         ` Justin He
2021-05-19  0:48                       ` [PATCH 06/14] d_path: don't bother with return value of prepend() Al Viro
2021-06-24  6:13                         ` Justin He
2021-05-19  0:48                       ` [PATCH 07/14] d_path: lift -ENAMETOOLONG handling into callers of prepend_path() Al Viro
2021-06-25  9:18                         ` Justin He
2021-06-28  5:20                           ` Justin He
2021-05-19  0:48                       ` [PATCH 08/14] d_path: make prepend_name() boolean Al Viro
2021-05-20  9:12                         ` Justin He
2021-05-20  9:19                           ` Andy Shevchenko
2021-05-20 14:53                           ` Petr Mladek
2021-05-20 19:35                             ` Al Viro
2021-07-07  7:43                         ` Justin He
2021-05-19  0:48                       ` [PATCH 09/14] d_path: introduce struct prepend_buffer Al Viro
2021-06-23 13:28                         ` Justin He
2021-06-24  9:29                           ` Enrico Weigelt, metux IT consult
2021-06-25  0:43                             ` Justin He
2021-06-28 16:42                               ` Enrico Weigelt, metux IT consult
2021-06-28 17:10                                 ` Andy Shevchenko
2021-05-19  0:48                       ` [PATCH 10/14] d_path: prepend_path(): get rid of vfsmnt Al Viro
2021-05-19  0:48                       ` [PATCH 11/14] d_path: prepend_path(): lift resetting b in case when we'd return 3 out of loop Al Viro
2021-05-19  0:48                       ` [PATCH 12/14] d_path: prepend_path(): lift the inner loop into a new helper Al Viro
2021-05-19  8:07                         ` Andy Shevchenko
2021-05-19 15:55                           ` Al Viro
2021-07-07  7:52                         ` Justin He
2021-05-19  0:49                       ` [PATCH 13/14] d_path: prepend_path() is unlikely to return non-zero Al Viro
2021-06-25  8:00                         ` Justin He
2021-06-25 17:58                           ` Al Viro
2021-06-28  3:28                             ` Justin He
2021-06-28  4:14                               ` Al Viro
2021-06-28  4:36                                 ` Justin He
2021-06-28  4:37                         ` Justin He
2021-05-19  0:49                       ` [PATCH 14/14] getcwd(2): clean up error handling Al Viro
2021-07-07  8:03                         ` Justin He
2021-06-24  6:05                       ` [PATCH 01/14] d_path: "\0" is {0,0}, not {0} Justin He
2021-05-19  2:39                     ` [PATCHSET] d_path cleanups Linus Torvalds
2021-06-22 14:00                     ` Justin He
2021-05-09  2:20         ` [PATCH RFC 1/3] fs: introduce helper d_path_fast() Al Viro
2021-05-09  4:58           ` Al Viro
2021-05-10 16:16           ` Eric W. Biederman
2021-05-10 15:07         ` Justin He
2021-05-10 17:03           ` Linus Torvalds
2021-05-08 12:25 ` [PATCH RFC 2/3] lib/vsprintf.c: make %pD print full path for file Jia He
2021-05-10  3:46   ` Sergey Senozhatsky
2021-05-10 13:04   ` Petr Mladek
2021-05-10 14:25     ` Justin He
2021-05-27  7:20     ` Justin He
2021-05-27  9:14       ` Petr Mladek
2021-05-08 12:25 ` [PATCH RFC 3/3] s390/hmcdrv: remove the redundant directory path in debug message Jia He

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='CAHk-=whZhNXiOGgw8mXG+PTpGvxnRG1v5_GjtjHpoYXd2Fn_Ow@mail.gmail.com' \
    --to=torvalds@linux-foundation.org \
    --cc=a.darwish@linutronix.de \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=borntraeger@de.ibm.com \
    --cc=corbet@lwn.net \
    --cc=darrick.wong@oracle.com \
    --cc=ebiederm@xmission.com \
    --cc=ebiggers@google.com \
    --cc=gor@linux.ibm.com \
    --cc=hca@linux.ibm.com \
    --cc=ira.weiny@intel.com \
    --cc=justin.he@arm.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-s390@vger.kernel.org \
    --cc=linux@rasmusvillemoes.dk \
    --cc=peterz@infradead.org \
    --cc=pmladek@suse.com \
    --cc=rostedt@goodmis.org \
    --cc=senozhatsky@chromium.org \
    --cc=viro@ftp.linux.org.uk \
    --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.