Merge branch 'for-4.5-ancestor-test' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
Preparatory changes for some new socket cgroup infrastructure and netfilter targets. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
bc9b145a09
|
@ -694,6 +694,29 @@ static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent,
|
|||
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
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @scops: optional syscall operations for the hierarchy
|
||||
|
|
|
@ -234,6 +234,14 @@ struct cgroup {
|
|||
*/
|
||||
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
|
||||
* one to populated_cnt. All children with non-zero popuplated_cnt
|
||||
|
@ -289,6 +297,9 @@ struct cgroup {
|
|||
|
||||
/* used to schedule release agent */
|
||||
struct work_struct release_agent_work;
|
||||
|
||||
/* ids of the ancestors at each level including self */
|
||||
int ancestor_ids[];
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -308,6 +319,9 @@ struct cgroup_root {
|
|||
/* The root cgroup. Root is destroyed on its release. */
|
||||
struct cgroup cgrp;
|
||||
|
||||
/* for cgrp->ancestor_ids[0] */
|
||||
int cgrp_ancestor_id_storage;
|
||||
|
||||
/* Number of cgroups in the hierarchy, used only for /proc/cgroups */
|
||||
atomic_t nr_cgrps;
|
||||
|
||||
|
|
|
@ -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 *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_transfer_tasks(struct cgroup *to, struct cgroup *from);
|
||||
|
||||
|
@ -352,6 +353,11 @@ static inline void css_put_many(struct cgroup_subsys_state *css, unsigned int 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: the task to obtain css_set for
|
||||
|
@ -459,6 +465,23 @@ static inline struct cgroup *task_cgroup(struct task_struct *task,
|
|||
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 */
|
||||
static inline bool cgroup_is_populated(struct cgroup *cgrp)
|
||||
{
|
||||
|
|
|
@ -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_find_and_get_ns(struct kernfs_node *parent,
|
||||
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_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,
|
||||
const void *ns)
|
||||
{ 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_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);
|
||||
}
|
||||
|
||||
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 *
|
||||
kernfs_create_dir(struct kernfs_node *parent, const char *name, umode_t mode,
|
||||
void *priv)
|
||||
|
|
|
@ -434,11 +434,6 @@ static bool cgroup_tryget(struct cgroup *cgrp)
|
|||
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 *cgrp = of->kn->parent->priv;
|
||||
|
@ -459,25 +454,6 @@ struct cgroup_subsys_state *of_css(struct kernfs_open_file *of)
|
|||
}
|
||||
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)
|
||||
{
|
||||
return test_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
|
||||
|
@ -1903,6 +1879,7 @@ static int cgroup_setup_root(struct cgroup_root *root, unsigned long ss_mask)
|
|||
if (ret < 0)
|
||||
goto out;
|
||||
root_cgrp->id = ret;
|
||||
root_cgrp->ancestor_ids[0] = ret;
|
||||
|
||||
ret = percpu_ref_init(&root_cgrp->self.refcnt, css_release, 0,
|
||||
GFP_KERNEL);
|
||||
|
@ -4846,11 +4823,11 @@ static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss,
|
|||
static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
|
||||
umode_t mode)
|
||||
{
|
||||
struct cgroup *parent, *cgrp;
|
||||
struct cgroup *parent, *cgrp, *tcgrp;
|
||||
struct cgroup_root *root;
|
||||
struct cgroup_subsys *ss;
|
||||
struct kernfs_node *kn;
|
||||
int ssid, ret;
|
||||
int level, ssid, ret;
|
||||
|
||||
/* Do not accept '\n' to prevent making /proc/<pid>/cgroup unparsable.
|
||||
*/
|
||||
|
@ -4861,9 +4838,11 @@ static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
|
|||
if (!parent)
|
||||
return -ENODEV;
|
||||
root = parent->root;
|
||||
level = parent->level + 1;
|
||||
|
||||
/* 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) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unlock;
|
||||
|
@ -4887,6 +4866,10 @@ static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
|
|||
|
||||
cgrp->self.parent = &parent->self;
|
||||
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))
|
||||
set_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
|
||||
|
@ -5765,6 +5748,40 @@ struct cgroup_subsys_state *css_from_id(int id, struct cgroup_subsys *ss)
|
|||
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
|
||||
static struct cgroup_subsys_state *
|
||||
debug_css_alloc(struct cgroup_subsys_state *parent_css)
|
||||
|
|
Loading…
Reference in New Issue