cgroup: remove cftype->read(), ->read_map() and ->write()
[platform/adaptation/renesas_rcar/renesas_kernel.git] / kernel / cgroup.c
index 671cbde..b132ff9 100644 (file)
@@ -2324,8 +2324,6 @@ static ssize_t cgroup_file_write(struct file *file, const char __user *buf,
        struct cftype *cft = __d_cft(file->f_dentry);
        struct cgroup_subsys_state *css = cfe->css;
 
-       if (cft->write)
-               return cft->write(css, cft, file, buf, nbytes, ppos);
        if (cft->write_u64 || cft->write_s64)
                return cgroup_write_X64(css, cft, file, buf, nbytes, ppos);
        if (cft->write_string)
@@ -2366,8 +2364,6 @@ static ssize_t cgroup_file_read(struct file *file, char __user *buf,
        struct cftype *cft = __d_cft(file->f_dentry);
        struct cgroup_subsys_state *css = cfe->css;
 
-       if (cft->read)
-               return cft->read(css, cft, file, buf, nbytes, ppos);
        if (cft->read_u64)
                return cgroup_read_u64(css, cft, file, buf, nbytes, ppos);
        if (cft->read_s64)
@@ -2380,25 +2376,12 @@ static ssize_t cgroup_file_read(struct file *file, char __user *buf,
  * supports string->u64 maps, but can be extended in future.
  */
 
-static int cgroup_map_add(struct cgroup_map_cb *cb, const char *key, u64 value)
-{
-       struct seq_file *sf = cb->state;
-       return seq_printf(sf, "%s %llu\n", key, (unsigned long long)value);
-}
-
 static int cgroup_seqfile_show(struct seq_file *m, void *arg)
 {
        struct cfent *cfe = m->private;
        struct cftype *cft = cfe->type;
        struct cgroup_subsys_state *css = cfe->css;
 
-       if (cft->read_map) {
-               struct cgroup_map_cb cb = {
-                       .fill = cgroup_map_add,
-                       .state = m,
-               };
-               return cft->read_map(css, cft, &cb);
-       }
        return cft->read_seq_string(css, cft, m);
 }
 
@@ -2444,7 +2427,7 @@ static int cgroup_file_open(struct inode *inode, struct file *file)
        WARN_ON_ONCE(cfe->css && cfe->css != css);
        cfe->css = css;
 
-       if (cft->read_map || cft->read_seq_string) {
+       if (cft->read_seq_string) {
                file->f_op = &cgroup_seqfile_operations;
                err = single_open(file, cgroup_seqfile_show, cfe);
        } else if (cft->open) {
@@ -2658,12 +2641,11 @@ static umode_t cgroup_file_mode(const struct cftype *cft)
        if (cft->mode)
                return cft->mode;
 
-       if (cft->read || cft->read_u64 || cft->read_s64 ||
-           cft->read_map || cft->read_seq_string)
+       if (cft->read_u64 || cft->read_s64 || cft->read_seq_string)
                mode |= S_IRUGO;
 
-       if (cft->write || cft->write_u64 || cft->write_s64 ||
-           cft->write_string || cft->trigger)
+       if (cft->write_u64 || cft->write_s64 || cft->write_string ||
+           cft->trigger)
                mode |= S_IWUSR;
 
        return mode;
@@ -3456,8 +3438,6 @@ struct cgroup_pidlist {
        pid_t *list;
        /* how many elements the above list has */
        int length;
-       /* how many files are using the current array */
-       int use_count;
        /* each of these stored in a list by its cgroup */
        struct list_head links;
        /* pointer to the cgroup we belong to, for list removal purposes */
@@ -3473,8 +3453,6 @@ struct cgroup_pidlist_open_file {
        struct cgroup_pidlist           *pidlist;
 };
 
-static void cgroup_release_pid_array(struct cgroup_pidlist *l);
-
 /*
  * The following two functions "fix" the issue where there are more pids
  * than kmalloc will give memory for; in such cases, we use vmalloc/vfree.
@@ -3524,10 +3502,10 @@ static void cgroup_pidlist_destroy_work_fn(struct work_struct *work)
        mutex_lock(&l->owner->pidlist_mutex);
 
        /*
-        * Destroy iff we didn't race with a new user or get queued again.
-        * Queued state won't change as it can only be queued while locked.
+        * Destroy iff we didn't get queued again.  The state won't change
+        * as destroy_dwork can only be queued while locked.
         */
-       if (!l->use_count && !delayed_work_pending(dwork)) {
+       if (!delayed_work_pending(dwork)) {
                list_del(&l->links);
                pidlist_free(l->list);
                put_pid_ns(l->key.ns);
@@ -3568,11 +3546,49 @@ after:
        return dest;
 }
 
+/*
+ * The two pid files - task and cgroup.procs - guaranteed that the result
+ * is sorted, which forced this whole pidlist fiasco.  As pid order is
+ * different per namespace, each namespace needs differently sorted list,
+ * making it impossible to use, for example, single rbtree of member tasks
+ * sorted by task pointer.  As pidlists can be fairly large, allocating one
+ * per open file is dangerous, so cgroup had to implement shared pool of
+ * pidlists keyed by cgroup and namespace.
+ *
+ * All this extra complexity was caused by the original implementation
+ * committing to an entirely unnecessary property.  In the long term, we
+ * want to do away with it.  Explicitly scramble sort order if
+ * sane_behavior so that no such expectation exists in the new interface.
+ *
+ * Scrambling is done by swapping every two consecutive bits, which is
+ * non-identity one-to-one mapping which disturbs sort order sufficiently.
+ */
+static pid_t pid_fry(pid_t pid)
+{
+       unsigned a = pid & 0x55555555;
+       unsigned b = pid & 0xAAAAAAAA;
+
+       return (a << 1) | (b >> 1);
+}
+
+static pid_t cgroup_pid_fry(struct cgroup *cgrp, pid_t pid)
+{
+       if (cgroup_sane_behavior(cgrp))
+               return pid_fry(pid);
+       else
+               return pid;
+}
+
 static int cmppid(const void *a, const void *b)
 {
        return *(pid_t *)a - *(pid_t *)b;
 }
 
+static int fried_cmppid(const void *a, const void *b)
+{
+       return pid_fry(*(pid_t *)a) - pid_fry(*(pid_t *)b);
+}
+
 static struct cgroup_pidlist *cgroup_pidlist_find(struct cgroup *cgrp,
                                                  enum cgroup_filetype type)
 {
@@ -3660,7 +3676,10 @@ static int pidlist_array_load(struct cgroup *cgrp, enum cgroup_filetype type,
        css_task_iter_end(&it);
        length = n;
        /* now sort & (if procs) strip out duplicates */
-       sort(array, length, sizeof(pid_t), cmppid, NULL);
+       if (cgroup_sane_behavior(cgrp))
+               sort(array, length, sizeof(pid_t), fried_cmppid, NULL);
+       else
+               sort(array, length, sizeof(pid_t), cmppid, NULL);
        if (type == CGROUP_FILE_PROCS)
                length = pidlist_uniq(array, length);
 
@@ -3775,17 +3794,16 @@ static void *cgroup_pidlist_start(struct seq_file *s, loff_t *pos)
                        return ERR_PTR(ret);
        }
        l = of->pidlist;
-       l->use_count++;
 
        if (pid) {
                int end = l->length;
 
                while (index < end) {
                        int mid = (index + end) / 2;
-                       if (l->list[mid] == pid) {
+                       if (cgroup_pid_fry(cgrp, l->list[mid]) == pid) {
                                index = mid;
                                break;
-                       } else if (l->list[mid] <= pid)
+                       } else if (cgroup_pid_fry(cgrp, l->list[mid]) <= pid)
                                index = mid + 1;
                        else
                                end = mid;
@@ -3796,7 +3814,7 @@ static void *cgroup_pidlist_start(struct seq_file *s, loff_t *pos)
                return NULL;
        /* Update the abstract position to be the actual pid that we found */
        iter = l->list + index;
-       *pos = *iter;
+       *pos = cgroup_pid_fry(cgrp, *iter);
        return iter;
 }
 
@@ -3804,9 +3822,11 @@ static void cgroup_pidlist_stop(struct seq_file *s, void *v)
 {
        struct cgroup_pidlist_open_file *of = s->private;
 
-       mutex_unlock(&of->cgrp->pidlist_mutex);
        if (of->pidlist)
-               cgroup_release_pid_array(of->pidlist);
+               mod_delayed_work(cgroup_pidlist_destroy_wq,
+                                &of->pidlist->destroy_dwork,
+                                CGROUP_PIDLIST_DESTROY_DELAY);
+       mutex_unlock(&of->cgrp->pidlist_mutex);
 }
 
 static void *cgroup_pidlist_next(struct seq_file *s, void *v, loff_t *pos)
@@ -3823,7 +3843,7 @@ static void *cgroup_pidlist_next(struct seq_file *s, void *v, loff_t *pos)
        if (p >= end) {
                return NULL;
        } else {
-               *pos = *p;
+               *pos = cgroup_pid_fry(of->cgrp, *p);
                return p;
        }
 }
@@ -3844,17 +3864,6 @@ static const struct seq_operations cgroup_pidlist_seq_operations = {
        .show = cgroup_pidlist_show,
 };
 
-static void cgroup_release_pid_array(struct cgroup_pidlist *l)
-{
-       mutex_lock(&l->owner->pidlist_mutex);
-       BUG_ON(!l->use_count);
-       /* if the last user, arm the destroy work */
-       if (!--l->use_count)
-               mod_delayed_work(cgroup_pidlist_destroy_wq, &l->destroy_dwork,
-                                CGROUP_PIDLIST_DESTROY_DELAY);
-       mutex_unlock(&l->owner->pidlist_mutex);
-}
-
 static const struct file_operations cgroup_pidlist_operations = {
        .read = seq_read,
        .llseek = seq_lseek,