Skip to content

Commit

Permalink
oprofile: fix crash when accessing freed task structs
Browse files Browse the repository at this point in the history
This patch fixes a crash during shutdown reported below. The crash is
caused by accessing already freed task structs. The fix changes the
order for registering and unregistering notifier callbacks.

All notifiers must be initialized before buffers start working. To
stop buffer synchronization we cancel all workqueues, unregister the
notifier callback and then flush all buffers. After all of this we
finally can free all tasks listed.

This should avoid accessing freed tasks.

On 22.07.10 01:14:40, Benjamin Herrenschmidt wrote:

> So the initial observation is a spinlock bad magic followed by a crash
> in the spinlock debug code:
>
> [ 1541.586531] BUG: spinlock bad magic on CPU#5, events/5/136
> [ 1541.597564] Unable to handle kernel paging request for data at address 0x6b6b6b6b6b6b6d03
>
> Backtrace looks like:
>
>       spin_bug+0x74/0xd4
>       ._raw_spin_lock+0x48/0x184
>       ._spin_lock+0x10/0x24
>       .get_task_mm+0x28/0x8c
>       .sync_buffer+0x1b4/0x598
>       .wq_sync_buffer+0xa0/0xdc
>       .worker_thread+0x1d8/0x2a8
>       .kthread+0xa8/0xb4
>       .kernel_thread+0x54/0x70
>
> So we are accessing a freed task struct in the work queue when
> processing the samples.

Reported-by: Benjamin Herrenschmidt <[email protected]>
Cc: [email protected]
Signed-off-by: Robert Richter <[email protected]>
  • Loading branch information
Robert Richter committed Aug 25, 2010
1 parent da5cabf commit 750d857
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 15 deletions.
27 changes: 14 additions & 13 deletions drivers/oprofile/buffer_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,24 +141,14 @@ static struct notifier_block module_load_nb = {
.notifier_call = module_load_notify,
};


static void end_sync(void)
{
end_cpu_work();
/* make sure we don't leak task structs */
process_task_mortuary();
process_task_mortuary();
}


int sync_start(void)
{
int err;

if (!zalloc_cpumask_var(&marked_cpus, GFP_KERNEL))
return -ENOMEM;

start_cpu_work();
mutex_lock(&buffer_mutex);

err = task_handoff_register(&task_free_nb);
if (err)
Expand All @@ -173,7 +163,10 @@ int sync_start(void)
if (err)
goto out4;

start_cpu_work();

out:
mutex_unlock(&buffer_mutex);
return err;
out4:
profile_event_unregister(PROFILE_MUNMAP, &munmap_nb);
Expand All @@ -182,19 +175,27 @@ int sync_start(void)
out2:
task_handoff_unregister(&task_free_nb);
out1:
end_sync();
free_cpumask_var(marked_cpus);
goto out;
}


void sync_stop(void)
{
/* flush buffers */
mutex_lock(&buffer_mutex);
end_cpu_work();
unregister_module_notifier(&module_load_nb);
profile_event_unregister(PROFILE_MUNMAP, &munmap_nb);
profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb);
task_handoff_unregister(&task_free_nb);
end_sync();
mutex_unlock(&buffer_mutex);
flush_scheduled_work();

/* make sure we don't leak task structs */
process_task_mortuary();
process_task_mortuary();

free_cpumask_var(marked_cpus);
}

Expand Down
2 changes: 0 additions & 2 deletions drivers/oprofile/cpu_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,6 @@ void end_cpu_work(void)

cancel_delayed_work(&b->work);
}

flush_scheduled_work();
}

/*
Expand Down

0 comments on commit 750d857

Please sign in to comment.