Merge branch 'for-3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 10 Oct 2014 11:24:40 +0000 (07:24 -0400)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 10 Oct 2014 11:24:40 +0000 (07:24 -0400)
Pull cgroup updates from Tejun Heo:
 "Nothing too interesting.  Just a handful of cleanup patches"

* 'for-3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup:
  Revert "cgroup: remove redundant variable in cgroup_mount()"
  cgroup: remove redundant variable in cgroup_mount()
  cgroup: fix missing unlock in cgroup_release_agent()
  cgroup: remove CGRP_RELEASABLE flag
  perf/cgroup: Remove perf_put_cgroup()
  cgroup: remove redundant check in cgroup_ino()
  cpuset: simplify proc_cpuset_show()
  cgroup: simplify proc_cgroup_show()
  cgroup: use a per-cgroup work for release agent
  cgroup: remove bogus comments
  cgroup: remove redundant code in cgroup_rmdir()
  cgroup: remove some useless forward declarations
  cgroup: fix a typo in comment.

1  2 
fs/proc/base.c
include/linux/cpuset.h
kernel/cgroup.c
kernel/cpuset.c
kernel/events/core.c

diff --combined fs/proc/base.c
index 4c542b9077547357d2cf973a75055488b197a981,4e8aa35fc3eb5c9387085ffa941febf0ba03b7a2..950100e326a10d2d4819e6e031ac0f7cea4c0258
@@@ -376,37 -376,6 +376,6 @@@ static const struct file_operations pro
  
  #endif
  
- #ifdef CONFIG_CGROUPS
- static int cgroup_open(struct inode *inode, struct file *file)
- {
-       struct pid *pid = PROC_I(inode)->pid;
-       return single_open(file, proc_cgroup_show, pid);
- }
- static const struct file_operations proc_cgroup_operations = {
-       .open           = cgroup_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
- };
- #endif
- #ifdef CONFIG_PROC_PID_CPUSET
- static int cpuset_open(struct inode *inode, struct file *file)
- {
-       struct pid *pid = PROC_I(inode)->pid;
-       return single_open(file, proc_cpuset_show, pid);
- }
- static const struct file_operations proc_cpuset_operations = {
-       .open           = cpuset_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
- };
- #endif
  static int proc_oom_score(struct seq_file *m, struct pid_namespace *ns,
                          struct pid *pid, struct task_struct *task)
  {
@@@ -632,35 -601,29 +601,35 @@@ static const struct file_operations pro
        .release        = single_release,
  };
  
 -static int __mem_open(struct inode *inode, struct file *file, unsigned int mode)
 +
 +struct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode)
  {
 -      struct task_struct *task = get_proc_task(file_inode(file));
 -      struct mm_struct *mm;
 +      struct task_struct *task = get_proc_task(inode);
 +      struct mm_struct *mm = ERR_PTR(-ESRCH);
  
 -      if (!task)
 -              return -ESRCH;
 +      if (task) {
 +              mm = mm_access(task, mode);
 +              put_task_struct(task);
  
 -      mm = mm_access(task, mode);
 -      put_task_struct(task);
 +              if (!IS_ERR_OR_NULL(mm)) {
 +                      /* ensure this mm_struct can't be freed */
 +                      atomic_inc(&mm->mm_count);
 +                      /* but do not pin its memory */
 +                      mmput(mm);
 +              }
 +      }
 +
 +      return mm;
 +}
 +
 +static int __mem_open(struct inode *inode, struct file *file, unsigned int mode)
 +{
 +      struct mm_struct *mm = proc_mem_open(inode, mode);
  
        if (IS_ERR(mm))
                return PTR_ERR(mm);
  
 -      if (mm) {
 -              /* ensure this mm_struct can't be freed */
 -              atomic_inc(&mm->mm_count);
 -              /* but do not pin its memory */
 -              mmput(mm);
 -      }
 -
        file->private_data = mm;
 -
        return 0;
  }
  
@@@ -2579,10 -2542,10 +2548,10 @@@ static const struct pid_entry tgid_base
        REG("latency",  S_IRUGO, proc_lstats_operations),
  #endif
  #ifdef CONFIG_PROC_PID_CPUSET
-       REG("cpuset",     S_IRUGO, proc_cpuset_operations),
+       ONE("cpuset",     S_IRUGO, proc_cpuset_show),
  #endif
  #ifdef CONFIG_CGROUPS
-       REG("cgroup",  S_IRUGO, proc_cgroup_operations),
+       ONE("cgroup",  S_IRUGO, proc_cgroup_show),
  #endif
        ONE("oom_score",  S_IRUGO, proc_oom_score),
        REG("oom_adj",    S_IRUGO|S_IWUSR, proc_oom_adj_operations),
@@@ -2925,10 -2888,10 +2894,10 @@@ static const struct pid_entry tid_base_
        REG("latency",  S_IRUGO, proc_lstats_operations),
  #endif
  #ifdef CONFIG_PROC_PID_CPUSET
-       REG("cpuset",    S_IRUGO, proc_cpuset_operations),
+       ONE("cpuset",    S_IRUGO, proc_cpuset_show),
  #endif
  #ifdef CONFIG_CGROUPS
-       REG("cgroup",  S_IRUGO, proc_cgroup_operations),
+       ONE("cgroup",  S_IRUGO, proc_cgroup_show),
  #endif
        ONE("oom_score", S_IRUGO, proc_oom_score),
        REG("oom_adj",   S_IRUGO|S_IWUSR, proc_oom_adj_operations),
diff --combined include/linux/cpuset.h
index 6e39c9bb0dae2b7c2f6738139aba7fed96b74549,0d4e0675b3180391250ca45205cd1bef46ea45a2..2f073db7392e06cf98455f9a83716be2cfaba69e
@@@ -86,19 -86,20 +86,20 @@@ extern void __cpuset_memory_pressure_bu
  
  extern void cpuset_task_status_allowed(struct seq_file *m,
                                        struct task_struct *task);
- extern int proc_cpuset_show(struct seq_file *, void *);
+ extern int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns,
+                           struct pid *pid, struct task_struct *tsk);
  
  extern int cpuset_mem_spread_node(void);
  extern int cpuset_slab_spread_node(void);
  
  static inline int cpuset_do_page_mem_spread(void)
  {
 -      return current->flags & PF_SPREAD_PAGE;
 +      return task_spread_page(current);
  }
  
  static inline int cpuset_do_slab_mem_spread(void)
  {
 -      return current->flags & PF_SPREAD_SLAB;
 +      return task_spread_slab(current);
  }
  
  extern int current_cpuset_is_being_rebound(void);
diff --combined kernel/cgroup.c
index 3a73f995a81e6167659a7b488f23a4feab3d2787,f873c468131648fa422bdaab9adb2faf8230297c..cab7dc4284dcb332748169525440951ee9254247
@@@ -185,7 -185,6 +185,6 @@@ static int need_forkexit_callback __rea
  static struct cftype cgroup_dfl_base_files[];
  static struct cftype cgroup_legacy_base_files[];
  
- static void cgroup_put(struct cgroup *cgrp);
  static int rebind_subsystems(struct cgroup_root *dst_root,
                             unsigned int ss_mask);
  static int cgroup_destroy_locked(struct cgroup *cgrp);
@@@ -195,7 -194,6 +194,6 @@@ static void css_release(struct percpu_r
  static void kill_css(struct cgroup_subsys_state *css);
  static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[],
                              bool is_add);
- static void cgroup_pidlist_destroy_all(struct cgroup *cgrp);
  
  /* IDR wrappers which synchronize using cgroup_idr_lock */
  static int cgroup_idr_alloc(struct idr *idr, void *ptr, int start, int end,
@@@ -331,14 -329,6 +329,6 @@@ bool cgroup_is_descendant(struct cgrou
        return false;
  }
  
- static int cgroup_is_releasable(const struct cgroup *cgrp)
- {
-       const int bits =
-               (1 << CGRP_RELEASABLE) |
-               (1 << CGRP_NOTIFY_ON_RELEASE);
-       return (cgrp->flags & bits) == bits;
- }
  static int notify_on_release(const struct cgroup *cgrp)
  {
        return test_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
                        ;                                               \
                else
  
- /* the list of cgroups eligible for automatic release. Protected by
-  * release_list_lock */
- static LIST_HEAD(release_list);
- static DEFINE_RAW_SPINLOCK(release_list_lock);
  static void cgroup_release_agent(struct work_struct *work);
- static DECLARE_WORK(release_agent_work, cgroup_release_agent);
  static void check_for_release(struct cgroup *cgrp);
  
  /*
@@@ -498,7 -483,7 +483,7 @@@ static unsigned long css_set_hash(struc
        return key;
  }
  
- static void put_css_set_locked(struct css_set *cset, bool taskexit)
+ static void put_css_set_locked(struct css_set *cset)
  {
        struct cgrp_cset_link *link, *tmp_link;
        struct cgroup_subsys *ss;
                /* @cgrp can't go away while we're holding css_set_rwsem */
                if (list_empty(&cgrp->cset_links)) {
                        cgroup_update_populated(cgrp, false);
-                       if (notify_on_release(cgrp)) {
-                               if (taskexit)
-                                       set_bit(CGRP_RELEASABLE, &cgrp->flags);
-                               check_for_release(cgrp);
-                       }
+                       check_for_release(cgrp);
                }
  
                kfree(link);
        kfree_rcu(cset, rcu_head);
  }
  
- static void put_css_set(struct css_set *cset, bool taskexit)
+ static void put_css_set(struct css_set *cset)
  {
        /*
         * Ensure that the refcount doesn't hit zero while any readers
                return;
  
        down_write(&css_set_rwsem);
-       put_css_set_locked(cset, taskexit);
+       put_css_set_locked(cset);
        up_write(&css_set_rwsem);
  }
  
@@@ -969,14 -950,6 +950,6 @@@ static struct cgroup *task_cgroup_from_
   * knows that the cgroup won't be removed, as cgroup_rmdir()
   * needs that mutex.
   *
-  * The fork and exit callbacks cgroup_fork() and cgroup_exit(), don't
-  * (usually) take cgroup_mutex.  These are the two most performance
-  * critical pieces of code here.  The exception occurs on cgroup_exit(),
-  * when a task in a notify_on_release cgroup exits.  Then cgroup_mutex
-  * is taken, and if the cgroup count is zero, a usermode call made
-  * to the release agent with the name of the cgroup (path relative to
-  * the root of cgroup file system) as the argument.
-  *
   * A cgroup can only be deleted if both its 'count' of using tasks
   * is zero, and its list of 'children' cgroups is empty.  Since all
   * tasks in the system use _some_ cgroup, and since there is always at
@@@ -1587,7 -1560,6 +1560,6 @@@ static void init_cgroup_housekeeping(st
        INIT_LIST_HEAD(&cgrp->self.sibling);
        INIT_LIST_HEAD(&cgrp->self.children);
        INIT_LIST_HEAD(&cgrp->cset_links);
-       INIT_LIST_HEAD(&cgrp->release_list);
        INIT_LIST_HEAD(&cgrp->pidlists);
        mutex_init(&cgrp->pidlist_mutex);
        cgrp->self.cgroup = cgrp;
                INIT_LIST_HEAD(&cgrp->e_csets[ssid]);
  
        init_waitqueue_head(&cgrp->offline_waitq);
+       INIT_WORK(&cgrp->release_agent_work, cgroup_release_agent);
  }
  
  static void init_cgroup_root(struct cgroup_root *root,
@@@ -2052,8 -2025,7 +2025,7 @@@ static void cgroup_task_migrate(struct 
         * task. As trading it for new_cset is protected by cgroup_mutex,
         * we're safe to drop it here; it will be freed under RCU.
         */
-       set_bit(CGRP_RELEASABLE, &old_cgrp->flags);
-       put_css_set_locked(old_cset, false);
+       put_css_set_locked(old_cset);
  }
  
  /**
@@@ -2074,7 -2046,7 +2046,7 @@@ static void cgroup_migrate_finish(struc
                cset->mg_src_cgrp = NULL;
                cset->mg_dst_cset = NULL;
                list_del_init(&cset->mg_preload_node);
-               put_css_set_locked(cset, false);
+               put_css_set_locked(cset);
        }
        up_write(&css_set_rwsem);
  }
@@@ -2168,8 -2140,8 +2140,8 @@@ static int cgroup_migrate_prepare_dst(s
                if (src_cset == dst_cset) {
                        src_cset->mg_src_cgrp = NULL;
                        list_del_init(&src_cset->mg_preload_node);
-                       put_css_set(src_cset, false);
-                       put_css_set(dst_cset, false);
+                       put_css_set(src_cset);
+                       put_css_set(dst_cset);
                        continue;
                }
  
                if (list_empty(&dst_cset->mg_preload_node))
                        list_add(&dst_cset->mg_preload_node, &csets);
                else
-                       put_css_set(dst_cset, false);
+                       put_css_set(dst_cset);
        }
  
        list_splice_tail(&csets, preloaded_csets);
@@@ -3985,6 -3957,7 +3957,6 @@@ static int pidlist_array_load(struct cg
  
        l = cgroup_pidlist_find_create(cgrp, type);
        if (!l) {
 -              mutex_unlock(&cgrp->pidlist_mutex);
                pidlist_free(array);
                return -ENOMEM;
        }
@@@ -4173,7 -4146,6 +4145,6 @@@ static u64 cgroup_read_notify_on_releas
  static int cgroup_write_notify_on_release(struct cgroup_subsys_state *css,
                                          struct cftype *cft, u64 val)
  {
-       clear_bit(CGRP_RELEASABLE, &css->cgroup->flags);
        if (val)
                set_bit(CGRP_NOTIFY_ON_RELEASE, &css->cgroup->flags);
        else
@@@ -4351,6 -4323,7 +4322,7 @@@ static void css_free_work_fn(struct wor
                /* cgroup free path */
                atomic_dec(&cgrp->root->nr_cgrps);
                cgroup_pidlist_destroy_all(cgrp);
+               cancel_work_sync(&cgrp->release_agent_work);
  
                if (cgroup_parent(cgrp)) {
                        /*
@@@ -4813,19 -4786,12 +4785,12 @@@ static int cgroup_destroy_locked(struc
        for_each_css(css, ssid, cgrp)
                kill_css(css);
  
-       /* CSS_ONLINE is clear, remove from ->release_list for the last time */
-       raw_spin_lock(&release_list_lock);
-       if (!list_empty(&cgrp->release_list))
-               list_del_init(&cgrp->release_list);
-       raw_spin_unlock(&release_list_lock);
        /*
         * Remove @cgrp directory along with the base files.  @cgrp has an
         * extra ref on its kn.
         */
        kernfs_remove(cgrp->kn);
  
-       set_bit(CGRP_RELEASABLE, &cgroup_parent(cgrp)->flags);
        check_for_release(cgroup_parent(cgrp));
  
        /* put the base reference */
@@@ -4842,13 -4808,10 +4807,10 @@@ static int cgroup_rmdir(struct kernfs_n
        cgrp = cgroup_kn_lock_live(kn);
        if (!cgrp)
                return 0;
-       cgroup_get(cgrp);       /* for @kn->priv clearing */
  
        ret = cgroup_destroy_locked(cgrp);
  
        cgroup_kn_unlock(kn);
-       cgroup_put(cgrp);
        return ret;
  }
  
@@@ -5052,12 -5015,9 +5014,9 @@@ core_initcall(cgroup_wq_init)
   *  - Print task's cgroup paths into seq_file, one line for each hierarchy
   *  - Used for /proc/<pid>/cgroup.
   */
- /* TODO: Use a proper seq_file iterator */
- int proc_cgroup_show(struct seq_file *m, void *v)
+ int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns,
+                    struct pid *pid, struct task_struct *tsk)
  {
-       struct pid *pid;
-       struct task_struct *tsk;
        char *buf, *path;
        int retval;
        struct cgroup_root *root;
        if (!buf)
                goto out;
  
-       retval = -ESRCH;
-       pid = m->private;
-       tsk = get_pid_task(pid, PIDTYPE_PID);
-       if (!tsk)
-               goto out_free;
-       retval = 0;
        mutex_lock(&cgroup_mutex);
        down_read(&css_set_rwsem);
  
                seq_putc(m, '\n');
        }
  
+       retval = 0;
  out_unlock:
        up_read(&css_set_rwsem);
        mutex_unlock(&cgroup_mutex);
-       put_task_struct(tsk);
- out_free:
        kfree(buf);
  out:
        return retval;
@@@ -5179,7 -5130,7 +5129,7 @@@ void cgroup_post_fork(struct task_struc
        int i;
  
        /*
-        * This may race against cgroup_enable_task_cg_links().  As that
+        * This may race against cgroup_enable_task_cg_lists().  As that
         * function sets use_task_css_set_links before grabbing
         * tasklist_lock and we just went through tasklist_lock to add
         * @child, it's guaranteed that either we see the set
         * when implementing operations which need to migrate all tasks of
         * a cgroup to another.
         *
-        * Note that if we lose to cgroup_enable_task_cg_links(), @child
+        * Note that if we lose to cgroup_enable_task_cg_lists(), @child
         * will remain in init_css_set.  This is safe because all tasks are
         * in the init_css_set before cg_links is enabled and there's no
         * operation which transfers all tasks out of init_css_set.
@@@ -5278,30 -5229,14 +5228,14 @@@ void cgroup_exit(struct task_struct *ts
        }
  
        if (put_cset)
-               put_css_set(cset, true);
+               put_css_set(cset);
  }
  
  static void check_for_release(struct cgroup *cgrp)
  {
-       if (cgroup_is_releasable(cgrp) && list_empty(&cgrp->cset_links) &&
-           !css_has_online_children(&cgrp->self)) {
-               /*
-                * Control Group is currently removeable. If it's not
-                * already queued for a userspace notification, queue
-                * it now
-                */
-               int need_schedule_work = 0;
-               raw_spin_lock(&release_list_lock);
-               if (!cgroup_is_dead(cgrp) &&
-                   list_empty(&cgrp->release_list)) {
-                       list_add(&cgrp->release_list, &release_list);
-                       need_schedule_work = 1;
-               }
-               raw_spin_unlock(&release_list_lock);
-               if (need_schedule_work)
-                       schedule_work(&release_agent_work);
-       }
+       if (notify_on_release(cgrp) && !cgroup_has_tasks(cgrp) &&
+           !css_has_online_children(&cgrp->self) && !cgroup_is_dead(cgrp))
+               schedule_work(&cgrp->release_agent_work);
  }
  
  /*
   */
  static void cgroup_release_agent(struct work_struct *work)
  {
-       BUG_ON(work != &release_agent_work);
+       struct cgroup *cgrp =
+               container_of(work, struct cgroup, release_agent_work);
+       char *pathbuf = NULL, *agentbuf = NULL, *path;
+       char *argv[3], *envp[3];
        mutex_lock(&cgroup_mutex);
-       raw_spin_lock(&release_list_lock);
-       while (!list_empty(&release_list)) {
-               char *argv[3], *envp[3];
-               int i;
-               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(PATH_MAX, GFP_KERNEL);
-               if (!pathbuf)
-                       goto continue_free;
-               path = cgroup_path(cgrp, pathbuf, PATH_MAX);
-               if (!path)
-                       goto continue_free;
-               agentbuf = kstrdup(cgrp->root->release_agent_path, GFP_KERNEL);
-               if (!agentbuf)
-                       goto continue_free;
-               i = 0;
-               argv[i++] = agentbuf;
-               argv[i++] = path;
-               argv[i] = NULL;
-               i = 0;
-               /* minimal command environment */
-               envp[i++] = "HOME=/";
-               envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-               envp[i] = NULL;
-               /* Drop the lock while we invoke the usermode helper,
-                * since the exec could involve hitting disk and hence
-                * be a slow process */
-               mutex_unlock(&cgroup_mutex);
-               call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
-               mutex_lock(&cgroup_mutex);
-  continue_free:
-               kfree(pathbuf);
-               kfree(agentbuf);
-               raw_spin_lock(&release_list_lock);
-       }
-       raw_spin_unlock(&release_list_lock);
+       pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
+       agentbuf = kstrdup(cgrp->root->release_agent_path, GFP_KERNEL);
+       if (!pathbuf || !agentbuf)
+               goto out;
+       path = cgroup_path(cgrp, pathbuf, PATH_MAX);
+       if (!path)
+               goto out;
+       argv[0] = agentbuf;
+       argv[1] = path;
+       argv[2] = NULL;
+       /* minimal command environment */
+       envp[0] = "HOME=/";
+       envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+       envp[2] = NULL;
+       mutex_unlock(&cgroup_mutex);
+       call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
+       goto out_free;
+ out:
        mutex_unlock(&cgroup_mutex);
+ out_free:
+       kfree(agentbuf);
+       kfree(pathbuf);
  }
  
  static int __init cgroup_disable(char *str)
@@@ -5562,7 -5484,8 +5483,8 @@@ static int cgroup_css_links_read(struc
  
  static u64 releasable_read(struct cgroup_subsys_state *css, struct cftype *cft)
  {
-       return test_bit(CGRP_RELEASABLE, &css->cgroup->flags);
+       return (!cgroup_has_tasks(css->cgroup) &&
+               !css_has_online_children(&css->cgroup->self));
  }
  
  static struct cftype debug_files[] =  {
diff --combined kernel/cpuset.c
index 52cb04c993b7282fb61d68e7a5223598841d9ff4,a37f4ed248673a3740a2bb81b471fac93d0872a8..1f107c74087bc52f690d957dbe610472688b4c1b
@@@ -365,14 -365,13 +365,14 @@@ static void cpuset_update_task_spread_f
                                        struct task_struct *tsk)
  {
        if (is_spread_page(cs))
 -              tsk->flags |= PF_SPREAD_PAGE;
 +              task_set_spread_page(tsk);
        else
 -              tsk->flags &= ~PF_SPREAD_PAGE;
 +              task_clear_spread_page(tsk);
 +
        if (is_spread_slab(cs))
 -              tsk->flags |= PF_SPREAD_SLAB;
 +              task_set_spread_slab(tsk);
        else
 -              tsk->flags &= ~PF_SPREAD_SLAB;
 +              task_clear_spread_slab(tsk);
  }
  
  /*
@@@ -2730,10 -2729,9 +2730,9 @@@ void __cpuset_memory_pressure_bump(void
   *    and we take cpuset_mutex, keeping cpuset_attach() from changing it
   *    anyway.
   */
- int proc_cpuset_show(struct seq_file *m, void *unused_v)
+ int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns,
+                    struct pid *pid, struct task_struct *tsk)
  {
-       struct pid *pid;
-       struct task_struct *tsk;
        char *buf, *p;
        struct cgroup_subsys_state *css;
        int retval;
        if (!buf)
                goto out;
  
-       retval = -ESRCH;
-       pid = m->private;
-       tsk = get_pid_task(pid, PIDTYPE_PID);
-       if (!tsk)
-               goto out_free;
        retval = -ENAMETOOLONG;
        rcu_read_lock();
        css = task_css(tsk, cpuset_cgrp_id);
        p = cgroup_path(css->cgroup, buf, PATH_MAX);
        rcu_read_unlock();
        if (!p)
-               goto out_put_task;
+               goto out_free;
        seq_puts(m, p);
        seq_putc(m, '\n');
        retval = 0;
- out_put_task:
-       put_task_struct(tsk);
  out_free:
        kfree(buf);
  out:
diff --combined kernel/events/core.c
index 963bf139e2b244fa1a4e2efb9a697e02b0c8dfa5,8be3e34274b9116871b6359ca82e412f1a192b06..b1c663593f5c9f082cb3dd997f94978a723b7599
@@@ -41,7 -41,6 +41,7 @@@
  #include <linux/cgroup.h>
  #include <linux/module.h>
  #include <linux/mman.h>
 +#include <linux/compat.h>
  
  #include "internal.h"
  
@@@ -392,14 -391,9 +392,9 @@@ perf_cgroup_match(struct perf_event *ev
                                    event->cgrp->css.cgroup);
  }
  
- static inline void perf_put_cgroup(struct perf_event *event)
- {
-       css_put(&event->cgrp->css);
- }
  static inline void perf_detach_cgroup(struct perf_event *event)
  {
-       perf_put_cgroup(event);
+       css_put(&event->cgrp->css);
        event->cgrp = NULL;
  }
  
@@@ -1524,11 -1518,6 +1519,11 @@@ retry
         */
        if (ctx->is_active) {
                raw_spin_unlock_irq(&ctx->lock);
 +              /*
 +               * Reload the task pointer, it might have been changed by
 +               * a concurrent perf_event_context_sched_out().
 +               */
 +              task = ctx->task;
                goto retry;
        }
  
@@@ -1972,11 -1961,6 +1967,11 @@@ retry
         */
        if (ctx->is_active) {
                raw_spin_unlock_irq(&ctx->lock);
 +              /*
 +               * Reload the task pointer, it might have been changed by
 +               * a concurrent perf_event_context_sched_out().
 +               */
 +              task = ctx->task;
                goto retry;
        }
  
@@@ -3728,26 -3712,6 +3723,26 @@@ static long perf_ioctl(struct file *fil
        return 0;
  }
  
 +#ifdef CONFIG_COMPAT
 +static long perf_compat_ioctl(struct file *file, unsigned int cmd,
 +                              unsigned long arg)
 +{
 +      switch (_IOC_NR(cmd)) {
 +      case _IOC_NR(PERF_EVENT_IOC_SET_FILTER):
 +      case _IOC_NR(PERF_EVENT_IOC_ID):
 +              /* Fix up pointer size (usually 4 -> 8 in 32-on-64-bit case */
 +              if (_IOC_SIZE(cmd) == sizeof(compat_uptr_t)) {
 +                      cmd &= ~IOCSIZE_MASK;
 +                      cmd |= sizeof(void *) << IOCSIZE_SHIFT;
 +              }
 +              break;
 +      }
 +      return perf_ioctl(file, cmd, arg);
 +}
 +#else
 +# define perf_compat_ioctl NULL
 +#endif
 +
  int perf_event_task_enable(void)
  {
        struct perf_event *event;
@@@ -4253,7 -4217,7 +4248,7 @@@ static const struct file_operations per
        .read                   = perf_read,
        .poll                   = perf_poll,
        .unlocked_ioctl         = perf_ioctl,
 -      .compat_ioctl           = perf_ioctl,
 +      .compat_ioctl           = perf_compat_ioctl,
        .mmap                   = perf_mmap,
        .fasync                 = perf_fasync,
  };
@@@ -7948,10 -7912,8 +7943,10 @@@ int perf_event_init_task(struct task_st
  
        for_each_task_context_nr(ctxn) {
                ret = perf_event_init_context(child, ctxn);
 -              if (ret)
 +              if (ret) {
 +                      perf_event_free_task(child);
                        return ret;
 +              }
        }
  
        return 0;