cgroup: remove cgroup->name

cgroup->name handling became quite complicated over time involving
dedicated struct cgroup_name for RCU protection.  Now that cgroup is
on kernfs, we can drop all of it and simply use kernfs_name/path() and
friends.  Replace cgroup->name and all related code with kernfs
name/path constructs.

* Reimplement cgroup_name() and cgroup_path() as thin wrappers on top
  of kernfs counterparts, which involves semantic changes.
  pr_cont_cgroup_name() and pr_cont_cgroup_path() added.

* cgroup->name handling dropped from cgroup_rename().

* All users of cgroup_name/path() updated to the new semantics.  Users
  which were formatting the string just to printk them are converted
  to use pr_cont_cgroup_name/path() instead, which simplifies things
  quite a bit.  As cgroup_name() no longer requires RCU read lock
  around it, RCU lockings which were protecting only cgroup_name() are
  removed.

v2: Comment above oom_info_lock updated as suggested by Michal.

v3: dummy_top doesn't have a kn associated and
    pr_cont_cgroup_name/path() ended up calling the matching kernfs
    functions with NULL kn leading to oops.  Test for NULL kn and
    print "/" if so.  This issue was reported by Fengguang Wu.

v4: Rebased on top of 0ab02ca8f8 ("cgroup: protect modifications to
    cgroup_idr with cgroup_mutex").

Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Acked-by: Michal Hocko <mhocko@suse.cz>
Acked-by: Li Zefan <lizefan@huawei.com>
Cc: Fengguang Wu <fengguang.wu@intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Balbir Singh <bsingharora@gmail.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
This commit is contained in:
Tejun Heo 2014-02-12 09:29:50 -05:00
parent 6f30558f37
commit e61734c55c
7 changed files with 110 additions and 210 deletions

View file

@ -145,8 +145,6 @@ static int cgroup_root_count;
/* hierarchy ID allocation and mapping, protected by cgroup_mutex */
static DEFINE_IDR(cgroup_hierarchy_idr);
static struct cgroup_name root_cgroup_name = { .name = "/" };
/*
* Assign a monotonically increasing serial number to cgroups. It
* guarantees cgroups with bigger numbers are newer than those with smaller
@ -888,17 +886,6 @@ static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask);
static struct kernfs_syscall_ops cgroup_kf_syscall_ops;
static const struct file_operations proc_cgroupstats_operations;
static struct cgroup_name *cgroup_alloc_name(const char *name_str)
{
struct cgroup_name *name;
name = kmalloc(sizeof(*name) + strlen(name_str) + 1, GFP_KERNEL);
if (!name)
return NULL;
strcpy(name->name, name_str);
return name;
}
static char *cgroup_file_name(struct cgroup *cgrp, const struct cftype *cft,
char *buf)
{
@ -958,8 +945,6 @@ static void cgroup_free_fn(struct work_struct *work)
cgroup_pidlist_destroy_all(cgrp);
kernfs_put(cgrp->kn);
kfree(rcu_dereference_raw(cgrp->name));
kfree(cgrp);
}
@ -1377,7 +1362,6 @@ static void init_cgroup_root(struct cgroupfs_root *root)
INIT_LIST_HEAD(&root->root_list);
root->number_of_cgroups = 1;
cgrp->root = root;
RCU_INIT_POINTER(cgrp->name, &root_cgroup_name);
init_cgroup_housekeeping(cgrp);
idr_init(&root->cgroup_idr);
}
@ -1597,57 +1581,6 @@ static struct file_system_type cgroup_fs_type = {
static struct kobject *cgroup_kobj;
/**
* cgroup_path - generate the path of a cgroup
* @cgrp: the cgroup in question
* @buf: the buffer to write the path into
* @buflen: the length of the buffer
*
* Writes path of cgroup into buf. Returns 0 on success, -errno on error.
*
* We can't generate cgroup path using dentry->d_name, as accessing
* dentry->name must be protected by irq-unsafe dentry->d_lock or parent
* inode's i_mutex, while on the other hand cgroup_path() can be called
* with some irq-safe spinlocks held.
*/
int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
{
int ret = -ENAMETOOLONG;
char *start;
if (!cgrp->parent) {
if (strlcpy(buf, "/", buflen) >= buflen)
return -ENAMETOOLONG;
return 0;
}
start = buf + buflen - 1;
*start = '\0';
rcu_read_lock();
do {
const char *name = cgroup_name(cgrp);
int len;
len = strlen(name);
if ((start -= len) < buf)
goto out;
memcpy(start, name, len);
if (--start < buf)
goto out;
*start = '/';
cgrp = cgrp->parent;
} while (cgrp->parent);
ret = 0;
memmove(buf, start, buf + buflen - start);
out:
rcu_read_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(cgroup_path);
/**
* task_cgroup_path - cgroup path of a task in the first cgroup hierarchy
* @task: target task
@ -1659,16 +1592,14 @@ EXPORT_SYMBOL_GPL(cgroup_path);
* function grabs cgroup_mutex and shouldn't be used inside locks used by
* cgroup controller callbacks.
*
* Returns 0 on success, fails with -%ENAMETOOLONG if @buflen is too short.
* Return value is the same as kernfs_path().
*/
int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen)
char *task_cgroup_path(struct task_struct *task, char *buf, size_t buflen)
{
struct cgroupfs_root *root;
struct cgroup *cgrp;
int hierarchy_id = 1, ret = 0;
if (buflen < 2)
return -ENAMETOOLONG;
int hierarchy_id = 1;
char *path = NULL;
mutex_lock(&cgroup_mutex);
@ -1676,14 +1607,15 @@ int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen)
if (root) {
cgrp = task_cgroup_from_root(task, root);
ret = cgroup_path(cgrp, buf, buflen);
path = cgroup_path(cgrp, buf, buflen);
} else {
/* if no hierarchy exists, everyone is in "/" */
memcpy(buf, "/", 2);
if (strlcpy(buf, "/", buflen) < buflen)
path = buf;
}
mutex_unlock(&cgroup_mutex);
return ret;
return path;
}
EXPORT_SYMBOL_GPL(task_cgroup_path);
@ -2211,7 +2143,6 @@ static int cgroup_rename(struct kernfs_node *kn, struct kernfs_node *new_parent,
const char *new_name_str)
{
struct cgroup *cgrp = kn->priv;
struct cgroup_name *name, *old_name;
int ret;
if (kernfs_type(kn) != KERNFS_DIR)
@ -2226,25 +2157,13 @@ static int cgroup_rename(struct kernfs_node *kn, struct kernfs_node *new_parent,
if (cgroup_sane_behavior(cgrp))
return -EPERM;
name = cgroup_alloc_name(new_name_str);
if (!name)
return -ENOMEM;
mutex_lock(&cgroup_tree_mutex);
mutex_lock(&cgroup_mutex);
ret = kernfs_rename(kn, new_parent, new_name_str);
if (!ret) {
old_name = rcu_dereference_protected(cgrp->name, true);
rcu_assign_pointer(cgrp->name, name);
} else {
old_name = name;
}
mutex_unlock(&cgroup_mutex);
mutex_unlock(&cgroup_tree_mutex);
kfree_rcu(old_name, rcu_head);
return ret;
}
@ -3719,14 +3638,13 @@ err_free:
/**
* cgroup_create - create a cgroup
* @parent: cgroup that will be parent of the new cgroup
* @name_str: name of the new cgroup
* @name: name of the new cgroup
* @mode: mode to set on new cgroup
*/
static long cgroup_create(struct cgroup *parent, const char *name_str,
static long cgroup_create(struct cgroup *parent, const char *name,
umode_t mode)
{
struct cgroup *cgrp;
struct cgroup_name *name;
struct cgroupfs_root *root = parent->root;
int ssid, err;
struct cgroup_subsys *ss;
@ -3737,13 +3655,6 @@ static long cgroup_create(struct cgroup *parent, const char *name_str,
if (!cgrp)
return -ENOMEM;
name = cgroup_alloc_name(name_str);
if (!name) {
err = -ENOMEM;
goto err_free_cgrp;
}
rcu_assign_pointer(cgrp->name, name);
mutex_lock(&cgroup_tree_mutex);
/*
@ -3781,7 +3692,7 @@ static long cgroup_create(struct cgroup *parent, const char *name_str,
set_bit(CGRP_CPUSET_CLONE_CHILDREN, &cgrp->flags);
/* create the directory */
kn = kernfs_create_dir(parent->kn, name->name, mode, cgrp);
kn = kernfs_create_dir(parent->kn, name, mode, cgrp);
if (IS_ERR(kn)) {
err = PTR_ERR(kn);
goto err_free_id;
@ -3839,8 +3750,6 @@ err_unlock:
mutex_unlock(&cgroup_mutex);
err_unlock_tree:
mutex_unlock(&cgroup_tree_mutex);
kfree(rcu_dereference_raw(cgrp->name));
err_free_cgrp:
kfree(cgrp);
return err;
@ -4304,12 +4213,12 @@ int proc_cgroup_show(struct seq_file *m, void *v)
{
struct pid *pid;
struct task_struct *tsk;
char *buf;
char *buf, *path;
int retval;
struct cgroupfs_root *root;
retval = -ENOMEM;
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
buf = kmalloc(PATH_MAX, GFP_KERNEL);
if (!buf)
goto out;
@ -4337,10 +4246,12 @@ int proc_cgroup_show(struct seq_file *m, void *v)
root->name);
seq_putc(m, ':');
cgrp = task_cgroup_from_root(tsk, root);
retval = cgroup_path(cgrp, buf, PAGE_SIZE);
if (retval < 0)
path = cgroup_path(cgrp, buf, PATH_MAX);
if (!path) {
retval = -ENAMETOOLONG;
goto out_unlock;
seq_puts(m, buf);
}
seq_puts(m, path);
seq_putc(m, '\n');
}
@ -4588,16 +4499,17 @@ static void cgroup_release_agent(struct work_struct *work)
while (!list_empty(&release_list)) {
char *argv[3], *envp[3];
int i;
char *pathbuf = NULL, *agentbuf = NULL;
char *pathbuf = NULL, *agentbuf = NULL, *path;
struct cgroup *cgrp = list_entry(release_list.next,
struct cgroup,
release_list);
list_del_init(&cgrp->release_list);
raw_spin_unlock(&release_list_lock);
pathbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
if (!pathbuf)
goto continue_free;
if (cgroup_path(cgrp, pathbuf, PAGE_SIZE) < 0)
path = cgroup_path(cgrp, pathbuf, PATH_MAX);
if (!path)
goto continue_free;
agentbuf = kstrdup(cgrp->root->release_agent_path, GFP_KERNEL);
if (!agentbuf)
@ -4605,7 +4517,7 @@ static void cgroup_release_agent(struct work_struct *work)
i = 0;
argv[i++] = agentbuf;
argv[i++] = pathbuf;
argv[i++] = path;
argv[i] = NULL;
i = 0;
@ -4755,6 +4667,11 @@ static int current_css_set_cg_links_read(struct seq_file *seq, void *v)
{
struct cgrp_cset_link *link;
struct css_set *cset;
char *name_buf;
name_buf = kmalloc(NAME_MAX + 1, GFP_KERNEL);
if (!name_buf)
return -ENOMEM;
read_lock(&css_set_lock);
rcu_read_lock();
@ -4763,14 +4680,17 @@ static int current_css_set_cg_links_read(struct seq_file *seq, void *v)
struct cgroup *c = link->cgrp;
const char *name = "?";
if (c != cgroup_dummy_top)
name = cgroup_name(c);
if (c != cgroup_dummy_top) {
cgroup_name(c, name_buf, NAME_MAX + 1);
name = name_buf;
}
seq_printf(seq, "Root %d group %s\n",
c->root->hierarchy_id, name);
}
rcu_read_unlock();
read_unlock(&css_set_lock);
kfree(name_buf);
return 0;
}