Clarify naming of thread info/stack allocators
We've had the thread info allocated together with the thread stack for most architectures for a long time (since the thread_info was split off from the task struct), but that is about to change. But the patches that move the thread info to be off-stack (and a part of the task struct instead) made it clear how confused the allocator and freeing functions are. Because the common case was that we share an allocation with the thread stack and the thread_info, the two pointers were identical. That identity then meant that we would have things like ti = alloc_thread_info_node(tsk, node); ... tsk->stack = ti; which certainly _worked_ (since stack and thread_info have the same value), but is rather confusing: why are we assigning a thread_info to the stack? And if we move the thread_info away, the "confusing" code just gets to be entirely bogus. So remove all this confusion, and make it clear that we are doing the stack allocation by renaming and clarifying the function names to be about the stack. The fact that the thread_info then shares the allocation is an implementation detail, and not really about the allocation itself. This is a pure renaming and type fix: we pass in the same pointer, it's just that we clarify what the pointer means. The ia64 code that actually only has one single allocation (for all of task_struct, thread_info and kernel thread stack) now looks a bit odd, but since "tsk->stack" is actually not even used there, that oddity doesn't matter. It would be a separate thing to clean that up, I intentionally left the ia64 changes as a pure brute-force renaming and type change. Acked-by: Andy Lutomirski <luto@amacapital.net> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Родитель
63c04ee7d3
Коммит
b235beea9e
|
@ -226,8 +226,8 @@ config ARCH_INIT_TASK
|
||||||
config ARCH_TASK_STRUCT_ALLOCATOR
|
config ARCH_TASK_STRUCT_ALLOCATOR
|
||||||
bool
|
bool
|
||||||
|
|
||||||
# Select if arch has its private alloc_thread_info() function
|
# Select if arch has its private alloc_thread_stack() function
|
||||||
config ARCH_THREAD_INFO_ALLOCATOR
|
config ARCH_THREAD_STACK_ALLOCATOR
|
||||||
bool
|
bool
|
||||||
|
|
||||||
# Select if arch wants to size task_struct dynamically via arch_task_struct_size:
|
# Select if arch wants to size task_struct dynamically via arch_task_struct_size:
|
||||||
|
|
|
@ -45,7 +45,7 @@ config IA64
|
||||||
select GENERIC_SMP_IDLE_THREAD
|
select GENERIC_SMP_IDLE_THREAD
|
||||||
select ARCH_INIT_TASK
|
select ARCH_INIT_TASK
|
||||||
select ARCH_TASK_STRUCT_ALLOCATOR
|
select ARCH_TASK_STRUCT_ALLOCATOR
|
||||||
select ARCH_THREAD_INFO_ALLOCATOR
|
select ARCH_THREAD_STACK_ALLOCATOR
|
||||||
select ARCH_CLOCKSOURCE_DATA
|
select ARCH_CLOCKSOURCE_DATA
|
||||||
select GENERIC_TIME_VSYSCALL_OLD
|
select GENERIC_TIME_VSYSCALL_OLD
|
||||||
select SYSCTL_ARCH_UNALIGN_NO_WARN
|
select SYSCTL_ARCH_UNALIGN_NO_WARN
|
||||||
|
|
|
@ -48,15 +48,15 @@ struct thread_info {
|
||||||
#ifndef ASM_OFFSETS_C
|
#ifndef ASM_OFFSETS_C
|
||||||
/* how to get the thread information struct from C */
|
/* how to get the thread information struct from C */
|
||||||
#define current_thread_info() ((struct thread_info *) ((char *) current + IA64_TASK_SIZE))
|
#define current_thread_info() ((struct thread_info *) ((char *) current + IA64_TASK_SIZE))
|
||||||
#define alloc_thread_info_node(tsk, node) \
|
#define alloc_thread_stack_node(tsk, node) \
|
||||||
((struct thread_info *) ((char *) (tsk) + IA64_TASK_SIZE))
|
((unsigned long *) ((char *) (tsk) + IA64_TASK_SIZE))
|
||||||
#define task_thread_info(tsk) ((struct thread_info *) ((char *) (tsk) + IA64_TASK_SIZE))
|
#define task_thread_info(tsk) ((struct thread_info *) ((char *) (tsk) + IA64_TASK_SIZE))
|
||||||
#else
|
#else
|
||||||
#define current_thread_info() ((struct thread_info *) 0)
|
#define current_thread_info() ((struct thread_info *) 0)
|
||||||
#define alloc_thread_info_node(tsk, node) ((struct thread_info *) 0)
|
#define alloc_thread_stack_node(tsk, node) ((unsigned long *) 0)
|
||||||
#define task_thread_info(tsk) ((struct thread_info *) 0)
|
#define task_thread_info(tsk) ((struct thread_info *) 0)
|
||||||
#endif
|
#endif
|
||||||
#define free_thread_info(ti) /* nothing */
|
#define free_thread_stack(ti) /* nothing */
|
||||||
#define task_stack_page(tsk) ((void *)(tsk))
|
#define task_stack_page(tsk) ((void *)(tsk))
|
||||||
|
|
||||||
#define __HAVE_THREAD_FUNCTIONS
|
#define __HAVE_THREAD_FUNCTIONS
|
||||||
|
|
|
@ -115,7 +115,7 @@ static inline unsigned long current_stack_pointer(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_KGDB
|
#ifndef CONFIG_KGDB
|
||||||
void arch_release_thread_info(struct thread_info *ti);
|
void arch_release_thread_stack(unsigned long *stack);
|
||||||
#endif
|
#endif
|
||||||
#define get_thread_info(ti) get_task_struct((ti)->task)
|
#define get_thread_info(ti) get_task_struct((ti)->task)
|
||||||
#define put_thread_info(ti) put_task_struct((ti)->task)
|
#define put_thread_info(ti) put_task_struct((ti)->task)
|
||||||
|
|
|
@ -397,8 +397,9 @@ static bool kgdb_arch_undo_singlestep(struct pt_regs *regs)
|
||||||
* single-step state is cleared. At this point the breakpoints should have
|
* single-step state is cleared. At this point the breakpoints should have
|
||||||
* been removed by __switch_to().
|
* been removed by __switch_to().
|
||||||
*/
|
*/
|
||||||
void arch_release_thread_info(struct thread_info *ti)
|
void arch_release_thread_stack(unsigned long *stack)
|
||||||
{
|
{
|
||||||
|
struct thread_info *ti = (void *)stack;
|
||||||
if (kgdb_sstep_thread == ti) {
|
if (kgdb_sstep_thread == ti) {
|
||||||
kgdb_sstep_thread = NULL;
|
kgdb_sstep_thread = NULL;
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,7 @@ struct thread_info {
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
void arch_release_thread_info(struct thread_info *info);
|
void arch_release_thread_stack(unsigned long *stack);
|
||||||
|
|
||||||
/* How to get the thread information struct from C. */
|
/* How to get the thread information struct from C. */
|
||||||
register unsigned long stack_pointer __asm__("sp");
|
register unsigned long stack_pointer __asm__("sp");
|
||||||
|
|
|
@ -73,8 +73,9 @@ void arch_cpu_idle(void)
|
||||||
/*
|
/*
|
||||||
* Release a thread_info structure
|
* Release a thread_info structure
|
||||||
*/
|
*/
|
||||||
void arch_release_thread_info(struct thread_info *info)
|
void arch_release_thread_stack(unsigned long *stack)
|
||||||
{
|
{
|
||||||
|
struct thread_info *info = (void *)stack;
|
||||||
struct single_step_state *step_state = info->step_state;
|
struct single_step_state *step_state = info->step_state;
|
||||||
|
|
||||||
if (step_state) {
|
if (step_state) {
|
||||||
|
|
|
@ -3007,7 +3007,7 @@ static inline int object_is_on_stack(void *obj)
|
||||||
return (obj >= stack) && (obj < (stack + THREAD_SIZE));
|
return (obj >= stack) && (obj < (stack + THREAD_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void thread_info_cache_init(void);
|
extern void thread_stack_cache_init(void);
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_STACK_USAGE
|
#ifdef CONFIG_DEBUG_STACK_USAGE
|
||||||
static inline unsigned long stack_not_used(struct task_struct *p)
|
static inline unsigned long stack_not_used(struct task_struct *p)
|
||||||
|
|
|
@ -453,7 +453,7 @@ void __init __weak smp_setup_processor_id(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
# if THREAD_SIZE >= PAGE_SIZE
|
# if THREAD_SIZE >= PAGE_SIZE
|
||||||
void __init __weak thread_info_cache_init(void)
|
void __init __weak thread_stack_cache_init(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -627,7 +627,7 @@ asmlinkage __visible void __init start_kernel(void)
|
||||||
/* Should be run before the first non-init thread is created */
|
/* Should be run before the first non-init thread is created */
|
||||||
init_espfix_bsp();
|
init_espfix_bsp();
|
||||||
#endif
|
#endif
|
||||||
thread_info_cache_init();
|
thread_stack_cache_init();
|
||||||
cred_init();
|
cred_init();
|
||||||
fork_init();
|
fork_init();
|
||||||
proc_caches_init();
|
proc_caches_init();
|
||||||
|
|
|
@ -148,18 +148,18 @@ static inline void free_task_struct(struct task_struct *tsk)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void __weak arch_release_thread_info(struct thread_info *ti)
|
void __weak arch_release_thread_stack(unsigned long *stack)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_ARCH_THREAD_INFO_ALLOCATOR
|
#ifndef CONFIG_ARCH_THREAD_STACK_ALLOCATOR
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a
|
* Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a
|
||||||
* kmemcache based allocator.
|
* kmemcache based allocator.
|
||||||
*/
|
*/
|
||||||
# if THREAD_SIZE >= PAGE_SIZE
|
# if THREAD_SIZE >= PAGE_SIZE
|
||||||
static struct thread_info *alloc_thread_info_node(struct task_struct *tsk,
|
static unsigned long *alloc_thread_stack_node(struct task_struct *tsk,
|
||||||
int node)
|
int node)
|
||||||
{
|
{
|
||||||
struct page *page = alloc_kmem_pages_node(node, THREADINFO_GFP,
|
struct page *page = alloc_kmem_pages_node(node, THREADINFO_GFP,
|
||||||
|
@ -172,33 +172,33 @@ static struct thread_info *alloc_thread_info_node(struct task_struct *tsk,
|
||||||
return page ? page_address(page) : NULL;
|
return page ? page_address(page) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void free_thread_info(struct thread_info *ti)
|
static inline void free_thread_stack(unsigned long *stack)
|
||||||
{
|
{
|
||||||
struct page *page = virt_to_page(ti);
|
struct page *page = virt_to_page(stack);
|
||||||
|
|
||||||
memcg_kmem_update_page_stat(page, MEMCG_KERNEL_STACK,
|
memcg_kmem_update_page_stat(page, MEMCG_KERNEL_STACK,
|
||||||
-(1 << THREAD_SIZE_ORDER));
|
-(1 << THREAD_SIZE_ORDER));
|
||||||
__free_kmem_pages(page, THREAD_SIZE_ORDER);
|
__free_kmem_pages(page, THREAD_SIZE_ORDER);
|
||||||
}
|
}
|
||||||
# else
|
# else
|
||||||
static struct kmem_cache *thread_info_cache;
|
static struct kmem_cache *thread_stack_cache;
|
||||||
|
|
||||||
static struct thread_info *alloc_thread_info_node(struct task_struct *tsk,
|
static struct thread_info *alloc_thread_stack_node(struct task_struct *tsk,
|
||||||
int node)
|
int node)
|
||||||
{
|
{
|
||||||
return kmem_cache_alloc_node(thread_info_cache, THREADINFO_GFP, node);
|
return kmem_cache_alloc_node(thread_stack_cache, THREADINFO_GFP, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_thread_info(struct thread_info *ti)
|
static void free_stack(unsigned long *stack)
|
||||||
{
|
{
|
||||||
kmem_cache_free(thread_info_cache, ti);
|
kmem_cache_free(thread_stack_cache, stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_info_cache_init(void)
|
void thread_stack_cache_init(void)
|
||||||
{
|
{
|
||||||
thread_info_cache = kmem_cache_create("thread_info", THREAD_SIZE,
|
thread_stack_cache = kmem_cache_create("thread_stack", THREAD_SIZE,
|
||||||
THREAD_SIZE, 0, NULL);
|
THREAD_SIZE, 0, NULL);
|
||||||
BUG_ON(thread_info_cache == NULL);
|
BUG_ON(thread_stack_cache == NULL);
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -221,9 +221,9 @@ struct kmem_cache *vm_area_cachep;
|
||||||
/* SLAB cache for mm_struct structures (tsk->mm) */
|
/* SLAB cache for mm_struct structures (tsk->mm) */
|
||||||
static struct kmem_cache *mm_cachep;
|
static struct kmem_cache *mm_cachep;
|
||||||
|
|
||||||
static void account_kernel_stack(struct thread_info *ti, int account)
|
static void account_kernel_stack(unsigned long *stack, int account)
|
||||||
{
|
{
|
||||||
struct zone *zone = page_zone(virt_to_page(ti));
|
struct zone *zone = page_zone(virt_to_page(stack));
|
||||||
|
|
||||||
mod_zone_page_state(zone, NR_KERNEL_STACK, account);
|
mod_zone_page_state(zone, NR_KERNEL_STACK, account);
|
||||||
}
|
}
|
||||||
|
@ -231,8 +231,8 @@ static void account_kernel_stack(struct thread_info *ti, int account)
|
||||||
void free_task(struct task_struct *tsk)
|
void free_task(struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
account_kernel_stack(tsk->stack, -1);
|
account_kernel_stack(tsk->stack, -1);
|
||||||
arch_release_thread_info(tsk->stack);
|
arch_release_thread_stack(tsk->stack);
|
||||||
free_thread_info(tsk->stack);
|
free_thread_stack(tsk->stack);
|
||||||
rt_mutex_debug_task_free(tsk);
|
rt_mutex_debug_task_free(tsk);
|
||||||
ftrace_graph_exit_task(tsk);
|
ftrace_graph_exit_task(tsk);
|
||||||
put_seccomp_filter(tsk);
|
put_seccomp_filter(tsk);
|
||||||
|
@ -343,7 +343,7 @@ void set_task_stack_end_magic(struct task_struct *tsk)
|
||||||
static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
|
static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
|
||||||
{
|
{
|
||||||
struct task_struct *tsk;
|
struct task_struct *tsk;
|
||||||
struct thread_info *ti;
|
unsigned long *stack;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (node == NUMA_NO_NODE)
|
if (node == NUMA_NO_NODE)
|
||||||
|
@ -352,15 +352,15 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
|
||||||
if (!tsk)
|
if (!tsk)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
ti = alloc_thread_info_node(tsk, node);
|
stack = alloc_thread_stack_node(tsk, node);
|
||||||
if (!ti)
|
if (!stack)
|
||||||
goto free_tsk;
|
goto free_tsk;
|
||||||
|
|
||||||
err = arch_dup_task_struct(tsk, orig);
|
err = arch_dup_task_struct(tsk, orig);
|
||||||
if (err)
|
if (err)
|
||||||
goto free_ti;
|
goto free_stack;
|
||||||
|
|
||||||
tsk->stack = ti;
|
tsk->stack = stack;
|
||||||
#ifdef CONFIG_SECCOMP
|
#ifdef CONFIG_SECCOMP
|
||||||
/*
|
/*
|
||||||
* We must handle setting up seccomp filters once we're under
|
* We must handle setting up seccomp filters once we're under
|
||||||
|
@ -392,14 +392,14 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
|
||||||
tsk->task_frag.page = NULL;
|
tsk->task_frag.page = NULL;
|
||||||
tsk->wake_q.next = NULL;
|
tsk->wake_q.next = NULL;
|
||||||
|
|
||||||
account_kernel_stack(ti, 1);
|
account_kernel_stack(stack, 1);
|
||||||
|
|
||||||
kcov_task_init(tsk);
|
kcov_task_init(tsk);
|
||||||
|
|
||||||
return tsk;
|
return tsk;
|
||||||
|
|
||||||
free_ti:
|
free_stack:
|
||||||
free_thread_info(ti);
|
free_thread_stack(stack);
|
||||||
free_tsk:
|
free_tsk:
|
||||||
free_task_struct(tsk);
|
free_task_struct(tsk);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче