Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
+30
-2
@@ -7458,7 +7458,19 @@ __perf_event_exit_task(struct perf_event *child_event,
|
||||
struct perf_event_context *child_ctx,
|
||||
struct task_struct *child)
|
||||
{
|
||||
perf_remove_from_context(child_event, true);
|
||||
/*
|
||||
* Do not destroy the 'original' grouping; because of the context
|
||||
* switch optimization the original events could've ended up in a
|
||||
* random child task.
|
||||
*
|
||||
* If we were to destroy the original group, all group related
|
||||
* operations would cease to function properly after this random
|
||||
* child dies.
|
||||
*
|
||||
* Do destroy all inherited groups, we don't care about those
|
||||
* and being thorough is better.
|
||||
*/
|
||||
perf_remove_from_context(child_event, !!child_event->parent);
|
||||
|
||||
/*
|
||||
* It can happen that the parent exits first, and has events
|
||||
@@ -7474,7 +7486,7 @@ __perf_event_exit_task(struct perf_event *child_event,
|
||||
static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
|
||||
{
|
||||
struct perf_event *child_event, *next;
|
||||
struct perf_event_context *child_ctx;
|
||||
struct perf_event_context *child_ctx, *parent_ctx;
|
||||
unsigned long flags;
|
||||
|
||||
if (likely(!child->perf_event_ctxp[ctxn])) {
|
||||
@@ -7499,6 +7511,15 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
|
||||
raw_spin_lock(&child_ctx->lock);
|
||||
task_ctx_sched_out(child_ctx);
|
||||
child->perf_event_ctxp[ctxn] = NULL;
|
||||
|
||||
/*
|
||||
* In order to avoid freeing: child_ctx->parent_ctx->task
|
||||
* under perf_event_context::lock, grab another reference.
|
||||
*/
|
||||
parent_ctx = child_ctx->parent_ctx;
|
||||
if (parent_ctx)
|
||||
get_ctx(parent_ctx);
|
||||
|
||||
/*
|
||||
* If this context is a clone; unclone it so it can't get
|
||||
* swapped to another process while we're removing all
|
||||
@@ -7508,6 +7529,13 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
|
||||
update_context_time(child_ctx);
|
||||
raw_spin_unlock_irqrestore(&child_ctx->lock, flags);
|
||||
|
||||
/*
|
||||
* Now that we no longer hold perf_event_context::lock, drop
|
||||
* our extra child_ctx->parent_ctx reference.
|
||||
*/
|
||||
if (parent_ctx)
|
||||
put_ctx(parent_ctx);
|
||||
|
||||
/*
|
||||
* Report the task dead after unscheduling the events so that we
|
||||
* won't get any samples after PERF_RECORD_EXIT. We can however still
|
||||
|
||||
+9
-5
@@ -2037,19 +2037,23 @@ static int __init populate_kprobe_blacklist(unsigned long *start,
|
||||
{
|
||||
unsigned long *iter;
|
||||
struct kprobe_blacklist_entry *ent;
|
||||
unsigned long offset = 0, size = 0;
|
||||
unsigned long entry, offset = 0, size = 0;
|
||||
|
||||
for (iter = start; iter < end; iter++) {
|
||||
if (!kallsyms_lookup_size_offset(*iter, &size, &offset)) {
|
||||
pr_err("Failed to find blacklist %p\n", (void *)*iter);
|
||||
entry = arch_deref_entry_point((void *)*iter);
|
||||
|
||||
if (!kernel_text_address(entry) ||
|
||||
!kallsyms_lookup_size_offset(entry, &size, &offset)) {
|
||||
pr_err("Failed to find blacklist at %p\n",
|
||||
(void *)entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
ent = kmalloc(sizeof(*ent), GFP_KERNEL);
|
||||
if (!ent)
|
||||
return -ENOMEM;
|
||||
ent->start_addr = *iter;
|
||||
ent->end_addr = *iter + size;
|
||||
ent->start_addr = entry;
|
||||
ent->end_addr = entry + size;
|
||||
INIT_LIST_HEAD(&ent->list);
|
||||
list_add_tail(&ent->list, &kprobe_blacklist);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user