Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 17749398 authored by Tejun Heo's avatar Tejun Heo
Browse files

Merge branch 'for-4.5-ancestor-test' of...

Merge branch 'for-4.5-ancestor-test' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup

 into for-4.5

Signed-off-by: default avatarTejun Heo <tj@kernel.org>
parents e11362bb 16af4396
Loading
Loading
Loading
Loading
+46 −0
Original line number Original line Diff line number Diff line
@@ -694,6 +694,29 @@ static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent,
	return NULL;
	return NULL;
}
}


static struct kernfs_node *kernfs_walk_ns(struct kernfs_node *parent,
					  const unsigned char *path,
					  const void *ns)
{
	static char path_buf[PATH_MAX];	/* protected by kernfs_mutex */
	size_t len = strlcpy(path_buf, path, PATH_MAX);
	char *p = path_buf;
	char *name;

	lockdep_assert_held(&kernfs_mutex);

	if (len >= PATH_MAX)
		return NULL;

	while ((name = strsep(&p, "/")) && parent) {
		if (*name == '\0')
			continue;
		parent = kernfs_find_ns(parent, name, ns);
	}

	return parent;
}

/**
/**
 * kernfs_find_and_get_ns - find and get kernfs_node with the given name
 * kernfs_find_and_get_ns - find and get kernfs_node with the given name
 * @parent: kernfs_node to search under
 * @parent: kernfs_node to search under
@@ -718,6 +741,29 @@ struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent,
}
}
EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns);
EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns);


/**
 * kernfs_walk_and_get_ns - find and get kernfs_node with the given path
 * @parent: kernfs_node to search under
 * @path: path to look for
 * @ns: the namespace tag to use
 *
 * Look for kernfs_node with path @path under @parent and get a reference
 * if found.  This function may sleep and returns pointer to the found
 * kernfs_node on success, %NULL on failure.
 */
struct kernfs_node *kernfs_walk_and_get_ns(struct kernfs_node *parent,
					   const char *path, const void *ns)
{
	struct kernfs_node *kn;

	mutex_lock(&kernfs_mutex);
	kn = kernfs_walk_ns(parent, path, ns);
	kernfs_get(kn);
	mutex_unlock(&kernfs_mutex);

	return kn;
}

/**
/**
 * kernfs_create_root - create a new kernfs hierarchy
 * kernfs_create_root - create a new kernfs hierarchy
 * @scops: optional syscall operations for the hierarchy
 * @scops: optional syscall operations for the hierarchy
+14 −0
Original line number Original line Diff line number Diff line
@@ -224,6 +224,14 @@ struct cgroup {
	 */
	 */
	int id;
	int id;


	/*
	 * The depth this cgroup is at.  The root is at depth zero and each
	 * step down the hierarchy increments the level.  This along with
	 * ancestor_ids[] can determine whether a given cgroup is a
	 * descendant of another without traversing the hierarchy.
	 */
	int level;

	/*
	/*
	 * Each non-empty css_set associated with this cgroup contributes
	 * Each non-empty css_set associated with this cgroup contributes
	 * one to populated_cnt.  All children with non-zero popuplated_cnt
	 * one to populated_cnt.  All children with non-zero popuplated_cnt
@@ -279,6 +287,9 @@ struct cgroup {


	/* used to schedule release agent */
	/* used to schedule release agent */
	struct work_struct release_agent_work;
	struct work_struct release_agent_work;

	/* ids of the ancestors at each level including self */
	int ancestor_ids[];
};
};


/*
/*
@@ -298,6 +309,9 @@ struct cgroup_root {
	/* The root cgroup.  Root is destroyed on its release. */
	/* The root cgroup.  Root is destroyed on its release. */
	struct cgroup cgrp;
	struct cgroup cgrp;


	/* for cgrp->ancestor_ids[0] */
	int cgrp_ancestor_id_storage;

	/* Number of cgroups in the hierarchy, used only for /proc/cgroups */
	/* Number of cgroups in the hierarchy, used only for /proc/cgroups */
	atomic_t nr_cgrps;
	atomic_t nr_cgrps;


+24 −1
Original line number Original line Diff line number Diff line
@@ -81,7 +81,8 @@ struct cgroup_subsys_state *cgroup_get_e_css(struct cgroup *cgroup,
struct cgroup_subsys_state *css_tryget_online_from_dir(struct dentry *dentry,
struct cgroup_subsys_state *css_tryget_online_from_dir(struct dentry *dentry,
						       struct cgroup_subsys *ss);
						       struct cgroup_subsys *ss);


bool cgroup_is_descendant(struct cgroup *cgrp, struct cgroup *ancestor);
struct cgroup *cgroup_get_from_path(const char *path);

int cgroup_attach_task_all(struct task_struct *from, struct task_struct *);
int cgroup_attach_task_all(struct task_struct *from, struct task_struct *);
int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from);
int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from);


@@ -361,6 +362,11 @@ static inline void css_put_many(struct cgroup_subsys_state *css, unsigned int n)
		percpu_ref_put_many(&css->refcnt, n);
		percpu_ref_put_many(&css->refcnt, n);
}
}


static inline void cgroup_put(struct cgroup *cgrp)
{
	css_put(&cgrp->self);
}

/**
/**
 * task_css_set_check - obtain a task's css_set with extra access conditions
 * task_css_set_check - obtain a task's css_set with extra access conditions
 * @task: the task to obtain css_set for
 * @task: the task to obtain css_set for
@@ -468,6 +474,23 @@ static inline struct cgroup *task_cgroup(struct task_struct *task,
	return task_css(task, subsys_id)->cgroup;
	return task_css(task, subsys_id)->cgroup;
}
}


/**
 * cgroup_is_descendant - test ancestry
 * @cgrp: the cgroup to be tested
 * @ancestor: possible ancestor of @cgrp
 *
 * Test whether @cgrp is a descendant of @ancestor.  It also returns %true
 * if @cgrp == @ancestor.  This function is safe to call as long as @cgrp
 * and @ancestor are accessible.
 */
static inline bool cgroup_is_descendant(struct cgroup *cgrp,
					struct cgroup *ancestor)
{
	if (cgrp->root != ancestor->root || cgrp->level < ancestor->level)
		return false;
	return cgrp->ancestor_ids[ancestor->level] == ancestor->id;
}

/* no synchronization, the result can only be used as a hint */
/* no synchronization, the result can only be used as a hint */
static inline bool cgroup_is_populated(struct cgroup *cgrp)
static inline bool cgroup_is_populated(struct cgroup *cgrp)
{
{
+12 −0
Original line number Original line Diff line number Diff line
@@ -274,6 +274,8 @@ void pr_cont_kernfs_path(struct kernfs_node *kn);
struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn);
struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn);
struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent,
struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent,
					   const char *name, const void *ns);
					   const char *name, const void *ns);
struct kernfs_node *kernfs_walk_and_get_ns(struct kernfs_node *parent,
					   const char *path, const void *ns);
void kernfs_get(struct kernfs_node *kn);
void kernfs_get(struct kernfs_node *kn);
void kernfs_put(struct kernfs_node *kn);
void kernfs_put(struct kernfs_node *kn);


@@ -350,6 +352,10 @@ static inline struct kernfs_node *
kernfs_find_and_get_ns(struct kernfs_node *parent, const char *name,
kernfs_find_and_get_ns(struct kernfs_node *parent, const char *name,
		       const void *ns)
		       const void *ns)
{ return NULL; }
{ return NULL; }
static inline struct kernfs_node *
kernfs_walk_and_get_ns(struct kernfs_node *parent, const char *path,
		       const void *ns)
{ return NULL; }


static inline void kernfs_get(struct kernfs_node *kn) { }
static inline void kernfs_get(struct kernfs_node *kn) { }
static inline void kernfs_put(struct kernfs_node *kn) { }
static inline void kernfs_put(struct kernfs_node *kn) { }
@@ -430,6 +436,12 @@ kernfs_find_and_get(struct kernfs_node *kn, const char *name)
	return kernfs_find_and_get_ns(kn, name, NULL);
	return kernfs_find_and_get_ns(kn, name, NULL);
}
}


static inline struct kernfs_node *
kernfs_walk_and_get(struct kernfs_node *kn, const char *path)
{
	return kernfs_walk_and_get_ns(kn, path, NULL);
}

static inline struct kernfs_node *
static inline struct kernfs_node *
kernfs_create_dir(struct kernfs_node *parent, const char *name, umode_t mode,
kernfs_create_dir(struct kernfs_node *parent, const char *name, umode_t mode,
		  void *priv)
		  void *priv)
+44 −27
Original line number Original line Diff line number Diff line
@@ -441,11 +441,6 @@ static bool cgroup_tryget(struct cgroup *cgrp)
	return css_tryget(&cgrp->self);
	return css_tryget(&cgrp->self);
}
}


static void cgroup_put(struct cgroup *cgrp)
{
	css_put(&cgrp->self);
}

struct cgroup_subsys_state *of_css(struct kernfs_open_file *of)
struct cgroup_subsys_state *of_css(struct kernfs_open_file *of)
{
{
	struct cgroup *cgrp = of->kn->parent->priv;
	struct cgroup *cgrp = of->kn->parent->priv;
@@ -466,25 +461,6 @@ struct cgroup_subsys_state *of_css(struct kernfs_open_file *of)
}
}
EXPORT_SYMBOL_GPL(of_css);
EXPORT_SYMBOL_GPL(of_css);


/**
 * cgroup_is_descendant - test ancestry
 * @cgrp: the cgroup to be tested
 * @ancestor: possible ancestor of @cgrp
 *
 * Test whether @cgrp is a descendant of @ancestor.  It also returns %true
 * if @cgrp == @ancestor.  This function is safe to call as long as @cgrp
 * and @ancestor are accessible.
 */
bool cgroup_is_descendant(struct cgroup *cgrp, struct cgroup *ancestor)
{
	while (cgrp) {
		if (cgrp == ancestor)
			return true;
		cgrp = cgroup_parent(cgrp);
	}
	return false;
}

static int notify_on_release(const struct cgroup *cgrp)
static int notify_on_release(const struct cgroup *cgrp)
{
{
	return test_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
	return test_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
@@ -1912,6 +1888,7 @@ static int cgroup_setup_root(struct cgroup_root *root, unsigned long ss_mask)
	if (ret < 0)
	if (ret < 0)
		goto out;
		goto out;
	root_cgrp->id = ret;
	root_cgrp->id = ret;
	root_cgrp->ancestor_ids[0] = ret;


	ret = percpu_ref_init(&root_cgrp->self.refcnt, css_release, 0,
	ret = percpu_ref_init(&root_cgrp->self.refcnt, css_release, 0,
			      GFP_KERNEL);
			      GFP_KERNEL);
@@ -4901,11 +4878,11 @@ static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss,
static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
			umode_t mode)
			umode_t mode)
{
{
	struct cgroup *parent, *cgrp;
	struct cgroup *parent, *cgrp, *tcgrp;
	struct cgroup_root *root;
	struct cgroup_root *root;
	struct cgroup_subsys *ss;
	struct cgroup_subsys *ss;
	struct kernfs_node *kn;
	struct kernfs_node *kn;
	int ssid, ret;
	int level, ssid, ret;


	/* Do not accept '\n' to prevent making /proc/<pid>/cgroup unparsable.
	/* Do not accept '\n' to prevent making /proc/<pid>/cgroup unparsable.
	 */
	 */
@@ -4916,9 +4893,11 @@ static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
	if (!parent)
	if (!parent)
		return -ENODEV;
		return -ENODEV;
	root = parent->root;
	root = parent->root;
	level = parent->level + 1;


	/* allocate the cgroup and its ID, 0 is reserved for the root */
	/* allocate the cgroup and its ID, 0 is reserved for the root */
	cgrp = kzalloc(sizeof(*cgrp), GFP_KERNEL);
	cgrp = kzalloc(sizeof(*cgrp) +
		       sizeof(cgrp->ancestor_ids[0]) * (level + 1), GFP_KERNEL);
	if (!cgrp) {
	if (!cgrp) {
		ret = -ENOMEM;
		ret = -ENOMEM;
		goto out_unlock;
		goto out_unlock;
@@ -4942,6 +4921,10 @@ static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name,


	cgrp->self.parent = &parent->self;
	cgrp->self.parent = &parent->self;
	cgrp->root = root;
	cgrp->root = root;
	cgrp->level = level;

	for (tcgrp = cgrp; tcgrp; tcgrp = cgroup_parent(tcgrp))
		cgrp->ancestor_ids[tcgrp->level] = tcgrp->id;


	if (notify_on_release(parent))
	if (notify_on_release(parent))
		set_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
		set_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
@@ -5805,6 +5788,40 @@ struct cgroup_subsys_state *css_from_id(int id, struct cgroup_subsys *ss)
	return id > 0 ? idr_find(&ss->css_idr, id) : NULL;
	return id > 0 ? idr_find(&ss->css_idr, id) : NULL;
}
}


/**
 * cgroup_get_from_path - lookup and get a cgroup from its default hierarchy path
 * @path: path on the default hierarchy
 *
 * Find the cgroup at @path on the default hierarchy, increment its
 * reference count and return it.  Returns pointer to the found cgroup on
 * success, ERR_PTR(-ENOENT) if @path doens't exist and ERR_PTR(-ENOTDIR)
 * if @path points to a non-directory.
 */
struct cgroup *cgroup_get_from_path(const char *path)
{
	struct kernfs_node *kn;
	struct cgroup *cgrp;

	mutex_lock(&cgroup_mutex);

	kn = kernfs_walk_and_get(cgrp_dfl_root.cgrp.kn, path);
	if (kn) {
		if (kernfs_type(kn) == KERNFS_DIR) {
			cgrp = kn->priv;
			cgroup_get(cgrp);
		} else {
			cgrp = ERR_PTR(-ENOTDIR);
		}
		kernfs_put(kn);
	} else {
		cgrp = ERR_PTR(-ENOENT);
	}

	mutex_unlock(&cgroup_mutex);
	return cgrp;
}
EXPORT_SYMBOL_GPL(cgroup_get_from_path);

#ifdef CONFIG_CGROUP_DEBUG
#ifdef CONFIG_CGROUP_DEBUG
static struct cgroup_subsys_state *
static struct cgroup_subsys_state *
debug_css_alloc(struct cgroup_subsys_state *parent_css)
debug_css_alloc(struct cgroup_subsys_state *parent_css)