From: "Serge E. Hallyn" <serge.hallyn@ubuntu.com>
To: Tejun Heo <tj@kernel.org>
Cc: "Serge E. Hallyn" <serge.hallyn@ubuntu.com>,
serge@hallyn.com, linux-kernel@vger.kernel.org,
adityakali@google.com, 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
Subject: Re: [PATCH 1/8] kernfs: Add API to generate relative kernfs path
Date: Mon, 30 Nov 2015 20:08:07 -0600 [thread overview]
Message-ID: <20151201020807.GA29487@mail.hallyn.com> (raw)
In-Reply-To: <20151130225318.GD9039@mtj.duckdns.org>
On Mon, Nov 30, 2015 at 05:53:18PM -0500, Tejun Heo wrote:
> Hello, Serge.
>
> On Mon, Nov 30, 2015 at 12:37:58PM -0600, Serge E. Hallyn wrote:
> > > Yeah, I agree but the name is kinda misleading tho. The output isn't
> > > really a relative path but rather absolute path against the specified
> > > root. Maybe updating the function and parameter names would be
> > > helpful?
> > >
> >
> > Ok - updating the comment is simple enough. Though the name/params
> > kernfs_path_from_node_locked(from, to) still seem to make sense. Would
> > you prefer something like kernfs_absolute_path_from node_locked()? I
> > hesitate to call 'from' 'root' since kernfs_root is a thing and this
> > is not that.
>
> Hmmm... I see. Let's just make sure that the comment is clear about
> the fact that it calculates (pseudo) absolute path rather than
> relative path.
>
> Thanks.
Ok, new patch follows (and is pushed at
https://git.kernel.org/cgit/linux/kernel/git/sergeh/linux-security.git/log/?h=2015-11-30/cgroupns)
[PATCH 1/7] kernfs: Add API to generate relative kernfs path
The new function kernfs_path_from_node() generates and returns kernfs
path of a given kernfs_node relative to a given parent kernfs_node.
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
Signed-off-by: Aditya Kali <adityakali@google.com>
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
---
fs/kernfs/dir.c | 182 +++++++++++++++++++++++++++++++++++++++++--------
include/linux/kernfs.h | 3 +
2 files changed, 158 insertions(+), 27 deletions(-)
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 91e0045..7cd4bb4 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -44,28 +44,134 @@ 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_node_distance(struct kernfs_node *from, struct kernfs_node *to)
{
- char *p = buf + buflen;
- int len;
+ size_t depth = 0;
- *--p = '\0';
+ BUG_ON(!to);
+ BUG_ON(!from);
- 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);
+ while (to->parent && to != from) {
+ depth++;
+ to = to->parent;
+ }
+ return depth;
+}
- return p;
+static struct kernfs_node *kernfs_common_ancestor(struct kernfs_node *a,
+ struct kernfs_node *b)
+{
+ size_t da = kernfs_node_distance(kernfs_root(a)->kn, a);
+ size_t db = kernfs_node_distance(kernfs_root(b)->kn, b);
+
+ if (da == 0)
+ return a;
+ if (db == 0)
+ return 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: /../..
+ */
+static char *
+__must_check kernfs_path_from_node_locked(struct kernfs_node *kn_from,
+ struct kernfs_node *kn_to, char *buf,
+ size_t buflen)
+{
+ char *p = buf;
+ struct kernfs_node *kn, *common;
+ const char parent_str[] = "/..";
+ int i;
+ size_t depth_from, depth_to, len = 0, nlen = 0,
+ plen = sizeof(parent_str) - 1;
+
+ /* We atleast need 2 bytes to write "/\0". */
+ if (buflen < 2)
+ return NULL;
+
+ if (!kn_from)
+ kn_from = kernfs_root(kn_to)->kn;
+
+ if (kn_from == kn_to) {
+ *p = '/';
+ *(++p) = '\0';
+ return buf;
+ }
+
+ common = kernfs_common_ancestor(kn_from, kn_to);
+ if (!common) {
+ WARN_ONCE("%s: kn_from and kn_to on different roots\n",
+ __func__);
+ return NULL;
+ }
+
+ depth_to = kernfs_node_distance(common, kn_to);
+ depth_from = kernfs_node_distance(common, kn_from);
+
+ for (i = 0; i < depth_from; i++) {
+ if (len + plen + 1 > buflen)
+ return NULL;
+ strcpy(p, parent_str);
+ p += plen;
+ len += plen;
+ }
+
+ /* Calculate how many bytes we need for the rest */
+ for (kn = kn_to; kn != common; kn = kn->parent)
+ nlen += strlen(kn->name) + 1;
+
+ if (len + nlen + 1 > buflen)
+ return NULL;
+
+ p += 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 buf;
}
/**
@@ -115,26 +221,48 @@ size_t kernfs_path_len(struct kernfs_node *kn)
}
/**
- * kernfs_path - build full path of a given node
+ * kernfs_path_from_node - build path of node @kn relative to @kn_root.
+ * @kn_root: parent kernfs_node relative to which we need to build the path
* @kn: kernfs_node of interest
- * @buf: buffer to copy @kn's name into
+ * @buf: buffer to copy @kn's path into
* @buflen: size of @buf
*
- * Builds and returns the full path of @kn in @buf of @buflen bytes. The
- * path is built from the end of @buf so the returned pointer usually
- * doesn't match @buf. If @buf isn't long enough, @buf is nul terminated
+ * Builds and returns @kn's path relative to @kn_root. @kn_root and @kn must
+ * be on the same kernfs-root. If @kn_root is not parent of @kn, then a relative
+ * path (which includes '..'s) as needed to reach from @kn_root to @kn is
+ * returned.
+ * The path may be built from the end of @buf so the returned pointer may not
+ * match @buf. If @buf isn't long enough, @buf is nul terminated
* and %NULL is returned.
*/
-char *kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen)
+char *kernfs_path_from_node(struct kernfs_node *kn_root, struct kernfs_node *kn,
+ char *buf, size_t buflen)
{
unsigned long flags;
char *p;
spin_lock_irqsave(&kernfs_rename_lock, flags);
- p = kernfs_path_locked(kn, buf, buflen);
+ p = kernfs_path_from_node_locked(kn_root, kn, buf, buflen);
spin_unlock_irqrestore(&kernfs_rename_lock, flags);
return p;
}
+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
+ * @buflen: size of @buf
+ *
+ * Builds and returns the full path of @kn in @buf of @buflen bytes. The
+ * path is built from the end of @buf so the returned pointer usually
+ * doesn't match @buf. If @buf isn't long enough, @buf is nul terminated
+ * and %NULL is returned.
+ */
+char *kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen)
+{
+ return kernfs_path_from_node(NULL, kn, buf, buflen);
+}
EXPORT_SYMBOL_GPL(kernfs_path);
/**
@@ -168,8 +296,8 @@ void pr_cont_kernfs_path(struct kernfs_node *kn)
spin_lock_irqsave(&kernfs_rename_lock, flags);
- p = kernfs_path_locked(kn, kernfs_pr_cont_buf,
- sizeof(kernfs_pr_cont_buf));
+ p = kernfs_path_from_node_locked(NULL, kn, kernfs_pr_cont_buf,
+ sizeof(kernfs_pr_cont_buf));
if (p)
pr_cont("%s", p);
else
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index 5d4e9c4..d025ebd 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -267,6 +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_from_node(struct kernfs_node *root_kn,
+ struct kernfs_node *kn, char *buf,
+ size_t buflen);
char * __must_check kernfs_path(struct kernfs_node *kn, char *buf,
size_t buflen);
void pr_cont_kernfs_name(struct kernfs_node *kn);
--
2.5.0
next prev parent reply other threads:[~2015-12-01 2:08 UTC|newest]
Thread overview: 67+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
2015-11-16 19:51 ` [PATCH 2/8] sched: new clone flag CLONE_NEWCGROUP for cgroup namespace serge
2015-11-16 19:51 ` [PATCH 3/8] cgroup: add function to get task's cgroup serge
2015-11-24 16:27 ` Tejun Heo
2015-11-24 16:54 ` Tejun Heo
2015-11-16 19:51 ` [PATCH 4/8] cgroup: export cgroup_get() and cgroup_put() serge
2015-11-24 16:30 ` Tejun Heo
2015-11-24 22:35 ` Serge E. Hallyn
2015-11-16 19:51 ` [PATCH 5/8] cgroup: introduce cgroup namespaces serge
2015-11-24 16:49 ` Tejun Heo
2015-11-16 19:51 ` [PATCH 6/8] cgroup: cgroup namespace setns support serge
2015-11-24 16:52 ` Tejun Heo
2015-11-16 19:51 ` [PATCH 7/8] cgroup: mount cgroupns-root when inside non-init cgroupns serge
2015-11-24 17:16 ` Tejun Heo
2015-11-25 6:01 ` Serge E. Hallyn
2015-11-25 19:10 ` Tejun Heo
2015-11-25 19:55 ` Serge Hallyn
2015-11-25 19:57 ` Tejun Heo
2015-11-27 5:17 ` Serge E. Hallyn
2015-11-30 15:09 ` Tejun Heo
2015-12-01 4:07 ` Serge E. Hallyn
2015-12-01 16:46 ` Tejun Heo
2015-12-01 21:58 ` Serge E. Hallyn
2015-12-02 16:53 ` Tejun Heo
2015-12-02 16:56 ` Serge E. Hallyn
2015-12-02 16:58 ` Tejun Heo
2015-12-02 17:02 ` Serge E. Hallyn
2015-12-02 17:05 ` Tejun Heo
2015-12-03 22:47 ` Serge E. Hallyn
2015-12-07 15:39 ` Tejun Heo
2015-12-07 15:53 ` Serge Hallyn
2015-11-16 19:51 ` [PATCH 8/8] cgroup: Add documentation for cgroup namespaces serge
2015-11-24 17:16 ` Tejun Heo
2015-11-16 20:41 ` CGroup Namespaces (v4) Richard Weinberger
2015-11-16 20:46 ` Serge E. Hallyn
2015-11-16 20:50 ` Richard Weinberger
2015-11-16 20:54 ` Serge E. Hallyn
2015-11-16 22:24 ` Eric W. Biederman
2015-11-16 22:37 ` Tejun Heo
2015-11-17 1:13 ` Serge E. Hallyn
2015-11-17 1:40 ` Serge E. Hallyn
2015-11-17 3:54 ` Serge E. Hallyn
2015-11-18 2:30 ` Serge E. Hallyn
2015-11-18 9:18 ` Eric W. Biederman
2015-11-18 15:43 ` Serge E. 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-12-23 4:23 CGroup Namespaces (v8) serge.hallyn
2015-12-23 4:23 ` [PATCH 1/8] kernfs: Add API to generate relative kernfs path serge.hallyn
2015-12-23 16:08 ` Tejun Heo
2015-12-23 16:36 ` Serge E. Hallyn
2015-12-23 16:24 ` Tejun Heo
2015-12-23 16:51 ` Greg KH
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
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
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=20151201020807.GA29487@mail.hallyn.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=linux-api@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lxc-devel@lists.linuxcontainers.org \
--cc=serge@hallyn.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
Powered by JetHome