Skip to content
cgroup.c 29.7 KiB
Newer Older
	/* The cgroup directory was pre-locked for us */
	BUG_ON(!mutex_is_locked(&cont->dentry->d_inode->i_mutex));

	err = cgroup_populate_dir(cont);
	/* If err < 0, we have a half-filled directory - oh well ;) */

	mutex_unlock(&cgroup_mutex);
	mutex_unlock(&cont->dentry->d_inode->i_mutex);

	return 0;

 err_remove:

	list_del(&cont->sibling);
	root->number_of_cgroups--;

 err_destroy:

	for_each_subsys(root, ss) {
		if (cont->subsys[ss->subsys_id])
			ss->destroy(ss, cont);
	}

	mutex_unlock(&cgroup_mutex);

	/* Release the reference count that we took on the superblock */
	deactivate_super(sb);

	kfree(cont);
	return err;
}

static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
	struct cgroup *c_parent = dentry->d_parent->d_fsdata;

	/* the vfs holds inode->i_mutex already */
	return cgroup_create(c_parent, dentry, mode | S_IFDIR);
}

static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
{
	struct cgroup *cont = dentry->d_fsdata;
	struct dentry *d;
	struct cgroup *parent;
	struct cgroup_subsys *ss;
	struct super_block *sb;
	struct cgroupfs_root *root;
	int css_busy = 0;

	/* the vfs holds both inode->i_mutex already */

	mutex_lock(&cgroup_mutex);
	if (atomic_read(&cont->count) != 0) {
		mutex_unlock(&cgroup_mutex);
		return -EBUSY;
	}
	if (!list_empty(&cont->children)) {
		mutex_unlock(&cgroup_mutex);
		return -EBUSY;
	}

	parent = cont->parent;
	root = cont->root;
	sb = root->sb;

	/* Check the reference count on each subsystem. Since we
	 * already established that there are no tasks in the
	 * cgroup, if the css refcount is also 0, then there should
	 * be no outstanding references, so the subsystem is safe to
	 * destroy */
	for_each_subsys(root, ss) {
		struct cgroup_subsys_state *css;
		css = cont->subsys[ss->subsys_id];
		if (atomic_read(&css->refcnt)) {
			css_busy = 1;
			break;
		}
	}
	if (css_busy) {
		mutex_unlock(&cgroup_mutex);
		return -EBUSY;
	}

	for_each_subsys(root, ss) {
		if (cont->subsys[ss->subsys_id])
			ss->destroy(ss, cont);
	}

	set_bit(CONT_REMOVED, &cont->flags);
	/* delete my sibling from parent->children */
	list_del(&cont->sibling);
	spin_lock(&cont->dentry->d_lock);
	d = dget(cont->dentry);
	cont->dentry = NULL;
	spin_unlock(&d->d_lock);

	cgroup_d_remove_dir(d);
	dput(d);
	root->number_of_cgroups--;

	mutex_unlock(&cgroup_mutex);
	/* Drop the active superblock reference that we took when we
	 * created the cgroup */
	deactivate_super(sb);
	return 0;
}

static void cgroup_init_subsys(struct cgroup_subsys *ss)
{
	struct task_struct *g, *p;
	struct cgroup_subsys_state *css;
	printk(KERN_ERR "Initializing cgroup subsys %s\n", ss->name);

	/* Create the top cgroup state for this subsystem */
	ss->root = &rootnode;
	css = ss->create(ss, dummytop);
	/* We don't handle early failures gracefully */
	BUG_ON(IS_ERR(css));
	init_cgroup_css(css, ss, dummytop);

	/* Update all tasks to contain a subsys pointer to this state
	 * - since the subsystem is newly registered, all tasks are in
	 * the subsystem's top cgroup. */

 	/* If this subsystem requested that it be notified with fork
 	 * events, we should send it one now for every process in the
 	 * system */

	read_lock(&tasklist_lock);
	init_task.cgroups.subsys[ss->subsys_id] = css;
	if (ss->fork)
		ss->fork(ss, &init_task);

	do_each_thread(g, p) {
		printk(KERN_INFO "Setting task %p css to %p (%d)\n", css, p, p->pid);
		p->cgroups.subsys[ss->subsys_id] = css;
		if (ss->fork)
			ss->fork(ss, p);
	} while_each_thread(g, p);
	read_unlock(&tasklist_lock);

	need_forkexit_callback |= ss->fork || ss->exit;

	ss->active = 1;
}

/**
 * cgroup_init_early - initialize cgroups at system boot, and
 * initialize any subsystems that request early init.
 */
int __init cgroup_init_early(void)
{
	int i;
	init_cgroup_root(&rootnode);
	list_add(&rootnode.root_list, &roots);

	for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
		struct cgroup_subsys *ss = subsys[i];

		BUG_ON(!ss->name);
		BUG_ON(strlen(ss->name) > MAX_CGROUP_TYPE_NAMELEN);
		BUG_ON(!ss->create);
		BUG_ON(!ss->destroy);
		if (ss->subsys_id != i) {
			printk(KERN_ERR "Subsys %s id == %d\n",
			       ss->name, ss->subsys_id);
			BUG();
		}

		if (ss->early_init)
			cgroup_init_subsys(ss);
	}
	return 0;
}

/**
 * cgroup_init - register cgroup filesystem and /proc file, and
 * initialize any subsystems that didn't request early init.
 */
int __init cgroup_init(void)
{
	int err;
	int i;

	for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
		struct cgroup_subsys *ss = subsys[i];
		if (!ss->early_init)
			cgroup_init_subsys(ss);
	}

	err = register_filesystem(&cgroup_fs_type);
	if (err < 0)
		goto out;

out:
	return err;
}