Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 322818
b: refs/heads/master
c: a6fa941
h: refs/heads/master
v: v3
  • Loading branch information
Al Viro authored and Ingo Molnar committed Sep 4, 2012
1 parent 7054750 commit 1648d21
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 31 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e3e45c01ae690e65f2650e5288b9af802e95a136
refs/heads/master: a6fa941d94b411bbd2b6421ffbde6db3c93e65ab
2 changes: 1 addition & 1 deletion trunk/include/linux/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -926,7 +926,7 @@ struct perf_event {
struct hw_perf_event hw;

struct perf_event_context *ctx;
struct file *filp;
atomic_long_t refcount;

/*
* These accumulate total time (in nanoseconds) that children
Expand Down
62 changes: 33 additions & 29 deletions trunk/kernel/events/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2935,12 +2935,12 @@ EXPORT_SYMBOL_GPL(perf_event_release_kernel);
/*
* Called when the last reference to the file is gone.
*/
static int perf_release(struct inode *inode, struct file *file)
static void put_event(struct perf_event *event)
{
struct perf_event *event = file->private_data;
struct task_struct *owner;

file->private_data = NULL;
if (!atomic_long_dec_and_test(&event->refcount))
return;

rcu_read_lock();
owner = ACCESS_ONCE(event->owner);
Expand Down Expand Up @@ -2975,7 +2975,13 @@ static int perf_release(struct inode *inode, struct file *file)
put_task_struct(owner);
}

return perf_event_release_kernel(event);
perf_event_release_kernel(event);
}

static int perf_release(struct inode *inode, struct file *file)
{
put_event(file->private_data);
return 0;
}

u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running)
Expand Down Expand Up @@ -3227,7 +3233,7 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg)

static const struct file_operations perf_fops;

static struct perf_event *perf_fget_light(int fd, int *fput_needed)
static struct file *perf_fget_light(int fd, int *fput_needed)
{
struct file *file;

Expand All @@ -3241,7 +3247,7 @@ static struct perf_event *perf_fget_light(int fd, int *fput_needed)
return ERR_PTR(-EBADF);
}

return file->private_data;
return file;
}

static int perf_event_set_output(struct perf_event *event,
Expand Down Expand Up @@ -3273,19 +3279,21 @@ 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_event = perf_fget_light(arg, &fput_needed);
if (IS_ERR(output_event))
return PTR_ERR(output_event);
output_file = perf_fget_light(arg, &fput_needed);
if (IS_ERR(output_file))
return PTR_ERR(output_file);
output_event = output_file->private_data;
}

ret = perf_event_set_output(event, output_event);
if (output_event)
fput_light(output_event->filp, fput_needed);
fput_light(output_file, fput_needed);

return ret;
}
Expand Down Expand Up @@ -5950,6 +5958,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,

mutex_init(&event->mmap_mutex);

atomic_long_set(&event->refcount, 1);
event->cpu = cpu;
event->attr = *attr;
event->group_leader = group_leader;
Expand Down Expand Up @@ -6260,12 +6269,12 @@ SYSCALL_DEFINE5(perf_event_open,
return event_fd;

if (group_fd != -1) {
group_leader = perf_fget_light(group_fd, &fput_needed);
if (IS_ERR(group_leader)) {
err = PTR_ERR(group_leader);
group_file = perf_fget_light(group_fd, &fput_needed);
if (IS_ERR(group_file)) {
err = PTR_ERR(group_file);
goto err_fd;
}
group_file = group_leader->filp;
group_leader = group_file->private_data;
if (flags & PERF_FLAG_FD_OUTPUT)
output_event = group_leader;
if (flags & PERF_FLAG_FD_NO_GROUP)
Expand Down Expand Up @@ -6402,7 +6411,6 @@ SYSCALL_DEFINE5(perf_event_open,
put_ctx(gctx);
}

event->filp = event_file;
WARN_ON_ONCE(ctx->parent_ctx);
mutex_lock(&ctx->mutex);

Expand Down Expand Up @@ -6496,7 +6504,6 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
goto err_free;
}

event->filp = NULL;
WARN_ON_ONCE(ctx->parent_ctx);
mutex_lock(&ctx->mutex);
perf_install_in_context(ctx, event, cpu);
Expand Down Expand Up @@ -6578,7 +6585,7 @@ static void sync_child_event(struct perf_event *child_event,
* Release the parent event, if this was the last
* reference to it.
*/
fput(parent_event->filp);
put_event(parent_event);
}

static void
Expand Down Expand Up @@ -6654,9 +6661,8 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
*
* __perf_event_exit_task()
* sync_child_event()
* fput(parent_event->filp)
* perf_release()
* mutex_lock(&ctx->mutex)
* put_event()
* mutex_lock(&ctx->mutex)
*
* But since its the parent context it won't be the same instance.
*/
Expand Down Expand Up @@ -6724,7 +6730,7 @@ static void perf_free_event(struct perf_event *event,
list_del_init(&event->child_list);
mutex_unlock(&parent->child_mutex);

fput(parent->filp);
put_event(parent);

perf_group_detach(event);
list_del_event(event, ctx);
Expand Down Expand Up @@ -6804,6 +6810,12 @@ inherit_event(struct perf_event *parent_event,
NULL, NULL);
if (IS_ERR(child_event))
return child_event;

if (!atomic_long_inc_not_zero(&parent_event->refcount)) {
free_event(child_event);
return NULL;
}

get_ctx(child_ctx);

/*
Expand Down Expand Up @@ -6844,14 +6856,6 @@ inherit_event(struct perf_event *parent_event,
add_event_to_ctx(child_event, child_ctx);
raw_spin_unlock_irqrestore(&child_ctx->lock, flags);

/*
* Get a reference to the parent filp - we will fput it
* when the child event exits. This is safe to do because
* we are in the parent and we know that the filp still
* exists and has a nonzero count:
*/
atomic_long_inc(&parent_event->filp->f_count);

/*
* Link this into the parent event's child list
*/
Expand Down

0 comments on commit 1648d21

Please sign in to comment.