Skip to content

Commit

Permalink
perf_counter: Fix race in counter initialization
Browse files Browse the repository at this point in the history
We need the PID namespace and counter ID available when the
counter overflows and we need to generate a sample event.

[ Impact: fix kernel crash with high-frequency sampling ]

Reported-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: John Kacur <jkacur@redhat.com>
LKML-Reference: <new-submission>
[ fixed a further crash and cleaned up the initialization a bit ]
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Peter Zijlstra authored and Ingo Molnar committed Jun 3, 2009
1 parent 8229289 commit a96bbc1
Showing 1 changed file with 14 additions and 11 deletions.
25 changes: 14 additions & 11 deletions kernel/perf_counter.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ int sysctl_perf_counter_priv __read_mostly; /* do we need to be privileged */
int sysctl_perf_counter_mlock __read_mostly = 512; /* 'free' kb per user */
int sysctl_perf_counter_limit __read_mostly = 100000; /* max NMIs per second */

static atomic64_t perf_counter_id;

/*
* Lock for (sysadmin-configurable) counter reservations:
*/
Expand Down Expand Up @@ -3351,14 +3353,18 @@ perf_counter_alloc(struct perf_counter_attr *attr,

mutex_init(&counter->mmap_mutex);

counter->cpu = cpu;
counter->cpu = cpu;
counter->attr = *attr;
counter->group_leader = group_leader;
counter->pmu = NULL;
counter->ctx = ctx;
counter->oncpu = -1;
counter->group_leader = group_leader;
counter->pmu = NULL;
counter->ctx = ctx;
counter->oncpu = -1;

counter->ns = get_pid_ns(current->nsproxy->pid_ns);
counter->id = atomic64_inc_return(&perf_counter_id);

counter->state = PERF_COUNTER_STATE_INACTIVE;

counter->state = PERF_COUNTER_STATE_INACTIVE;
if (attr->disabled)
counter->state = PERF_COUNTER_STATE_OFF;

Expand Down Expand Up @@ -3402,6 +3408,8 @@ perf_counter_alloc(struct perf_counter_attr *attr,
err = PTR_ERR(pmu);

if (err) {
if (counter->ns)
put_pid_ns(counter->ns);
kfree(counter);
return ERR_PTR(err);
}
Expand All @@ -3419,8 +3427,6 @@ perf_counter_alloc(struct perf_counter_attr *attr,
return counter;
}

static atomic64_t perf_counter_id;

/**
* sys_perf_counter_open - open a performance counter, associate it to a task/cpu
*
Expand Down Expand Up @@ -3515,9 +3521,6 @@ SYSCALL_DEFINE5(perf_counter_open,
list_add_tail(&counter->owner_entry, &current->perf_counter_list);
mutex_unlock(&current->perf_counter_mutex);

counter->ns = get_pid_ns(current->nsproxy->pid_ns);
counter->id = atomic64_inc_return(&perf_counter_id);

fput_light(counter_file, fput_needed2);

out_fput:
Expand Down

0 comments on commit a96bbc1

Please sign in to comment.