Skip to content

Commit

Permalink
ARM: Convert VFP/Crunch/XscaleCP thread_release() to exit_thread()
Browse files Browse the repository at this point in the history
This avoids races in the VFP code where the dead thread may have
state on another CPU.  By moving this code to exit_thread(), we
will be running as the thread, and therefore be running on the
current CPU.

This means that we can ensure that the only local state is accessed
in the thread notifiers.

Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Russell King committed Dec 18, 2009
1 parent 2395d66 commit 797245f
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 18 deletions.
2 changes: 1 addition & 1 deletion arch/arm/include/asm/thread_notify.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ static inline void thread_notify(unsigned long rc, struct thread_info *thread)
* These are the reason codes for the thread notifier.
*/
#define THREAD_NOTIFY_FLUSH 0
#define THREAD_NOTIFY_RELEASE 1
#define THREAD_NOTIFY_EXIT 1
#define THREAD_NOTIFY_SWITCH 2

#endif
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/kernel/crunch.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ static int crunch_do(struct notifier_block *self, unsigned long cmd, void *t)
* initialised state information on the first fault.
*/

case THREAD_NOTIFY_RELEASE:
case THREAD_NOTIFY_EXIT:
crunch_task_release(thread);
break;

Expand Down
12 changes: 5 additions & 7 deletions arch/arm/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,17 +274,18 @@ void show_regs(struct pt_regs * regs)
__backtrace();
}

ATOMIC_NOTIFIER_HEAD(thread_notify_head);

EXPORT_SYMBOL_GPL(thread_notify_head);

/*
* Free current thread data structures etc..
*/
void exit_thread(void)
{
thread_notify(THREAD_NOTIFY_EXIT, current_thread_info());
}

ATOMIC_NOTIFIER_HEAD(thread_notify_head);

EXPORT_SYMBOL_GPL(thread_notify_head);

void flush_thread(void)
{
struct thread_info *thread = current_thread_info();
Expand All @@ -299,9 +300,6 @@ void flush_thread(void)

void release_thread(struct task_struct *dead_task)
{
struct thread_info *thread = task_thread_info(dead_task);

thread_notify(THREAD_NOTIFY_RELEASE, thread);
}

asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/kernel/xscale-cp0.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ static int iwmmxt_do(struct notifier_block *self, unsigned long cmd, void *t)
* initialised state information on the first fault.
*/

case THREAD_NOTIFY_RELEASE:
case THREAD_NOTIFY_EXIT:
iwmmxt_task_release(thread);
break;

Expand Down
19 changes: 11 additions & 8 deletions arch/arm/vfp/vfpmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,15 @@ static void vfp_thread_flush(struct thread_info *thread)
put_cpu();
}

static void vfp_thread_release(struct thread_info *thread)
static void vfp_thread_exit(struct thread_info *thread)
{
/* release case: Per-thread VFP cleanup. */
union vfp_state *vfp = &thread->vfpstate;
unsigned int cpu = thread->cpu;
unsigned int cpu = get_cpu();

if (last_VFP_context[cpu] == vfp)
last_VFP_context[cpu] = NULL;
put_cpu();
}

/*
Expand All @@ -88,11 +89,13 @@ static void vfp_thread_release(struct thread_info *thread)
* but may change at any time.
* - we could be preempted if tree preempt rcu is enabled, so
* it is unsafe to use thread->cpu.
* THREAD_NOTIFY_RELEASE:
* - the thread (v) will not be running on any CPU; it is a dead thread.
* - thread->cpu will be the last CPU the thread ran on, which may not
* be the current CPU.
* - we could be preempted if tree preempt rcu is enabled.
* THREAD_NOTIFY_EXIT
* - the thread (v) will be running on the local CPU, so
* v === current_thread_info()
* - thread->cpu is the local CPU number at the time it is accessed,
* but may change at any time.
* - we could be preempted if tree preempt rcu is enabled, so
* it is unsafe to use thread->cpu.
*/
static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
{
Expand Down Expand Up @@ -133,7 +136,7 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
if (cmd == THREAD_NOTIFY_FLUSH)
vfp_thread_flush(thread);
else
vfp_thread_release(thread);
vfp_thread_exit(thread);

return NOTIFY_DONE;
}
Expand Down

0 comments on commit 797245f

Please sign in to comment.