diff options
Diffstat (limited to 'kernel/fork.c')
| -rw-r--r-- | kernel/fork.c | 105 | 
1 files changed, 58 insertions, 47 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 086fe73ad6b..6a13c46cd87 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -28,6 +28,8 @@  #include <linux/mman.h>  #include <linux/mmu_notifier.h>  #include <linux/fs.h> +#include <linux/mm.h> +#include <linux/vmacache.h>  #include <linux/nsproxy.h>  #include <linux/capability.h>  #include <linux/cpu.h> @@ -71,6 +73,7 @@  #include <linux/signalfd.h>  #include <linux/uprobes.h>  #include <linux/aio.h> +#include <linux/compiler.h>  #include <asm/pgtable.h>  #include <asm/pgalloc.h> @@ -147,15 +150,15 @@ void __weak arch_release_thread_info(struct thread_info *ti)  static struct thread_info *alloc_thread_info_node(struct task_struct *tsk,  						  int node)  { -	struct page *page = alloc_pages_node(node, THREADINFO_GFP_ACCOUNTED, -					     THREAD_SIZE_ORDER); +	struct page *page = alloc_kmem_pages_node(node, THREADINFO_GFP, +						  THREAD_SIZE_ORDER);  	return page ? page_address(page) : NULL;  }  static inline void free_thread_info(struct thread_info *ti)  { -	free_memcg_kmem_pages((unsigned long)ti, THREAD_SIZE_ORDER); +	free_kmem_pages((unsigned long)ti, THREAD_SIZE_ORDER);  }  # else  static struct kmem_cache *thread_info_cache; @@ -237,6 +240,7 @@ void __put_task_struct(struct task_struct *tsk)  	WARN_ON(atomic_read(&tsk->usage));  	WARN_ON(tsk == current); +	task_numa_free(tsk);  	security_task_free(tsk);  	exit_creds(tsk);  	delayacct_tsk_free(tsk); @@ -283,7 +287,7 @@ void __init fork_init(unsigned long mempages)  		init_task.signal->rlim[RLIMIT_NPROC];  } -int __attribute__((weak)) arch_dup_task_struct(struct task_struct *dst, +int __weak arch_dup_task_struct(struct task_struct *dst,  					       struct task_struct *src)  {  	*dst = *src; @@ -363,7 +367,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)  	mm->locked_vm = 0;  	mm->mmap = NULL; -	mm->mmap_cache = NULL; +	mm->vmacache_seqnum = 0;  	mm->map_count = 0;  	cpumask_clear(mm_cpumask(mm));  	mm->mm_rb = RB_ROOT; @@ -529,17 +533,23 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p)  	atomic_set(&mm->mm_count, 1);  	init_rwsem(&mm->mmap_sem);  	INIT_LIST_HEAD(&mm->mmlist); -	mm->flags = (current->mm) ? -		(current->mm->flags & MMF_INIT_MASK) : default_dump_filter;  	mm->core_state = NULL; -	mm->nr_ptes = 0; +	atomic_long_set(&mm->nr_ptes, 0);  	memset(&mm->rss_stat, 0, sizeof(mm->rss_stat));  	spin_lock_init(&mm->page_table_lock);  	mm_init_aio(mm);  	mm_init_owner(mm, p); +	clear_tlb_flush_pending(mm); -	if (likely(!mm_alloc_pgd(mm))) { +	if (current->mm) { +		mm->flags = current->mm->flags & MMF_INIT_MASK; +		mm->def_flags = current->mm->def_flags & VM_INIT_DEF_MASK; +	} else { +		mm->flags = default_dump_filter;  		mm->def_flags = 0; +	} + +	if (likely(!mm_alloc_pgd(mm))) {  		mmu_notifier_mm_init(mm);  		return mm;  	} @@ -560,7 +570,7 @@ static void check_mm(struct mm_struct *mm)  					  "mm:%p idx:%d val:%ld\n", mm, i, x);  	} -#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && !USE_SPLIT_PMD_PTLOCKS  	VM_BUG_ON(mm->pmd_huge_pte);  #endif  } @@ -799,14 +809,11 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm)   * Allocate a new mm structure and copy contents from the   * mm structure of the passed in task structure.   */ -struct mm_struct *dup_mm(struct task_struct *tsk) +static struct mm_struct *dup_mm(struct task_struct *tsk)  {  	struct mm_struct *mm, *oldmm = current->mm;  	int err; -	if (!oldmm) -		return NULL; -  	mm = allocate_mm();  	if (!mm)  		goto fail_nomem; @@ -814,12 +821,9 @@ struct mm_struct *dup_mm(struct task_struct *tsk)  	memcpy(mm, oldmm, sizeof(*mm));  	mm_init_cpumask(mm); -#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && !USE_SPLIT_PMD_PTLOCKS  	mm->pmd_huge_pte = NULL;  #endif -#ifdef CONFIG_NUMA_BALANCING -	mm->first_nid = NUMA_PTE_SCAN_INIT; -#endif  	if (!mm_init(mm, tsk))  		goto fail_nomem; @@ -881,6 +885,9 @@ static int copy_mm(unsigned long clone_flags, struct task_struct *tsk)  	if (!oldmm)  		return 0; +	/* initialize the new vmacache entries */ +	vmacache_flush(tsk); +  	if (clone_flags & CLONE_VM) {  		atomic_inc(&oldmm->mm_users);  		mm = oldmm; @@ -1037,6 +1044,11 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)  	sig->nr_threads = 1;  	atomic_set(&sig->live, 1);  	atomic_set(&sig->sigcnt, 1); + +	/* list_add(thread_node, thread_head) without INIT_LIST_HEAD() */ +	sig->thread_head = (struct list_head)LIST_HEAD_INIT(tsk->thread_node); +	tsk->thread_node = (struct list_head)LIST_HEAD_INIT(sig->thread_head); +  	init_waitqueue_head(&sig->wait_chldexit);  	sig->curr_target = tsk;  	init_sigpending(&sig->shared_pending); @@ -1069,15 +1081,6 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)  	return 0;  } -static void copy_flags(unsigned long clone_flags, struct task_struct *p) -{ -	unsigned long new_flags = p->flags; - -	new_flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER); -	new_flags |= PF_FORKNOEXEC; -	p->flags = new_flags; -} -  SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr)  {  	current->clear_child_tid = tidptr; @@ -1089,17 +1092,19 @@ static void rt_mutex_init_task(struct task_struct *p)  {  	raw_spin_lock_init(&p->pi_lock);  #ifdef CONFIG_RT_MUTEXES -	plist_head_init(&p->pi_waiters); +	p->pi_waiters = RB_ROOT; +	p->pi_waiters_leftmost = NULL;  	p->pi_blocked_on = NULL; +	p->pi_top_task = NULL;  #endif  } -#ifdef CONFIG_MM_OWNER +#ifdef CONFIG_MEMCG  void mm_init_owner(struct mm_struct *mm, struct task_struct *p)  {  	mm->owner = p;  } -#endif /* CONFIG_MM_OWNER */ +#endif /* CONFIG_MEMCG */  /*   * Initialize POSIX timer handling for a single task. @@ -1174,7 +1179,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,  	 * do not allow it to share a thread group or signal handlers or  	 * parent with the forking task.  	 */ -	if (clone_flags & (CLONE_SIGHAND | CLONE_PARENT)) { +	if (clone_flags & CLONE_SIGHAND) {  		if ((clone_flags & (CLONE_NEWUSER | CLONE_NEWPID)) ||  		    (task_active_pid_ns(current) !=  				current->nsproxy->pid_ns_for_children)) @@ -1224,9 +1229,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,  	if (!try_module_get(task_thread_info(p)->exec_domain->module))  		goto bad_fork_cleanup_count; -	p->did_exec = 0;  	delayacct_tsk_init(p);	/* Must remain after dup_task_struct() */ -	copy_flags(clone_flags, p); +	p->flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER); +	p->flags |= PF_FORKNOEXEC;  	INIT_LIST_HEAD(&p->children);  	INIT_LIST_HEAD(&p->sibling);  	rcu_copy_process(p); @@ -1270,9 +1275,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,  	if (IS_ERR(p->mempolicy)) {  		retval = PTR_ERR(p->mempolicy);  		p->mempolicy = NULL; -		goto bad_fork_cleanup_cgroup; +		goto bad_fork_cleanup_threadgroup_lock;  	} -	mpol_fix_fork_child_flag(p);  #endif  #ifdef CONFIG_CPUSETS  	p->cpuset_mem_spread_rotor = NUMA_NO_NODE; @@ -1313,7 +1317,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,  #endif  	/* Perform scheduler related setup. Assign this task to a CPU. */ -	sched_fork(p); +	retval = sched_fork(clone_flags, p); +	if (retval) +		goto bad_fork_cleanup_policy;  	retval = perf_event_init_task(p);  	if (retval) @@ -1373,7 +1379,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,  	INIT_LIST_HEAD(&p->pi_state_list);  	p->pi_state_cache = NULL;  #endif -	uprobe_copy_process(p);  	/*  	 * sigaltstack should be cleared when sharing the same VM  	 */ @@ -1406,13 +1411,11 @@ static struct task_struct *copy_process(unsigned long clone_flags,  		p->tgid = p->pid;  	} -	p->pdeath_signal = 0; -	p->exit_state = 0; -  	p->nr_dirtied = 0;  	p->nr_dirtied_pause = 128 >> (PAGE_SHIFT - 10);  	p->dirty_paused_when = 0; +	p->pdeath_signal = 0;  	INIT_LIST_HEAD(&p->thread_group);  	p->task_works = NULL; @@ -1475,6 +1478,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,  			atomic_inc(¤t->signal->sigcnt);  			list_add_tail_rcu(&p->thread_group,  					  &p->group_leader->thread_group); +			list_add_tail_rcu(&p->thread_node, +					  &p->signal->thread_head);  		}  		attach_pid(p, PIDTYPE_PID);  		nr_threads++; @@ -1482,7 +1487,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,  	total_forks++;  	spin_unlock(¤t->sighand->siglock); +	syscall_tracepoint_update(p);  	write_unlock_irq(&tasklist_lock); +  	proc_fork_connector(p);  	cgroup_post_fork(p);  	if (clone_flags & CLONE_THREAD) @@ -1490,6 +1497,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,  	perf_event_fork(p);  	trace_task_newtask(p, clone_flags); +	uprobe_copy_process(p, clone_flags);  	return p; @@ -1521,11 +1529,10 @@ bad_fork_cleanup_policy:  	perf_event_free_task(p);  #ifdef CONFIG_NUMA  	mpol_put(p->mempolicy); -bad_fork_cleanup_cgroup: +bad_fork_cleanup_threadgroup_lock:  #endif  	if (clone_flags & CLONE_THREAD)  		threadgroup_change_end(current); -	cgroup_exit(p, 0);  	delayacct_tsk_free(p);  	module_put(task_thread_info(p)->exec_domain->module);  bad_fork_cleanup_count: @@ -1601,10 +1608,12 @@ long do_fork(unsigned long clone_flags,  	 */  	if (!IS_ERR(p)) {  		struct completion vfork; +		struct pid *pid;  		trace_sched_process_fork(current, p); -		nr = task_pid_vnr(p); +		pid = get_task_pid(p, PIDTYPE_PID); +		nr = pid_vnr(pid);  		if (clone_flags & CLONE_PARENT_SETTID)  			put_user(nr, parent_tidptr); @@ -1619,12 +1628,14 @@ long do_fork(unsigned long clone_flags,  		/* forking complete and child started to run, tell ptracer */  		if (unlikely(trace)) -			ptrace_event(trace, nr); +			ptrace_event_pid(trace, pid);  		if (clone_flags & CLONE_VFORK) {  			if (!wait_for_vfork_done(p, &vfork)) -				ptrace_event(PTRACE_EVENT_VFORK_DONE, nr); +				ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid);  		} + +		put_pid(pid);  	} else {  		nr = PTR_ERR(p);  	} @@ -1647,7 +1658,7 @@ SYSCALL_DEFINE0(fork)  	return do_fork(SIGCHLD, 0, 0, NULL, NULL);  #else  	/* can not support in nommu mode */ -	return(-EINVAL); +	return -EINVAL;  #endif  }  #endif @@ -1655,7 +1666,7 @@ SYSCALL_DEFINE0(fork)  #ifdef __ARCH_WANT_SYS_VFORK  SYSCALL_DEFINE0(vfork)  { -	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0,  +	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0,  			0, NULL, NULL);  }  #endif  | 
