diff options
Diffstat (limited to 'kernel/fork.c')
-rw-r--r-- | kernel/fork.c | 64 |
1 files changed, 35 insertions, 29 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 14cf79f14237..51ad0b0b7266 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <linux/ftrace.h> | 49 | #include <linux/ftrace.h> |
50 | #include <linux/profile.h> | 50 | #include <linux/profile.h> |
51 | #include <linux/rmap.h> | 51 | #include <linux/rmap.h> |
52 | #include <linux/ksm.h> | ||
52 | #include <linux/acct.h> | 53 | #include <linux/acct.h> |
53 | #include <linux/tsacct_kern.h> | 54 | #include <linux/tsacct_kern.h> |
54 | #include <linux/cn_proc.h> | 55 | #include <linux/cn_proc.h> |
@@ -61,7 +62,7 @@ | |||
61 | #include <linux/blkdev.h> | 62 | #include <linux/blkdev.h> |
62 | #include <linux/fs_struct.h> | 63 | #include <linux/fs_struct.h> |
63 | #include <linux/magic.h> | 64 | #include <linux/magic.h> |
64 | #include <linux/perf_counter.h> | 65 | #include <linux/perf_event.h> |
65 | #include <linux/posix-timers.h> | 66 | #include <linux/posix-timers.h> |
66 | 67 | ||
67 | #include <asm/pgtable.h> | 68 | #include <asm/pgtable.h> |
@@ -137,9 +138,17 @@ struct kmem_cache *vm_area_cachep; | |||
137 | /* SLAB cache for mm_struct structures (tsk->mm) */ | 138 | /* SLAB cache for mm_struct structures (tsk->mm) */ |
138 | static struct kmem_cache *mm_cachep; | 139 | static struct kmem_cache *mm_cachep; |
139 | 140 | ||
141 | static void account_kernel_stack(struct thread_info *ti, int account) | ||
142 | { | ||
143 | struct zone *zone = page_zone(virt_to_page(ti)); | ||
144 | |||
145 | mod_zone_page_state(zone, NR_KERNEL_STACK, account); | ||
146 | } | ||
147 | |||
140 | void free_task(struct task_struct *tsk) | 148 | void free_task(struct task_struct *tsk) |
141 | { | 149 | { |
142 | prop_local_destroy_single(&tsk->dirties); | 150 | prop_local_destroy_single(&tsk->dirties); |
151 | account_kernel_stack(tsk->stack, -1); | ||
143 | free_thread_info(tsk->stack); | 152 | free_thread_info(tsk->stack); |
144 | rt_mutex_debug_task_free(tsk); | 153 | rt_mutex_debug_task_free(tsk); |
145 | ftrace_graph_exit_task(tsk); | 154 | ftrace_graph_exit_task(tsk); |
@@ -153,8 +162,7 @@ void __put_task_struct(struct task_struct *tsk) | |||
153 | WARN_ON(atomic_read(&tsk->usage)); | 162 | WARN_ON(atomic_read(&tsk->usage)); |
154 | WARN_ON(tsk == current); | 163 | WARN_ON(tsk == current); |
155 | 164 | ||
156 | put_cred(tsk->real_cred); | 165 | exit_creds(tsk); |
157 | put_cred(tsk->cred); | ||
158 | delayacct_tsk_free(tsk); | 166 | delayacct_tsk_free(tsk); |
159 | 167 | ||
160 | if (!profile_handoff_task(tsk)) | 168 | if (!profile_handoff_task(tsk)) |
@@ -255,6 +263,9 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) | |||
255 | tsk->btrace_seq = 0; | 263 | tsk->btrace_seq = 0; |
256 | #endif | 264 | #endif |
257 | tsk->splice_pipe = NULL; | 265 | tsk->splice_pipe = NULL; |
266 | |||
267 | account_kernel_stack(ti, 1); | ||
268 | |||
258 | return tsk; | 269 | return tsk; |
259 | 270 | ||
260 | out: | 271 | out: |
@@ -290,6 +301,9 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) | |||
290 | rb_link = &mm->mm_rb.rb_node; | 301 | rb_link = &mm->mm_rb.rb_node; |
291 | rb_parent = NULL; | 302 | rb_parent = NULL; |
292 | pprev = &mm->mmap; | 303 | pprev = &mm->mmap; |
304 | retval = ksm_fork(mm, oldmm); | ||
305 | if (retval) | ||
306 | goto out; | ||
293 | 307 | ||
294 | for (mpnt = oldmm->mmap; mpnt; mpnt = mpnt->vm_next) { | 308 | for (mpnt = oldmm->mmap; mpnt; mpnt = mpnt->vm_next) { |
295 | struct file *file; | 309 | struct file *file; |
@@ -426,8 +440,8 @@ static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p) | |||
426 | atomic_set(&mm->mm_count, 1); | 440 | atomic_set(&mm->mm_count, 1); |
427 | init_rwsem(&mm->mmap_sem); | 441 | init_rwsem(&mm->mmap_sem); |
428 | INIT_LIST_HEAD(&mm->mmlist); | 442 | INIT_LIST_HEAD(&mm->mmlist); |
429 | mm->flags = (current->mm) ? current->mm->flags : default_dump_filter; | 443 | mm->flags = (current->mm) ? |
430 | mm->oom_adj = (current->mm) ? current->mm->oom_adj : 0; | 444 | (current->mm->flags & MMF_INIT_MASK) : default_dump_filter; |
431 | mm->core_state = NULL; | 445 | mm->core_state = NULL; |
432 | mm->nr_ptes = 0; | 446 | mm->nr_ptes = 0; |
433 | set_mm_counter(mm, file_rss, 0); | 447 | set_mm_counter(mm, file_rss, 0); |
@@ -488,6 +502,7 @@ void mmput(struct mm_struct *mm) | |||
488 | 502 | ||
489 | if (atomic_dec_and_test(&mm->mm_users)) { | 503 | if (atomic_dec_and_test(&mm->mm_users)) { |
490 | exit_aio(mm); | 504 | exit_aio(mm); |
505 | ksm_exit(mm); | ||
491 | exit_mmap(mm); | 506 | exit_mmap(mm); |
492 | set_mm_exe_file(mm, NULL); | 507 | set_mm_exe_file(mm, NULL); |
493 | if (!list_empty(&mm->mmlist)) { | 508 | if (!list_empty(&mm->mmlist)) { |
@@ -817,11 +832,8 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) | |||
817 | { | 832 | { |
818 | struct signal_struct *sig; | 833 | struct signal_struct *sig; |
819 | 834 | ||
820 | if (clone_flags & CLONE_THREAD) { | 835 | if (clone_flags & CLONE_THREAD) |
821 | atomic_inc(¤t->signal->count); | ||
822 | atomic_inc(¤t->signal->live); | ||
823 | return 0; | 836 | return 0; |
824 | } | ||
825 | 837 | ||
826 | sig = kmem_cache_alloc(signal_cachep, GFP_KERNEL); | 838 | sig = kmem_cache_alloc(signal_cachep, GFP_KERNEL); |
827 | tsk->signal = sig; | 839 | tsk->signal = sig; |
@@ -855,6 +867,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) | |||
855 | sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0; | 867 | sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0; |
856 | sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0; | 868 | sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0; |
857 | sig->inblock = sig->oublock = sig->cinblock = sig->coublock = 0; | 869 | sig->inblock = sig->oublock = sig->cinblock = sig->coublock = 0; |
870 | sig->maxrss = sig->cmaxrss = 0; | ||
858 | task_io_accounting_init(&sig->ioac); | 871 | task_io_accounting_init(&sig->ioac); |
859 | sig->sum_sched_runtime = 0; | 872 | sig->sum_sched_runtime = 0; |
860 | taskstats_tgid_init(sig); | 873 | taskstats_tgid_init(sig); |
@@ -869,6 +882,8 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) | |||
869 | 882 | ||
870 | tty_audit_fork(sig); | 883 | tty_audit_fork(sig); |
871 | 884 | ||
885 | sig->oom_adj = current->signal->oom_adj; | ||
886 | |||
872 | return 0; | 887 | return 0; |
873 | } | 888 | } |
874 | 889 | ||
@@ -879,16 +894,6 @@ void __cleanup_signal(struct signal_struct *sig) | |||
879 | kmem_cache_free(signal_cachep, sig); | 894 | kmem_cache_free(signal_cachep, sig); |
880 | } | 895 | } |
881 | 896 | ||
882 | static void cleanup_signal(struct task_struct *tsk) | ||
883 | { | ||
884 | struct signal_struct *sig = tsk->signal; | ||
885 | |||
886 | atomic_dec(&sig->live); | ||
887 | |||
888 | if (atomic_dec_and_test(&sig->count)) | ||
889 | __cleanup_signal(sig); | ||
890 | } | ||
891 | |||
892 | static void copy_flags(unsigned long clone_flags, struct task_struct *p) | 897 | static void copy_flags(unsigned long clone_flags, struct task_struct *p) |
893 | { | 898 | { |
894 | unsigned long new_flags = p->flags; | 899 | unsigned long new_flags = p->flags; |
@@ -1023,10 +1028,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1023 | copy_flags(clone_flags, p); | 1028 | copy_flags(clone_flags, p); |
1024 | INIT_LIST_HEAD(&p->children); | 1029 | INIT_LIST_HEAD(&p->children); |
1025 | INIT_LIST_HEAD(&p->sibling); | 1030 | INIT_LIST_HEAD(&p->sibling); |
1026 | #ifdef CONFIG_PREEMPT_RCU | 1031 | rcu_copy_process(p); |
1027 | p->rcu_read_lock_nesting = 0; | ||
1028 | p->rcu_flipctr_idx = 0; | ||
1029 | #endif /* #ifdef CONFIG_PREEMPT_RCU */ | ||
1030 | p->vfork_done = NULL; | 1032 | p->vfork_done = NULL; |
1031 | spin_lock_init(&p->alloc_lock); | 1033 | spin_lock_init(&p->alloc_lock); |
1032 | 1034 | ||
@@ -1094,10 +1096,12 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1094 | 1096 | ||
1095 | p->bts = NULL; | 1097 | p->bts = NULL; |
1096 | 1098 | ||
1099 | p->stack_start = stack_start; | ||
1100 | |||
1097 | /* Perform scheduler related setup. Assign this task to a CPU. */ | 1101 | /* Perform scheduler related setup. Assign this task to a CPU. */ |
1098 | sched_fork(p, clone_flags); | 1102 | sched_fork(p, clone_flags); |
1099 | 1103 | ||
1100 | retval = perf_counter_init_task(p); | 1104 | retval = perf_event_init_task(p); |
1101 | if (retval) | 1105 | if (retval) |
1102 | goto bad_fork_cleanup_policy; | 1106 | goto bad_fork_cleanup_policy; |
1103 | 1107 | ||
@@ -1241,6 +1245,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1241 | } | 1245 | } |
1242 | 1246 | ||
1243 | if (clone_flags & CLONE_THREAD) { | 1247 | if (clone_flags & CLONE_THREAD) { |
1248 | atomic_inc(¤t->signal->count); | ||
1249 | atomic_inc(¤t->signal->live); | ||
1244 | p->group_leader = current->group_leader; | 1250 | p->group_leader = current->group_leader; |
1245 | list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group); | 1251 | list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group); |
1246 | } | 1252 | } |
@@ -1270,7 +1276,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1270 | write_unlock_irq(&tasklist_lock); | 1276 | write_unlock_irq(&tasklist_lock); |
1271 | proc_fork_connector(p); | 1277 | proc_fork_connector(p); |
1272 | cgroup_post_fork(p); | 1278 | cgroup_post_fork(p); |
1273 | perf_counter_fork(p); | 1279 | perf_event_fork(p); |
1274 | return p; | 1280 | return p; |
1275 | 1281 | ||
1276 | bad_fork_free_pid: | 1282 | bad_fork_free_pid: |
@@ -1284,7 +1290,8 @@ bad_fork_cleanup_mm: | |||
1284 | if (p->mm) | 1290 | if (p->mm) |
1285 | mmput(p->mm); | 1291 | mmput(p->mm); |
1286 | bad_fork_cleanup_signal: | 1292 | bad_fork_cleanup_signal: |
1287 | cleanup_signal(p); | 1293 | if (!(clone_flags & CLONE_THREAD)) |
1294 | __cleanup_signal(p->signal); | ||
1288 | bad_fork_cleanup_sighand: | 1295 | bad_fork_cleanup_sighand: |
1289 | __cleanup_sighand(p->sighand); | 1296 | __cleanup_sighand(p->sighand); |
1290 | bad_fork_cleanup_fs: | 1297 | bad_fork_cleanup_fs: |
@@ -1296,7 +1303,7 @@ bad_fork_cleanup_semundo: | |||
1296 | bad_fork_cleanup_audit: | 1303 | bad_fork_cleanup_audit: |
1297 | audit_free(p); | 1304 | audit_free(p); |
1298 | bad_fork_cleanup_policy: | 1305 | bad_fork_cleanup_policy: |
1299 | perf_counter_free_task(p); | 1306 | perf_event_free_task(p); |
1300 | #ifdef CONFIG_NUMA | 1307 | #ifdef CONFIG_NUMA |
1301 | mpol_put(p->mempolicy); | 1308 | mpol_put(p->mempolicy); |
1302 | bad_fork_cleanup_cgroup: | 1309 | bad_fork_cleanup_cgroup: |
@@ -1309,8 +1316,7 @@ bad_fork_cleanup_put_domain: | |||
1309 | module_put(task_thread_info(p)->exec_domain->module); | 1316 | module_put(task_thread_info(p)->exec_domain->module); |
1310 | bad_fork_cleanup_count: | 1317 | bad_fork_cleanup_count: |
1311 | atomic_dec(&p->cred->user->processes); | 1318 | atomic_dec(&p->cred->user->processes); |
1312 | put_cred(p->real_cred); | 1319 | exit_creds(p); |
1313 | put_cred(p->cred); | ||
1314 | bad_fork_free: | 1320 | bad_fork_free: |
1315 | free_task(p); | 1321 | free_task(p); |
1316 | fork_out: | 1322 | fork_out: |