|
@@ -147,6 +147,15 @@ struct cgroupfs_root {
|
|
|
*/
|
|
|
static struct cgroupfs_root rootnode;
|
|
|
|
|
|
+/*
|
|
|
+ * cgroupfs file entry, pointed to from leaf dentry->d_fsdata.
|
|
|
+ */
|
|
|
+struct cfent {
|
|
|
+ struct list_head node;
|
|
|
+ struct dentry *dentry;
|
|
|
+ struct cftype *type;
|
|
|
+};
|
|
|
+
|
|
|
/*
|
|
|
* CSS ID -- ID per subsys's Cgroup Subsys State(CSS). used only when
|
|
|
* cgroup_subsys->use_id != 0.
|
|
@@ -287,11 +296,16 @@ static inline struct cgroup *__d_cgrp(struct dentry *dentry)
|
|
|
return dentry->d_fsdata;
|
|
|
}
|
|
|
|
|
|
-static inline struct cftype *__d_cft(struct dentry *dentry)
|
|
|
+static inline struct cfent *__d_cfe(struct dentry *dentry)
|
|
|
{
|
|
|
return dentry->d_fsdata;
|
|
|
}
|
|
|
|
|
|
+static inline struct cftype *__d_cft(struct dentry *dentry)
|
|
|
+{
|
|
|
+ return __d_cfe(dentry)->type;
|
|
|
+}
|
|
|
+
|
|
|
/* the list of cgroups eligible for automatic release. Protected by
|
|
|
* release_list_lock */
|
|
|
static LIST_HEAD(release_list);
|
|
@@ -877,6 +891,14 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
|
|
|
BUG_ON(!list_empty(&cgrp->pidlists));
|
|
|
|
|
|
kfree_rcu(cgrp, rcu_head);
|
|
|
+ } else {
|
|
|
+ struct cfent *cfe = __d_cfe(dentry);
|
|
|
+ struct cgroup *cgrp = dentry->d_parent->d_fsdata;
|
|
|
+
|
|
|
+ WARN_ONCE(!list_empty(&cfe->node) &&
|
|
|
+ cgrp != &cgrp->root->top_cgroup,
|
|
|
+ "cfe still linked for %s\n", cfe->type->name);
|
|
|
+ kfree(cfe);
|
|
|
}
|
|
|
iput(inode);
|
|
|
}
|
|
@@ -895,34 +917,36 @@ static void remove_dir(struct dentry *d)
|
|
|
dput(parent);
|
|
|
}
|
|
|
|
|
|
-static void cgroup_clear_directory(struct dentry *dentry)
|
|
|
-{
|
|
|
- struct list_head *node;
|
|
|
-
|
|
|
- BUG_ON(!mutex_is_locked(&dentry->d_inode->i_mutex));
|
|
|
- spin_lock(&dentry->d_lock);
|
|
|
- node = dentry->d_subdirs.next;
|
|
|
- while (node != &dentry->d_subdirs) {
|
|
|
- struct dentry *d = list_entry(node, struct dentry, d_u.d_child);
|
|
|
-
|
|
|
- spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED);
|
|
|
- list_del_init(node);
|
|
|
- if (d->d_inode) {
|
|
|
- /* This should never be called on a cgroup
|
|
|
- * directory with child cgroups */
|
|
|
- BUG_ON(d->d_inode->i_mode & S_IFDIR);
|
|
|
- dget_dlock(d);
|
|
|
- spin_unlock(&d->d_lock);
|
|
|
- spin_unlock(&dentry->d_lock);
|
|
|
- d_delete(d);
|
|
|
- simple_unlink(dentry->d_inode, d);
|
|
|
- dput(d);
|
|
|
- spin_lock(&dentry->d_lock);
|
|
|
- } else
|
|
|
- spin_unlock(&d->d_lock);
|
|
|
- node = dentry->d_subdirs.next;
|
|
|
+static int cgroup_rm_file(struct cgroup *cgrp, const struct cftype *cft)
|
|
|
+{
|
|
|
+ struct cfent *cfe;
|
|
|
+
|
|
|
+ lockdep_assert_held(&cgrp->dentry->d_inode->i_mutex);
|
|
|
+ lockdep_assert_held(&cgroup_mutex);
|
|
|
+
|
|
|
+ list_for_each_entry(cfe, &cgrp->files, node) {
|
|
|
+ struct dentry *d = cfe->dentry;
|
|
|
+
|
|
|
+ if (cft && cfe->type != cft)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ dget(d);
|
|
|
+ d_delete(d);
|
|
|
+ simple_unlink(d->d_inode, d);
|
|
|
+ list_del_init(&cfe->node);
|
|
|
+ dput(d);
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
- spin_unlock(&dentry->d_lock);
|
|
|
+ return -ENOENT;
|
|
|
+}
|
|
|
+
|
|
|
+static void cgroup_clear_directory(struct dentry *dir)
|
|
|
+{
|
|
|
+ struct cgroup *cgrp = __d_cgrp(dir);
|
|
|
+
|
|
|
+ while (!list_empty(&cgrp->files))
|
|
|
+ cgroup_rm_file(cgrp, NULL);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1352,6 +1376,7 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp)
|
|
|
{
|
|
|
INIT_LIST_HEAD(&cgrp->sibling);
|
|
|
INIT_LIST_HEAD(&cgrp->children);
|
|
|
+ INIT_LIST_HEAD(&cgrp->files);
|
|
|
INIT_LIST_HEAD(&cgrp->css_sets);
|
|
|
INIT_LIST_HEAD(&cgrp->release_list);
|
|
|
INIT_LIST_HEAD(&cgrp->pidlists);
|
|
@@ -2619,7 +2644,9 @@ static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys,
|
|
|
const struct cftype *cft)
|
|
|
{
|
|
|
struct dentry *dir = cgrp->dentry;
|
|
|
+ struct cgroup *parent = __d_cgrp(dir);
|
|
|
struct dentry *dentry;
|
|
|
+ struct cfent *cfe;
|
|
|
int error;
|
|
|
umode_t mode;
|
|
|
char name[MAX_CGROUP_TYPE_NAMELEN + MAX_CFTYPE_NAME + 2] = { 0 };
|
|
@@ -2635,17 +2662,31 @@ static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys,
|
|
|
strcat(name, ".");
|
|
|
}
|
|
|
strcat(name, cft->name);
|
|
|
+
|
|
|
BUG_ON(!mutex_is_locked(&dir->d_inode->i_mutex));
|
|
|
+
|
|
|
+ cfe = kzalloc(sizeof(*cfe), GFP_KERNEL);
|
|
|
+ if (!cfe)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
dentry = lookup_one_len(name, dir, strlen(name));
|
|
|
- if (!IS_ERR(dentry)) {
|
|
|
- mode = cgroup_file_mode(cft);
|
|
|
- error = cgroup_create_file(dentry, mode | S_IFREG,
|
|
|
- cgrp->root->sb);
|
|
|
- if (!error)
|
|
|
- dentry->d_fsdata = (void *)cft;
|
|
|
- dput(dentry);
|
|
|
- } else
|
|
|
+ if (IS_ERR(dentry)) {
|
|
|
error = PTR_ERR(dentry);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ mode = cgroup_file_mode(cft);
|
|
|
+ error = cgroup_create_file(dentry, mode | S_IFREG, cgrp->root->sb);
|
|
|
+ if (!error) {
|
|
|
+ cfe->type = (void *)cft;
|
|
|
+ cfe->dentry = dentry;
|
|
|
+ dentry->d_fsdata = cfe;
|
|
|
+ list_add_tail(&cfe->node, &parent->files);
|
|
|
+ cfe = NULL;
|
|
|
+ }
|
|
|
+ dput(dentry);
|
|
|
+out:
|
|
|
+ kfree(cfe);
|
|
|
return error;
|
|
|
}
|
|
|
|