All of lore.kernel.org
 help / color / mirror / Atom feed
From: Al Viro <viro@zeniv.linux.org.uk>
To: Linus Torvalds <torvalds@linux-foundation.org>
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: Sun, 9 May 2021 02:20:32 +0000	[thread overview]
Message-ID: <YJdG8LhKBoFayOc+@zeniv-ca.linux.org.uk> (raw)
In-Reply-To: <CAHk-=whZhNXiOGgw8mXG+PTpGvxnRG1v5_GjtjHpoYXd2Fn_Ow@mail.gmail.com>

On Sat, May 08, 2021 at 01:39:45PM -0700, Linus Torvalds wrote:
> -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;
>  }

OK, that part is pretty obvious - pointers to a couple of objects in the same
stack frame replaced with a single pointer to structure consisting of those
two objects.  Might actually be an optimization.

> @@ -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++;

Ditto.

> @@ -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;
> +}

See other reply.

> +
>  /**
>   * 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);

Minor yuck: that should be "", 1 (in the original as well).  Same below...
Fairly subtle point: we do *not* need to check for failures here, since
prepend_path() will attempt to produce at least something.  And we'll
catch that failure just fine.  However, we do depend upon buflen being
non-negative here.  If we ever called that (or any other in that family,
really) with buflen == MIN_INT, we'd get seriously unpleasant results.
No such callers exist, thankfully.

>  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;
>  }

Umm...  Interesting, especially considering the way dyname_dname() looks like.
char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen,
                        const char *fmt, ...)
{
        va_list args;
        char temp[64];
        int sz;

        va_start(args, fmt);
        sz = vsnprintf(temp, sizeof(temp), fmt, args) + 1;
        va_end(args);

        if (sz > sizeof(temp) || sz > buflen)
                return ERR_PTR(-ENAMETOOLONG);

        buffer += buflen - sz;
        return memcpy(buffer, temp, sz);
}

Looks like there's a piece of prepend() open-coded in it.  And
since all ->d_dname() instances are either simple_dname() or end up
with call of dynamic_dname()...

Might make sense to turn that method into
	int (*d_dname)(struct dentry *, struct prepend_buffer *);

Followup patch, obviously, but it might be worth looking into.

Another thing that keeps bugging me about prepend_path() is the
set of return values.  I mean, 0/1/2/3/-ENAMETOOLONG, and all
except 0 are unlikely?  Might as well make that 0/1/2/3/-1, if
not an outright 0/1/2/3/4.  And prepend() could return bool, while
we are at it (true - success, false - overflow)...

  parent reply	other threads:[~2021-05-09  2:21 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
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         ` Al Viro [this message]
2021-05-09  4:58           ` [PATCH RFC 1/3] fs: introduce helper d_path_fast() 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=YJdG8LhKBoFayOc+@zeniv-ca.linux.org.uk \
    --to=viro@zeniv.linux.org.uk \
    --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=torvalds@linux-foundation.org \
    --cc=viro@ftp.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.