From: serge.hallyn@ubuntu.com
To: linux-kernel@vger.kernel.org
Cc: adityakali@google.com, tj@kernel.org, linux-api@vger.kernel.org,
containers@lists.linux-foundation.org, cgroups@vger.kernel.org,
lxc-devel@lists.linuxcontainers.org, akpm@linux-foundation.org,
ebiederm@xmission.com, gregkh@linuxfoundation.org,
lizefan@huawei.com, hannes@cmpxchg.org,
"Serge E. Hallyn" <serge.hallyn@canonical.com>
Subject: [PATCH 1/8] kernfs: Add API to generate relative kernfs path
Date: Tue, 22 Dec 2015 22:23:22 -0600 [thread overview]
Message-ID: <1450844609-9194-2-git-send-email-serge.hallyn@ubuntu.com> (raw)
In-Reply-To: <1450844609-9194-1-git-send-email-serge.hallyn@ubuntu.com>
From: Aditya Kali <adityakali@google.com>
The new function kernfs_path_from_node() generates and returns kernfs
path of a given kernfs_node relative to a given parent kernfs_node.
Signed-off-by: Aditya Kali <adityakali@google.com>
Signed-off-by: Serge E. Hallyn <serge.hallyn@canonical.com>
---
Changelog 20151125:
- Fully-wing multilinecomments
- Rework kernfs_path_from_node_locked() logic
- Replace BUG_ONs with returning NULL
- Use a const char* for /.. and precalculate its size
Changelog 20151130:
- Update kernfs_path_from_node_locked comment
Changelog 20151208:
- kernfs_node_distance:
* Remove BUG_ON(NULL)s
* Rename kernfs_node_distance to kernfs_depth
- kernfs_common-ancestor:
* Remove useless checks for depth == 0
* Add check to ensure nodes are from same root
- kernfs_path_from_node_locked:
* Remove needless __must_check
* Put p;len on its own decl line.
* Fix wrong WARN_ONCE usage
Changelog 20151209:
- kernfs_path_from_node: change arguments to 'to' and 'from', and
change their order.
Changelog 20151222:
- kernfs_path_from_node{,_locked}: return the string length.
kernfs_path is gpl-exported, so changing their return value seemed
ill-advised, but if noone minds I can update it too.
---
fs/kernfs/dir.c | 205 ++++++++++++++++++++++++++++++++++++++++--------
include/linux/kernfs.h | 9 ++-
2 files changed, 179 insertions(+), 35 deletions(-)
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 742bf4a..e82b9a1 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -44,28 +44,123 @@ static int kernfs_name_locked(struct kernfs_node *kn, char *buf, size_t buflen)
return strlcpy(buf, kn->parent ? kn->name : "/", buflen);
}
-static char * __must_check kernfs_path_locked(struct kernfs_node *kn, char *buf,
- size_t buflen)
+/* kernfs_node_depth - compute depth from @from to @to */
+static size_t kernfs_depth(struct kernfs_node *from, struct kernfs_node *to)
{
- char *p = buf + buflen;
- int len;
+ size_t depth = 0;
- *--p = '\0';
+ while (to->parent && to != from) {
+ depth++;
+ to = to->parent;
+ }
+ return depth;
+}
- do {
- len = strlen(kn->name);
- if (p - buf < len + 1) {
- buf[0] = '\0';
- p = NULL;
- break;
- }
- p -= len;
- memcpy(p, kn->name, len);
- *--p = '/';
- kn = kn->parent;
- } while (kn && kn->parent);
+static struct kernfs_node *kernfs_common_ancestor(struct kernfs_node *a,
+ struct kernfs_node *b)
+{
+ size_t da, db;
+ struct kernfs_root *ra = kernfs_root(a), *rb = kernfs_root(b);
+
+ if (ra != rb)
+ return NULL;
+
+ da = kernfs_depth(ra->kn, a);
+ db = kernfs_depth(rb->kn, b);
+
+ while (da > db) {
+ a = a->parent;
+ da--;
+ }
+ while (db > da) {
+ b = b->parent;
+ db--;
+ }
+
+ /* worst case b and a will be the same at root */
+ while (b != a) {
+ b = b->parent;
+ a = a->parent;
+ }
+
+ return a;
+}
+
+/**
+ * kernfs_path_from_node_locked - find a pseudo-absolute path to @kn_to,
+ * where kn_from is treated as root of the path.
+ * @kn_from: kernfs node which should be treated as root for the path
+ * @kn_to: kernfs node to which path is needed
+ * @buf: buffer to copy the path into
+ * @buflen: size of @buf
+ *
+ * We need to handle couple of scenarios here:
+ * [1] when @kn_from is an ancestor of @kn_to at some level
+ * kn_from: /n1/n2/n3
+ * kn_to: /n1/n2/n3/n4/n5
+ * result: /n4/n5
+ *
+ * [2] when @kn_from is on a different hierarchy and we need to find common
+ * ancestor between @kn_from and @kn_to.
+ * kn_from: /n1/n2/n3/n4
+ * kn_to: /n1/n2/n5
+ * result: /../../n5
+ * OR
+ * kn_from: /n1/n2/n3/n4/n5 [depth=5]
+ * kn_to: /n1/n2/n3 [depth=3]
+ * result: /../..
+ *
+ * return value: length of the string. If greater than buflen,
+ * then contents of buf are undefined. On error, -1 is returned.
+ */
+static int
+kernfs_path_from_node_locked(struct kernfs_node *kn_to,
+ struct kernfs_node *kn_from, char *buf,
+ size_t buflen)
+{
+ struct kernfs_node *kn, *common;
+ const char parent_str[] = "/..";
+ size_t depth_from, depth_to, len = 0, nlen = 0;
+ char *p;
+ int i;
+
+ if (!kn_from)
+ kn_from = kernfs_root(kn_to)->kn;
+
+ if (kn_from == kn_to)
+ return strlcpy(buf, "/", buflen);
+
+ common = kernfs_common_ancestor(kn_from, kn_to);
+ if (WARN_ON(!common))
+ return -1;
+
+ depth_to = kernfs_depth(common, kn_to);
+ depth_from = kernfs_depth(common, kn_from);
+
+ if (buf)
+ buf[0] = '\0';
+
+ for (i = 0; i < depth_from; i++)
+ len += strlcpy(buf + len, parent_str,
+ len < buflen ? buflen - len : 0);
+
+ /* Calculate how many bytes we need for the rest */
+ for (kn = kn_to; kn != common; kn = kn->parent)
+ nlen += strlen(kn->name) + 1;
- return p;
+ if (len + nlen >= buflen)
+ return len + nlen;
+
+ p = buf + len + nlen;
+ *p = '\0';
+ for (kn = kn_to; kn != common; kn = kn->parent) {
+ nlen = strlen(kn->name);
+ p -= nlen;
+ memcpy(p, kn->name, nlen);
+ *(--p) = '/';
+ }
+
+ return len + nlen;
}
/**
@@ -115,6 +210,34 @@ size_t kernfs_path_len(struct kernfs_node *kn)
}
/**
+ * kernfs_path_from_node - build path of node @to relative to @from.
+ * @from: parent kernfs_node relative to which we need to build the path
+ * @to: kernfs_node of interest
+ * @buf: buffer to copy @to's path into
+ * @buflen: size of @buf
+ *
+ * Builds @to's path relative to @from in @buf. @from and @to must
+ * be on the same kernfs-root. If @from is not parent of @to, then a relative
+ * path (which includes '..'s) as needed to reach from @from to @to is
+ * returned.
+ *
+ * If @buf isn't long enough, the return value will be greater than @buflen
+ * and @buf contents are undefined.
+ */
+int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from,
+ char *buf, size_t buflen)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&kernfs_rename_lock, flags);
+ ret = kernfs_path_from_node_locked(to, from, buf, buflen);
+ spin_unlock_irqrestore(&kernfs_rename_lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(kernfs_path_from_node);
+
+/**
* kernfs_path - build full path of a given node
* @kn: kernfs_node of interest
* @buf: buffer to copy @kn's name into
@@ -127,13 +250,12 @@ size_t kernfs_path_len(struct kernfs_node *kn)
*/
char *kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen)
{
- unsigned long flags;
- char *p;
+ int ret;
- spin_lock_irqsave(&kernfs_rename_lock, flags);
- p = kernfs_path_locked(kn, buf, buflen);
- spin_unlock_irqrestore(&kernfs_rename_lock, flags);
- return p;
+ ret = kernfs_path_from_node(kn, NULL, buf, buflen);
+ if (ret < 0 || ret >= buflen)
+ return NULL;
+ return buf;
}
EXPORT_SYMBOL_GPL(kernfs_path);
@@ -164,18 +286,39 @@ void pr_cont_kernfs_name(struct kernfs_node *kn)
void pr_cont_kernfs_path(struct kernfs_node *kn)
{
unsigned long flags;
- char *p;
+ char *p = NULL;
+ int sz1, sz2;
spin_lock_irqsave(&kernfs_rename_lock, flags);
- p = kernfs_path_locked(kn, kernfs_pr_cont_buf,
- sizeof(kernfs_pr_cont_buf));
- if (p)
- pr_cont("%s", p);
- else
- pr_cont("<name too long>");
+ sz1 = kernfs_path_from_node_locked(kn, NULL, kernfs_pr_cont_buf,
+ sizeof(kernfs_pr_cont_buf));
+ if (sz1 < 0) {
+ pr_cont("(error)");
+ goto out;
+ }
+
+ if (sz1 < sizeof(kernfs_pr_cont_buf)) {
+ pr_cont("%s", kernfs_pr_cont_buf);
+ goto out;
+ }
+
+ p = kmalloc(sz1 + 1, GFP_NOFS);
+ if (!p) {
+ pr_cont("(out of memory)");
+ goto out;
+ }
+ sz2 = kernfs_path_from_node_locked(kn, NULL, p, sz1 + 1);
+ if (sz2 > sz1 || sz2 < 0) {
+ pr_cont("(error)");
+ goto out;
+ }
+
+ pr_cont("%s", p);
+out:
spin_unlock_irqrestore(&kernfs_rename_lock, flags);
+ kfree(p);
}
/**
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index af51df3..716bfde 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -267,8 +267,9 @@ static inline bool kernfs_ns_enabled(struct kernfs_node *kn)
int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen);
size_t kernfs_path_len(struct kernfs_node *kn);
-char * __must_check kernfs_path(struct kernfs_node *kn, char *buf,
- size_t buflen);
+int kernfs_path_from_node(struct kernfs_node *root_kn, struct kernfs_node *kn,
+ char *buf, size_t buflen);
+char *kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen);
void pr_cont_kernfs_name(struct kernfs_node *kn);
void pr_cont_kernfs_path(struct kernfs_node *kn);
struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn);
@@ -338,8 +339,8 @@ static inline int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen)
static inline size_t kernfs_path_len(struct kernfs_node *kn)
{ return 0; }
-static inline char * __must_check kernfs_path(struct kernfs_node *kn, char *buf,
- size_t buflen)
+static inline char *kernfs_path(struct kernfs_node *kn, char *buf,
+ size_t buflen)
{ return NULL; }
static inline void pr_cont_kernfs_name(struct kernfs_node *kn) { }
--
1.7.9.5
next prev parent reply other threads:[~2015-12-23 4:26 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-12-23 4:23 CGroup Namespaces (v8) serge.hallyn
2015-12-23 4:23 ` serge.hallyn [this message]
2015-12-23 16:08 ` [PATCH 1/8] kernfs: Add API to generate relative kernfs path Tejun Heo
2015-12-23 16:36 ` Serge E. Hallyn
2015-12-23 19:33 ` [PATCH 1/8 v8.2] " Serge E. Hallyn
2015-12-23 16:24 ` [PATCH 1/8] " Tejun Heo
2015-12-23 16:51 ` Greg KH
2015-12-23 4:23 ` [PATCH 2/8] sched: new clone flag CLONE_NEWCGROUP for cgroup namespace serge.hallyn
2015-12-23 4:23 ` [PATCH 3/8] cgroup: introduce cgroup namespaces serge.hallyn
2015-12-23 16:15 ` Tejun Heo
2015-12-23 19:34 ` [PATCH 3/8 v8.2] " Serge E. Hallyn
2015-12-23 4:23 ` [PATCH 4/8] cgroup: cgroup namespace setns support serge.hallyn
2015-12-23 4:23 ` [PATCH 5/8] kernfs: define kernfs_node_dentry serge.hallyn
2015-12-23 16:25 ` Tejun Heo
2015-12-23 16:51 ` Greg KH
2015-12-23 4:23 ` [PATCH 6/8] cgroup: mount cgroupns-root when inside non-init cgroupns serge.hallyn
2015-12-31 13:38 ` Sergey Senozhatsky
2016-01-01 0:58 ` Serge E. Hallyn
2016-01-01 1:17 ` Sergey Senozhatsky
2016-01-01 1:56 ` Tejun Heo
2015-12-23 4:23 ` [PATCH 7/8] cgroup: Add documentation for cgroup namespaces serge.hallyn
2015-12-28 17:47 ` Tejun Heo
2015-12-28 21:13 ` Serge Hallyn
2015-12-28 21:48 ` [PATCH] " Tejun Heo
2015-12-23 4:23 ` [PATCH 8/8] Add FS_USERNS_FLAG to cgroup fs serge.hallyn
2015-12-28 17:46 ` CGroup Namespaces (v8) Tejun Heo
2016-01-01 8:19 ` Dan Williams
2016-01-01 8:59 ` Serge E. Hallyn
2016-01-01 9:42 ` Dan Williams
2016-01-01 18:06 ` Serge E. Hallyn
2016-01-01 19:14 ` Dan Williams
2016-01-02 11:52 ` Tejun Heo
-- strict thread matches above, loose matches on Subject: below --
2016-01-29 8:54 CGroup Namespaces (v10) serge.hallyn
2016-01-29 8:54 ` [PATCH 1/8] kernfs: Add API to generate relative kernfs path serge.hallyn
2016-01-04 19:54 CGroup Namespaces (v9) serge.hallyn
2016-01-04 19:54 ` [PATCH 1/8] kernfs: Add API to generate relative kernfs path serge.hallyn
2015-12-09 19:28 CGroup Namespaces (v7) serge.hallyn
2015-12-09 19:28 ` [PATCH 1/8] kernfs: Add API to generate relative kernfs path serge.hallyn
2015-12-09 21:38 ` Tejun Heo
2015-12-09 22:13 ` Serge Hallyn
2015-12-09 22:36 ` Tejun Heo
2015-12-09 22:51 ` Serge E. Hallyn
2015-12-10 1:28 ` Serge E. Hallyn
2015-11-16 19:51 CGroup Namespaces (v4) serge
2015-11-16 19:51 ` [PATCH 1/8] kernfs: Add API to generate relative kernfs path serge
2015-11-24 16:16 ` Tejun Heo
2015-11-24 16:17 ` Tejun Heo
2015-11-24 17:43 ` Serge E. Hallyn
2015-11-27 5:25 ` Serge E. Hallyn
2015-11-30 15:11 ` Tejun Heo
2015-11-30 18:37 ` Serge E. Hallyn
2015-11-30 22:53 ` Tejun Heo
2015-12-01 2:08 ` Serge E. Hallyn
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=1450844609-9194-2-git-send-email-serge.hallyn@ubuntu.com \
--to=serge.hallyn@ubuntu.com \
--cc=adityakali@google.com \
--cc=akpm@linux-foundation.org \
--cc=cgroups@vger.kernel.org \
--cc=containers@lists.linux-foundation.org \
--cc=ebiederm@xmission.com \
--cc=gregkh@linuxfoundation.org \
--cc=hannes@cmpxchg.org \
--cc=linux-api@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lizefan@huawei.com \
--cc=lxc-devel@lists.linuxcontainers.org \
--cc=serge.hallyn@canonical.com \
--cc=tj@kernel.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).