Add a cgroup.api control file in every cgroup directory. This reports
for each control file the type of data represented by that control
file, and a user-friendly description of the contents.

A secondary effect of this patch is to add the "cgroup." prefix in
front of all cgroup-provided control files. This will reduce the
chance of future control files clashing with user-provided names.

Signed-off-by: Paul Menage <[EMAIL PROTECTED]>

---
 include/linux/cgroup.h |   21 +++++++
 kernel/cgroup.c        |  133 ++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 148 insertions(+), 6 deletions(-)

Index: cgroupmap-2.6.24-mm1/include/linux/cgroup.h
===================================================================
--- cgroupmap-2.6.24-mm1.orig/include/linux/cgroup.h
+++ cgroupmap-2.6.24-mm1/include/linux/cgroup.h
@@ -179,12 +179,33 @@ struct css_set {
  *     - the 'cftype' of the file is file->f_dentry->d_fsdata
  */
 
+/*
+ * The various types of control file that are reported in the
+ * cgroup.api file. "String" is a catch-all default, but should only
+ * be used for special cases. If you use the appropriate accessors
+ * (such as "read_uint") in your control file, then you can leave this
+ * as 0 (CGROUP_FILE_UNKNOWN) and let cgroup figure out the right type.
+ */
+enum cgroup_file_type {
+       CGROUP_FILE_UNKNOWN = 0,
+       CGROUP_FILE_VOID,
+       CGROUP_FILE_U64,
+       CGROUP_FILE_STRING,
+};
+
 #define MAX_CFTYPE_NAME 64
 struct cftype {
        /* By convention, the name should begin with the name of the
         * subsystem, followed by a period */
        char name[MAX_CFTYPE_NAME];
        int private;
+
+       /* The type of a file - reported in the cgroup.api file */
+       enum cgroup_file_type type;
+
+       /* Human-readable description of the file */
+       const char *desc;
+
        int (*open) (struct inode *inode, struct file *file);
        ssize_t (*read) (struct cgroup *cont, struct cftype *cft,
                         struct file *file,
Index: cgroupmap-2.6.24-mm1/kernel/cgroup.c
===================================================================
--- cgroupmap-2.6.24-mm1.orig/kernel/cgroup.c
+++ cgroupmap-2.6.24-mm1/kernel/cgroup.c
@@ -1301,6 +1301,7 @@ enum cgroup_filetype {
        FILE_NOTIFY_ON_RELEASE,
        FILE_RELEASABLE,
        FILE_RELEASE_AGENT,
+       FILE_API,
 };
 
 static ssize_t cgroup_write_uint(struct cgroup *cgrp, struct cftype *cft,
@@ -1611,17 +1612,21 @@ static int cgroup_create_dir(struct cgro
 }
 
 int cgroup_add_file(struct cgroup *cgrp,
-                      struct cgroup_subsys *subsys,
-                      const struct cftype *cft)
+                   struct cgroup_subsys *subsys,
+                   const struct cftype *cft)
 {
        struct dentry *dir = cgrp->dentry;
        struct dentry *dentry;
        int error;
 
        char name[MAX_CGROUP_TYPE_NAMELEN + MAX_CFTYPE_NAME + 2] = { 0 };
-       if (subsys && !test_bit(ROOT_NOPREFIX, &cgrp->root->flags)) {
-               strcpy(name, subsys->name);
-               strcat(name, ".");
+       if (!test_bit(ROOT_NOPREFIX, &cgrp->root->flags)) {
+               if (subsys) {
+                       strcpy(name, subsys->name);
+                       strcat(name, ".");
+               } else {
+                       strcpy(name, "cgroup.");
+               }
        }
        strcat(name, cft->name);
        BUG_ON(!mutex_is_locked(&dir->d_inode->i_mutex));
@@ -2126,6 +2131,110 @@ static u64 cgroup_read_releasable(struct
        return test_bit(CGRP_RELEASABLE, &cgrp->flags);
 }
 
+static const struct file_operations cgroup_api_file_operations = {
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+/*
+ * cgroup.api is a file in each cgroup directory that gives the types
+ * and descriptions of the various control files in that directory.
+ */
+
+static struct dentry *cgroup_api_advance(struct dentry *d, int advance)
+{
+       struct dentry *parent = d->d_parent;
+       struct list_head *l = &d->d_u.d_child;
+       while (true) {
+               if (advance)
+                       l = l->next;
+               advance = true;
+               /* Did we reach the end of the directory? */
+               if (l == &parent->d_subdirs)
+                       return NULL;
+               d = container_of(l, struct dentry, d_u.d_child);
+               /* Skip cgroup subdirectories */
+               if (d->d_inode && S_ISREG(d->d_inode->i_mode))
+                       return d;
+       }
+}
+
+static void *cgroup_api_start(struct seq_file *sf, loff_t *pos)
+{
+       struct dentry *parent = sf->private;
+       struct dentry *d;
+       loff_t l = 0;
+       spin_lock(&dcache_lock);
+       if (list_empty(&parent->d_subdirs))
+               return NULL;
+       d = container_of(parent->d_subdirs.next, struct dentry, d_u.d_child);
+       d = cgroup_api_advance(d, 0);
+       while (d && l < *pos) {
+               (*pos)++;
+               d = cgroup_api_advance(d, 1);
+       }
+
+       return d;
+}
+
+static void *cgroup_api_next(struct seq_file *sf, void *v, loff_t *pos)
+{
+       struct dentry *d = v;
+       (*pos)++;
+       return cgroup_api_advance(d, 1);
+}
+
+static void cgroup_api_stop(struct seq_file *sf, void *v)
+{
+       spin_unlock(&dcache_lock);
+}
+
+static const char *cft_type_names[] = {
+       "unknown",
+       "void",
+       "u64",
+       "string",
+       "u64map",
+};
+
+static int cgroup_api_show(struct seq_file *sf, void *v)
+{
+       struct dentry *d = v;
+       struct cftype *cft = __d_cft(d);
+       unsigned type = cft->type;
+       if (type == CGROUP_FILE_UNKNOWN) {
+               if (cft->read_uint)
+                       type = CGROUP_FILE_U64;
+               else if (cft->read)
+                       type = CGROUP_FILE_STRING;
+               else if (!cft->open)
+                       type = CGROUP_FILE_VOID;
+       }
+       if (type >= ARRAY_SIZE(cft_type_names))
+               type = CGROUP_FILE_UNKNOWN;
+       return seq_printf(sf, "%s\t%s\t%s\n", d->d_name.name,
+                         cft_type_names[type], cft->desc ?: "");
+}
+
+static const struct seq_operations cgroup_api_seqop = {
+       .start = cgroup_api_start,
+       .next = cgroup_api_next,
+       .stop = cgroup_api_stop,
+       .show = cgroup_api_show,
+};
+
+static int cgroup_api_open(struct inode *inode, struct file *file)
+{
+       int ret = seq_open(file, &cgroup_api_seqop);
+       if (ret == 0) {
+               struct seq_file *sf = file->private_data;
+               sf->private = file->f_dentry->d_parent;
+               file->f_op = &cgroup_api_file_operations;
+       }
+       return ret;
+}
+
 /*
  * for the common functions, 'private' gives the type of file
  */
@@ -2137,6 +2246,7 @@ static struct cftype files[] = {
                .write = cgroup_common_file_write,
                .release = cgroup_tasks_release,
                .private = FILE_TASKLIST,
+               .desc = "Thread ids of threads in this cgroup",
        },
 
        {
@@ -2144,13 +2254,23 @@ static struct cftype files[] = {
                .read_uint = cgroup_read_notify_on_release,
                .write = cgroup_common_file_write,
                .private = FILE_NOTIFY_ON_RELEASE,
+               .desc =
+               "Should the release agent trigger when this cgroup is empty",
        },
 
        {
                .name = "releasable",
                .read_uint = cgroup_read_releasable,
                .private = FILE_RELEASABLE,
-       }
+               .desc = "Is this cgroup able to be freed when empty"
+       },
+
+       {
+               .name = "api",
+               .open = cgroup_api_open,
+               .private = FILE_API,
+               .desc = "Control file descriptions",
+       },
 };
 
 static struct cftype cft_release_agent = {
@@ -2158,6 +2278,7 @@ static struct cftype cft_release_agent =
        .read = cgroup_common_file_read,
        .write = cgroup_common_file_write,
        .private = FILE_RELEASE_AGENT,
+       .desc = "Path to release agent binary",
 };
 
 static int cgroup_populate_dir(struct cgroup *cgrp)

--
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to