diff options
Diffstat (limited to 'kernel/fork.c')
| -rw-r--r-- | kernel/fork.c | 75 | 
1 files changed, 55 insertions, 20 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index b9372a0bff1..ad54c833116 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -34,6 +34,7 @@  #include <linux/cgroup.h>  #include <linux/security.h>  #include <linux/hugetlb.h> +#include <linux/seccomp.h>  #include <linux/swap.h>  #include <linux/syscalls.h>  #include <linux/jiffies.h> @@ -47,6 +48,7 @@  #include <linux/audit.h>  #include <linux/memcontrol.h>  #include <linux/ftrace.h> +#include <linux/proc_fs.h>  #include <linux/profile.h>  #include <linux/rmap.h>  #include <linux/ksm.h> @@ -111,32 +113,67 @@ int nr_processes(void)  	return total;  } -#ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR -# define alloc_task_struct_node(node)		\ -		kmem_cache_alloc_node(task_struct_cachep, GFP_KERNEL, node) -# define free_task_struct(tsk)			\ -		kmem_cache_free(task_struct_cachep, (tsk)) +#ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR  static struct kmem_cache *task_struct_cachep; + +static inline struct task_struct *alloc_task_struct_node(int node) +{ +	return kmem_cache_alloc_node(task_struct_cachep, GFP_KERNEL, node); +} + +void __weak arch_release_task_struct(struct task_struct *tsk) { } + +static inline void free_task_struct(struct task_struct *tsk) +{ +	arch_release_task_struct(tsk); +	kmem_cache_free(task_struct_cachep, tsk); +}  #endif -#ifndef __HAVE_ARCH_THREAD_INFO_ALLOCATOR +#ifndef CONFIG_ARCH_THREAD_INFO_ALLOCATOR +void __weak arch_release_thread_info(struct thread_info *ti) { } + +/* + * Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a + * kmemcache based allocator. + */ +# if THREAD_SIZE >= PAGE_SIZE  static struct thread_info *alloc_thread_info_node(struct task_struct *tsk,  						  int node)  { -#ifdef CONFIG_DEBUG_STACK_USAGE -	gfp_t mask = GFP_KERNEL | __GFP_ZERO; -#else -	gfp_t mask = GFP_KERNEL; -#endif -	struct page *page = alloc_pages_node(node, mask, THREAD_SIZE_ORDER); +	struct page *page = alloc_pages_node(node, THREADINFO_GFP, +					     THREAD_SIZE_ORDER);  	return page ? page_address(page) : NULL;  }  static inline void free_thread_info(struct thread_info *ti)  { +	arch_release_thread_info(ti);  	free_pages((unsigned long)ti, THREAD_SIZE_ORDER);  } +# else +static struct kmem_cache *thread_info_cache; + +static struct thread_info *alloc_thread_info_node(struct task_struct *tsk, +						  int node) +{ +	return kmem_cache_alloc_node(thread_info_cache, THREADINFO_GFP, node); +} + +static void free_thread_info(struct thread_info *ti) +{ +	arch_release_thread_info(ti); +	kmem_cache_free(thread_info_cache, ti); +} + +void thread_info_cache_init(void) +{ +	thread_info_cache = kmem_cache_create("thread_info", THREAD_SIZE, +					      THREAD_SIZE, 0, NULL); +	BUG_ON(thread_info_cache == NULL); +} +# endif  #endif  /* SLAB cache for signal_struct structures (tsk->signal) */ @@ -170,6 +207,7 @@ void free_task(struct task_struct *tsk)  	free_thread_info(tsk->stack);  	rt_mutex_debug_task_free(tsk);  	ftrace_graph_exit_task(tsk); +	put_seccomp_filter(tsk);  	free_task_struct(tsk);  }  EXPORT_SYMBOL(free_task); @@ -203,17 +241,11 @@ void __put_task_struct(struct task_struct *tsk)  }  EXPORT_SYMBOL_GPL(__put_task_struct); -/* - * macro override instead of weak attribute alias, to workaround - * gcc 4.1.0 and 4.1.1 bugs with weak attribute and empty functions. - */ -#ifndef arch_task_cache_init -#define arch_task_cache_init() -#endif +void __init __weak arch_task_cache_init(void) { }  void __init fork_init(unsigned long mempages)  { -#ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR +#ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR  #ifndef ARCH_MIN_TASKALIGN  #define ARCH_MIN_TASKALIGN	L1_CACHE_BYTES  #endif @@ -1162,6 +1194,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,  		goto fork_out;  	ftrace_graph_init_task(p); +	get_seccomp_filter(p);  	rt_mutex_init_task(p); @@ -1464,6 +1497,8 @@ bad_fork_cleanup_io:  	if (p->io_context)  		exit_io_context(p);  bad_fork_cleanup_namespaces: +	if (unlikely(clone_flags & CLONE_NEWPID)) +		pid_ns_release_proc(p->nsproxy->pid_ns);  	exit_task_namespaces(p);  bad_fork_cleanup_mm:  	if (p->mm)  |