Commit 1929ab8c authored by Russell King's avatar Russell King Committed by Russell King

[ARM] Fix thread struct allocator for SMP case

The ARM thread struct allocator is racy on SMP systems.  Fix it by
turning it into a per-cpu based allocator.  This also allows keeps
the cache cache warm for thread structs and kernel stacks.
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent f9d8f063
...@@ -264,8 +264,12 @@ void show_fpregs(struct user_fp *regs) ...@@ -264,8 +264,12 @@ void show_fpregs(struct user_fp *regs)
/* /*
* Task structure and kernel stack allocation. * Task structure and kernel stack allocation.
*/ */
static unsigned long *thread_info_head; struct thread_info_list {
static unsigned int nr_thread_info; unsigned long *head;
unsigned int nr;
};
static DEFINE_PER_CPU(struct thread_info_list, thread_info_list) = { NULL, 0 };
#define EXTRA_TASK_STRUCT 4 #define EXTRA_TASK_STRUCT 4
...@@ -274,12 +278,15 @@ struct thread_info *alloc_thread_info(struct task_struct *task) ...@@ -274,12 +278,15 @@ struct thread_info *alloc_thread_info(struct task_struct *task)
struct thread_info *thread = NULL; struct thread_info *thread = NULL;
if (EXTRA_TASK_STRUCT) { if (EXTRA_TASK_STRUCT) {
unsigned long *p = thread_info_head; struct thread_info_list *th = &get_cpu_var(thread_info_list);
unsigned long *p = th->head;
if (p) { if (p) {
thread_info_head = (unsigned long *)p[0]; th->head = (unsigned long *)p[0];
nr_thread_info -= 1; th->nr -= 1;
} }
put_cpu_var(thread_info_list);
thread = (struct thread_info *)p; thread = (struct thread_info *)p;
} }
...@@ -300,13 +307,19 @@ struct thread_info *alloc_thread_info(struct task_struct *task) ...@@ -300,13 +307,19 @@ struct thread_info *alloc_thread_info(struct task_struct *task)
void free_thread_info(struct thread_info *thread) void free_thread_info(struct thread_info *thread)
{ {
if (EXTRA_TASK_STRUCT && nr_thread_info < EXTRA_TASK_STRUCT) { if (EXTRA_TASK_STRUCT) {
unsigned long *p = (unsigned long *)thread; struct thread_info_list *th = &get_cpu_var(thread_info_list);
p[0] = (unsigned long)thread_info_head; if (th->nr < EXTRA_TASK_STRUCT) {
thread_info_head = p; unsigned long *p = (unsigned long *)thread;
nr_thread_info += 1; p[0] = th->head;
} else th->head = p;
free_pages((unsigned long)thread, THREAD_SIZE_ORDER); th->nr += 1;
put_cpu_var(thread_info_list);
return;
}
put_cpu_var(thread_info_list);
}
free_pages((unsigned long)thread, THREAD_SIZE_ORDER);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment