Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[platform/adaptation/renesas_rcar/renesas_kernel.git] / kernel / events / core.c
index fd15593..dbccf83 100644 (file)
@@ -471,14 +471,13 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event,
 {
        struct perf_cgroup *cgrp;
        struct cgroup_subsys_state *css;
-       struct file *file;
-       int ret = 0, fput_needed;
+       struct fd f = fdget(fd);
+       int ret = 0;
 
-       file = fget_light(fd, &fput_needed);
-       if (!file)
+       if (!f.file)
                return -EBADF;
 
-       css = cgroup_css_from_dir(file, perf_subsys_id);
+       css = cgroup_css_from_dir(f.file, perf_subsys_id);
        if (IS_ERR(css)) {
                ret = PTR_ERR(css);
                goto out;
@@ -504,7 +503,7 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event,
                ret = -EINVAL;
        }
 out:
-       fput_light(file, fput_needed);
+       fdput(f);
        return ret;
 }
 
@@ -3237,21 +3236,18 @@ unlock:
 
 static const struct file_operations perf_fops;
 
-static struct file *perf_fget_light(int fd, int *fput_needed)
+static inline int perf_fget_light(int fd, struct fd *p)
 {
-       struct file *file;
-
-       file = fget_light(fd, fput_needed);
-       if (!file)
-               return ERR_PTR(-EBADF);
+       struct fd f = fdget(fd);
+       if (!f.file)
+               return -EBADF;
 
-       if (file->f_op != &perf_fops) {
-               fput_light(file, *fput_needed);
-               *fput_needed = 0;
-               return ERR_PTR(-EBADF);
+       if (f.file->f_op != &perf_fops) {
+               fdput(f);
+               return -EBADF;
        }
-
-       return file;
+       *p = f;
+       return 0;
 }
 
 static int perf_event_set_output(struct perf_event *event,
@@ -3283,22 +3279,19 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
        case PERF_EVENT_IOC_SET_OUTPUT:
        {
-               struct file *output_file = NULL;
-               struct perf_event *output_event = NULL;
-               int fput_needed = 0;
                int ret;
-
                if (arg != -1) {
-                       output_file = perf_fget_light(arg, &fput_needed);
-                       if (IS_ERR(output_file))
-                               return PTR_ERR(output_file);
-                       output_event = output_file->private_data;
+                       struct perf_event *output_event;
+                       struct fd output;
+                       ret = perf_fget_light(arg, &output);
+                       if (ret)
+                               return ret;
+                       output_event = output.file->private_data;
+                       ret = perf_event_set_output(event, output_event);
+                       fdput(output);
+               } else {
+                       ret = perf_event_set_output(event, NULL);
                }
-
-               ret = perf_event_set_output(event, output_event);
-               if (output_event)
-                       fput_light(output_file, fput_needed);
-
                return ret;
        }
 
@@ -3681,7 +3674,7 @@ unlock:
                atomic_inc(&event->mmap_count);
        mutex_unlock(&event->mmap_mutex);
 
-       vma->vm_flags |= VM_RESERVED;
+       vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
        vma->vm_ops = &perf_mmap_vmops;
 
        return ret;
@@ -6446,12 +6439,11 @@ SYSCALL_DEFINE5(perf_event_open,
        struct perf_event_attr attr;
        struct perf_event_context *ctx;
        struct file *event_file = NULL;
-       struct file *group_file = NULL;
+       struct fd group = {NULL, 0};
        struct task_struct *task = NULL;
        struct pmu *pmu;
        int event_fd;
        int move_group = 0;
-       int fput_needed = 0;
        int err;
 
        /* for future expandability... */
@@ -6481,17 +6473,15 @@ SYSCALL_DEFINE5(perf_event_open,
        if ((flags & PERF_FLAG_PID_CGROUP) && (pid == -1 || cpu == -1))
                return -EINVAL;
 
-       event_fd = get_unused_fd_flags(O_RDWR);
+       event_fd = get_unused_fd();
        if (event_fd < 0)
                return event_fd;
 
        if (group_fd != -1) {
-               group_file = perf_fget_light(group_fd, &fput_needed);
-               if (IS_ERR(group_file)) {
-                       err = PTR_ERR(group_file);
+               err = perf_fget_light(group_fd, &group);
+               if (err)
                        goto err_fd;
-               }
-               group_leader = group_file->private_data;
+               group_leader = group.file->private_data;
                if (flags & PERF_FLAG_FD_OUTPUT)
                        output_event = group_leader;
                if (flags & PERF_FLAG_FD_NO_GROUP)
@@ -6667,7 +6657,7 @@ SYSCALL_DEFINE5(perf_event_open,
         * of the group leader will find the pointer to itself in
         * perf_group_detach().
         */
-       fput_light(group_file, fput_needed);
+       fdput(group);
        fd_install(event_fd, event_file);
        return event_fd;
 
@@ -6681,7 +6671,7 @@ err_task:
        if (task)
                put_task_struct(task);
 err_group_fd:
-       fput_light(group_file, fput_needed);
+       fdput(group);
 err_fd:
        put_unused_fd(event_fd);
        return err;
@@ -7506,5 +7496,12 @@ struct cgroup_subsys perf_subsys = {
        .destroy        = perf_cgroup_destroy,
        .exit           = perf_cgroup_exit,
        .attach         = perf_cgroup_attach,
+
+       /*
+        * perf_event cgroup doesn't handle nesting correctly.
+        * ctx->nr_cgroups adjustments should be propagated through the
+        * cgroup hierarchy.  Fix it and remove the following.
+        */
+       .broken_hierarchy = true,
 };
 #endif /* CONFIG_CGROUP_PERF */