/* Called with cgroup_mutex held or else with an RCU-protected cgroup reference. Writes path of cgroup into buf. Returns 0 on success, -errno on error.  */
int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
/* Called with cgroup_mutex held or else with an RCU-protected cgroup reference. Writes path of cgroup into buf. Returns 0 on success, -errno on error.  */
int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
{
	char *start;
	struct dentry *dentry = rcu_dereference(cgrp->dentry);
	if (!dentry || cgrp == dummytop) {
		strcpy(buf, "/");
		return 0;
	}
	start = buf + buflen;
	*--start = '\0';
	for (;;) {
		int len = dentry->d_name.len;
		if ((start -= len) < buf)
			return -ENAMETOOLONG;
		memcpy(start, cgrp->dentry->d_name.name, len);
		cgrp = cgrp->parent;
		if (!cgrp)
			break;
		dentry = rcu_dereference(cgrp->dentry);
		if (!cgrp->parent)
			continue;
		if (--start < buf)
			return -ENAMETOOLONG;
		*start = '/';
	}
	memmove(buf, start, buf + buflen - start);
	return 0;
}