All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jia He <justin.he@arm.com>
To: 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>,
	Alexander Viro <viro@zeniv.linux.org.uk>,
	Linus Torvalds <torvalds@linux-foundation.org>
Cc: "Peter Zijlstra (Intel)" <peterz@infradead.org>,
	Eric Biggers <ebiggers@google.com>,
	"Ahmed S. Darwish" <a.darwish@linutronix.de>,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-fsdevel@vger.kernel.org,
	Matthew Wilcox <willy@infradead.org>, Jia He <justin.he@arm.com>
Subject: [PATCH RFCv4 1/4] fs: introduce helper d_path_unsafe()
Date: Tue, 15 Jun 2021 23:49:49 +0800	[thread overview]
Message-ID: <20210615154952.2744-2-justin.he@arm.com> (raw)
In-Reply-To: <20210615154952.2744-1-justin.he@arm.com>

This helper is similar to d_path except that it doesn't take any
seqlock/spinlock. It is typical for debugging purpose. Besides,
an additional return value *prenpend_len* is used to get the full
path length of the dentry.

prepend_name_with_len() enhances the behavior of prepend_name().
Previously it will skip the loop at once in __prepen_path() when the
space is not enough. __prepend_path() gets the full length of dentry
together with the parent recusively.

Besides, if someone invokes snprintf with small but positive space,
prepend_name_with() needs to move and copy the string partially.

More than that, kasnprintf will pass NULL _buf_ and _end_, hence
it returns at the very beginning with false in this case;

Suggested-by: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Jia He <justin.he@arm.com>
---
 fs/d_path.c            | 83 +++++++++++++++++++++++++++++++++++++++++-
 include/linux/dcache.h |  1 +
 2 files changed, 82 insertions(+), 2 deletions(-)

diff --git a/fs/d_path.c b/fs/d_path.c
index 23a53f7b5c71..4fc224eadf58 100644
--- a/fs/d_path.c
+++ b/fs/d_path.c
@@ -68,9 +68,66 @@ static bool prepend_name(struct prepend_buffer *p, const struct qstr *name)
 	return true;
 }
 
+static bool prepend_name_with_len(struct prepend_buffer *p, const struct qstr *name,
+			 int orig_buflen)
+{
+	const char *dname = smp_load_acquire(&name->name); /* ^^^ */
+	int dlen = READ_ONCE(name->len);
+	char *s;
+	int last_len = p->len;
+
+	p->len -= dlen + 1;
+
+	if (unlikely(!p->buf))
+		return false;
+
+	if (orig_buflen <= 0)
+		return false;
+	/*
+	 * The first time we overflow the buffer. Then fill the string
+	 * partially from the beginning
+	 */
+	if (unlikely(p->len < 0)) {
+		int buflen = strlen(p->buf);
+
+		s = p->buf;
+
+		/* Still have small space to fill partially */
+		if (last_len > 0) {
+			p->buf -= last_len;
+			buflen += last_len;
+		}
+
+		if (buflen > dlen + 1) {
+			/* This dentry name can be fully filled */
+			memmove(p->buf + dlen + 1, s, buflen - dlen - 1);
+			p->buf[0] = '/';
+			memcpy(p->buf + 1, dname, dlen);
+		} else if (buflen > 0) {
+			/* Partially filled, and drop last dentry name */
+			p->buf[0] = '/';
+			memcpy(p->buf + 1, dname, buflen - 1);
+		}
+
+		return false;
+	}
+
+	s = p->buf -= dlen + 1;
+	*s++ = '/';
+	while (dlen--) {
+		char c = *dname++;
+
+		if (!c)
+			break;
+		*s++ = c;
+	}
+	return true;
+}
 static int __prepend_path(const struct dentry *dentry, const struct mount *mnt,
 			  const struct path *root, struct prepend_buffer *p)
 {
+	int orig_buflen = p->len;
+
 	while (dentry != root->dentry || &mnt->mnt != root->mnt) {
 		const struct dentry *parent = READ_ONCE(dentry->d_parent);
 
@@ -97,8 +154,7 @@ static int __prepend_path(const struct dentry *dentry, const struct mount *mnt,
 			return 3;
 
 		prefetch(parent);
-		if (!prepend_name(p, &dentry->d_name))
-			break;
+		prepend_name_with_len(p, &dentry->d_name, orig_buflen);
 		dentry = parent;
 	}
 	return 0;
@@ -263,6 +319,29 @@ char *d_path(const struct path *path, char *buf, int buflen)
 }
 EXPORT_SYMBOL(d_path);
 
+/**
+ * d_path_unsafe - fast return the full path of a dentry without taking
+ * any seqlock/spinlock. This helper is typical for debugging purpose.
+ */
+char *d_path_unsafe(const struct path *path, char *buf, int buflen,
+		    int *prepend_len)
+{
+	struct path root;
+	struct mount *mnt = real_mount(path->mnt);
+	DECLARE_BUFFER(b, buf, buflen);
+
+	rcu_read_lock();
+	get_fs_root_rcu(current->fs, &root);
+
+	prepend(&b, "", 1);
+	__prepend_path(path->dentry, mnt, &root, &b);
+	rcu_read_unlock();
+
+	*prepend_len = b.len;
+
+	return b.buf;
+}
+
 /*
  * Helper function for dentry_operations.d_dname() members
  */
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 9e23d33bb6f1..ec118b684055 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -301,6 +301,7 @@ char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
 extern char *__d_path(const struct path *, const struct path *, char *, int);
 extern char *d_absolute_path(const struct path *, char *, int);
 extern char *d_path(const struct path *, char *, int);
+extern char *d_path_unsafe(const struct path *, char *, int, int*);
 extern char *dentry_path_raw(const struct dentry *, char *, int);
 extern char *dentry_path(const struct dentry *, char *, int);
 
-- 
2.17.1


  reply	other threads:[~2021-06-15 15:53 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-15 15:49 [PATCH RFCv4 0/4] make '%pD' print full path for file Jia He
2021-06-15 15:49 ` Jia He [this message]
2021-06-15 20:40   ` [PATCH RFCv4 1/4] fs: introduce helper d_path_unsafe() Andy Shevchenko
2021-06-16  0:54     ` Justin He
2021-06-15 15:49 ` [PATCH RFCv4 2/4] lib/vsprintf.c: make '%pD' print full path for file Jia He
2021-06-15 20:44   ` Andy Shevchenko
2021-06-17 14:09   ` Petr Mladek
2021-06-22  2:20     ` Justin He
2021-06-15 15:49 ` [PATCH RFCv4 3/4] lib/test_printf.c: split write-beyond-buffer check in two Jia He
2021-06-17 14:17   ` Petr Mladek
2022-06-17  7:15     ` Rasmus Villemoes
2022-06-17 16:41       ` Kent Overstreet
2022-07-11 13:08       ` Petr Mladek
2021-06-15 15:49 ` [PATCH RFCv4 4/4] lib/test_printf.c: add test cases for '%pD' Jia He
2021-06-15 20:47   ` Andy Shevchenko
2021-06-17 14:52     ` Petr Mladek
2021-06-22  2:21       ` Justin He
2021-06-15 20:42 ` [PATCH RFCv4 0/4] make '%pD' print full path for file Andy Shevchenko
2021-06-16  5:09 ` Christoph Hellwig
2021-06-16  5:16   ` Justin 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=20210615154952.2744-2-justin.he@arm.com \
    --to=justin.he@arm.com \
    --cc=a.darwish@linutronix.de \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=corbet@lwn.net \
    --cc=ebiggers@google.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@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@zeniv.linux.org.uk \
    --cc=willy@infradead.org \
    /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.