diff options
Diffstat (limited to 'kernel/exit.c')
-rw-r--r-- | kernel/exit.c | 64 |
1 files changed, 38 insertions, 26 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 16395644a98f..2d8be7ebb0f7 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -40,13 +40,13 @@ | |||
40 | #include <linux/cn_proc.h> | 40 | #include <linux/cn_proc.h> |
41 | #include <linux/mutex.h> | 41 | #include <linux/mutex.h> |
42 | #include <linux/futex.h> | 42 | #include <linux/futex.h> |
43 | #include <linux/compat.h> | ||
44 | #include <linux/pipe_fs_i.h> | 43 | #include <linux/pipe_fs_i.h> |
45 | #include <linux/audit.h> /* for audit_free() */ | 44 | #include <linux/audit.h> /* for audit_free() */ |
46 | #include <linux/resource.h> | 45 | #include <linux/resource.h> |
47 | #include <linux/blkdev.h> | 46 | #include <linux/blkdev.h> |
48 | #include <linux/task_io_accounting_ops.h> | 47 | #include <linux/task_io_accounting_ops.h> |
49 | #include <linux/tracehook.h> | 48 | #include <linux/tracehook.h> |
49 | #include <trace/sched.h> | ||
50 | 50 | ||
51 | #include <asm/uaccess.h> | 51 | #include <asm/uaccess.h> |
52 | #include <asm/unistd.h> | 52 | #include <asm/unistd.h> |
@@ -112,8 +112,6 @@ static void __exit_signal(struct task_struct *tsk) | |||
112 | * We won't ever get here for the group leader, since it | 112 | * We won't ever get here for the group leader, since it |
113 | * will have been the last reference on the signal_struct. | 113 | * will have been the last reference on the signal_struct. |
114 | */ | 114 | */ |
115 | sig->utime = cputime_add(sig->utime, task_utime(tsk)); | ||
116 | sig->stime = cputime_add(sig->stime, task_stime(tsk)); | ||
117 | sig->gtime = cputime_add(sig->gtime, task_gtime(tsk)); | 115 | sig->gtime = cputime_add(sig->gtime, task_gtime(tsk)); |
118 | sig->min_flt += tsk->min_flt; | 116 | sig->min_flt += tsk->min_flt; |
119 | sig->maj_flt += tsk->maj_flt; | 117 | sig->maj_flt += tsk->maj_flt; |
@@ -122,7 +120,6 @@ static void __exit_signal(struct task_struct *tsk) | |||
122 | sig->inblock += task_io_get_inblock(tsk); | 120 | sig->inblock += task_io_get_inblock(tsk); |
123 | sig->oublock += task_io_get_oublock(tsk); | 121 | sig->oublock += task_io_get_oublock(tsk); |
124 | task_io_accounting_add(&sig->ioac, &tsk->ioac); | 122 | task_io_accounting_add(&sig->ioac, &tsk->ioac); |
125 | sig->sum_sched_runtime += tsk->se.sum_exec_runtime; | ||
126 | sig = NULL; /* Marker for below. */ | 123 | sig = NULL; /* Marker for below. */ |
127 | } | 124 | } |
128 | 125 | ||
@@ -143,13 +140,21 @@ static void __exit_signal(struct task_struct *tsk) | |||
143 | if (sig) { | 140 | if (sig) { |
144 | flush_sigqueue(&sig->shared_pending); | 141 | flush_sigqueue(&sig->shared_pending); |
145 | taskstats_tgid_free(sig); | 142 | taskstats_tgid_free(sig); |
143 | /* | ||
144 | * Make sure ->signal can't go away under rq->lock, | ||
145 | * see account_group_exec_runtime(). | ||
146 | */ | ||
147 | task_rq_unlock_wait(tsk); | ||
146 | __cleanup_signal(sig); | 148 | __cleanup_signal(sig); |
147 | } | 149 | } |
148 | } | 150 | } |
149 | 151 | ||
150 | static void delayed_put_task_struct(struct rcu_head *rhp) | 152 | static void delayed_put_task_struct(struct rcu_head *rhp) |
151 | { | 153 | { |
152 | put_task_struct(container_of(rhp, struct task_struct, rcu)); | 154 | struct task_struct *tsk = container_of(rhp, struct task_struct, rcu); |
155 | |||
156 | trace_sched_process_free(tsk); | ||
157 | put_task_struct(tsk); | ||
153 | } | 158 | } |
154 | 159 | ||
155 | 160 | ||
@@ -583,8 +588,6 @@ mm_need_new_owner(struct mm_struct *mm, struct task_struct *p) | |||
583 | * If there are other users of the mm and the owner (us) is exiting | 588 | * If there are other users of the mm and the owner (us) is exiting |
584 | * we need to find a new owner to take on the responsibility. | 589 | * we need to find a new owner to take on the responsibility. |
585 | */ | 590 | */ |
586 | if (!mm) | ||
587 | return 0; | ||
588 | if (atomic_read(&mm->mm_users) <= 1) | 591 | if (atomic_read(&mm->mm_users) <= 1) |
589 | return 0; | 592 | return 0; |
590 | if (mm->owner != p) | 593 | if (mm->owner != p) |
@@ -627,29 +630,38 @@ retry: | |||
627 | } while_each_thread(g, c); | 630 | } while_each_thread(g, c); |
628 | 631 | ||
629 | read_unlock(&tasklist_lock); | 632 | read_unlock(&tasklist_lock); |
633 | /* | ||
634 | * We found no owner yet mm_users > 1: this implies that we are | ||
635 | * most likely racing with swapoff (try_to_unuse()) or /proc or | ||
636 | * ptrace or page migration (get_task_mm()). Mark owner as NULL, | ||
637 | * so that subsystems can understand the callback and take action. | ||
638 | */ | ||
639 | down_write(&mm->mmap_sem); | ||
640 | cgroup_mm_owner_callbacks(mm->owner, NULL); | ||
641 | mm->owner = NULL; | ||
642 | up_write(&mm->mmap_sem); | ||
630 | return; | 643 | return; |
631 | 644 | ||
632 | assign_new_owner: | 645 | assign_new_owner: |
633 | BUG_ON(c == p); | 646 | BUG_ON(c == p); |
634 | get_task_struct(c); | 647 | get_task_struct(c); |
648 | read_unlock(&tasklist_lock); | ||
649 | down_write(&mm->mmap_sem); | ||
635 | /* | 650 | /* |
636 | * The task_lock protects c->mm from changing. | 651 | * The task_lock protects c->mm from changing. |
637 | * We always want mm->owner->mm == mm | 652 | * We always want mm->owner->mm == mm |
638 | */ | 653 | */ |
639 | task_lock(c); | 654 | task_lock(c); |
640 | /* | ||
641 | * Delay read_unlock() till we have the task_lock() | ||
642 | * to ensure that c does not slip away underneath us | ||
643 | */ | ||
644 | read_unlock(&tasklist_lock); | ||
645 | if (c->mm != mm) { | 655 | if (c->mm != mm) { |
646 | task_unlock(c); | 656 | task_unlock(c); |
657 | up_write(&mm->mmap_sem); | ||
647 | put_task_struct(c); | 658 | put_task_struct(c); |
648 | goto retry; | 659 | goto retry; |
649 | } | 660 | } |
650 | cgroup_mm_owner_callbacks(mm->owner, c); | 661 | cgroup_mm_owner_callbacks(mm->owner, c); |
651 | mm->owner = c; | 662 | mm->owner = c; |
652 | task_unlock(c); | 663 | task_unlock(c); |
664 | up_write(&mm->mmap_sem); | ||
653 | put_task_struct(c); | 665 | put_task_struct(c); |
654 | } | 666 | } |
655 | #endif /* CONFIG_MM_OWNER */ | 667 | #endif /* CONFIG_MM_OWNER */ |
@@ -1046,14 +1058,6 @@ NORET_TYPE void do_exit(long code) | |||
1046 | exit_itimers(tsk->signal); | 1058 | exit_itimers(tsk->signal); |
1047 | } | 1059 | } |
1048 | acct_collect(code, group_dead); | 1060 | acct_collect(code, group_dead); |
1049 | #ifdef CONFIG_FUTEX | ||
1050 | if (unlikely(tsk->robust_list)) | ||
1051 | exit_robust_list(tsk); | ||
1052 | #ifdef CONFIG_COMPAT | ||
1053 | if (unlikely(tsk->compat_robust_list)) | ||
1054 | compat_exit_robust_list(tsk); | ||
1055 | #endif | ||
1056 | #endif | ||
1057 | if (group_dead) | 1061 | if (group_dead) |
1058 | tty_audit_exit(); | 1062 | tty_audit_exit(); |
1059 | if (unlikely(tsk->audit_context)) | 1063 | if (unlikely(tsk->audit_context)) |
@@ -1066,6 +1070,8 @@ NORET_TYPE void do_exit(long code) | |||
1066 | 1070 | ||
1067 | if (group_dead) | 1071 | if (group_dead) |
1068 | acct_process(); | 1072 | acct_process(); |
1073 | trace_sched_process_exit(tsk); | ||
1074 | |||
1069 | exit_sem(tsk); | 1075 | exit_sem(tsk); |
1070 | exit_files(tsk); | 1076 | exit_files(tsk); |
1071 | exit_fs(tsk); | 1077 | exit_fs(tsk); |
@@ -1294,6 +1300,7 @@ static int wait_task_zombie(struct task_struct *p, int options, | |||
1294 | if (likely(!traced)) { | 1300 | if (likely(!traced)) { |
1295 | struct signal_struct *psig; | 1301 | struct signal_struct *psig; |
1296 | struct signal_struct *sig; | 1302 | struct signal_struct *sig; |
1303 | struct task_cputime cputime; | ||
1297 | 1304 | ||
1298 | /* | 1305 | /* |
1299 | * The resource counters for the group leader are in its | 1306 | * The resource counters for the group leader are in its |
@@ -1309,20 +1316,23 @@ static int wait_task_zombie(struct task_struct *p, int options, | |||
1309 | * need to protect the access to p->parent->signal fields, | 1316 | * need to protect the access to p->parent->signal fields, |
1310 | * as other threads in the parent group can be right | 1317 | * as other threads in the parent group can be right |
1311 | * here reaping other children at the same time. | 1318 | * here reaping other children at the same time. |
1319 | * | ||
1320 | * We use thread_group_cputime() to get times for the thread | ||
1321 | * group, which consolidates times for all threads in the | ||
1322 | * group including the group leader. | ||
1312 | */ | 1323 | */ |
1313 | spin_lock_irq(&p->parent->sighand->siglock); | 1324 | spin_lock_irq(&p->parent->sighand->siglock); |
1314 | psig = p->parent->signal; | 1325 | psig = p->parent->signal; |
1315 | sig = p->signal; | 1326 | sig = p->signal; |
1327 | thread_group_cputime(p, &cputime); | ||
1316 | psig->cutime = | 1328 | psig->cutime = |
1317 | cputime_add(psig->cutime, | 1329 | cputime_add(psig->cutime, |
1318 | cputime_add(p->utime, | 1330 | cputime_add(cputime.utime, |
1319 | cputime_add(sig->utime, | 1331 | sig->cutime)); |
1320 | sig->cutime))); | ||
1321 | psig->cstime = | 1332 | psig->cstime = |
1322 | cputime_add(psig->cstime, | 1333 | cputime_add(psig->cstime, |
1323 | cputime_add(p->stime, | 1334 | cputime_add(cputime.stime, |
1324 | cputime_add(sig->stime, | 1335 | sig->cstime)); |
1325 | sig->cstime))); | ||
1326 | psig->cgtime = | 1336 | psig->cgtime = |
1327 | cputime_add(psig->cgtime, | 1337 | cputime_add(psig->cgtime, |
1328 | cputime_add(p->gtime, | 1338 | cputime_add(p->gtime, |
@@ -1667,6 +1677,8 @@ static long do_wait(enum pid_type type, struct pid *pid, int options, | |||
1667 | struct task_struct *tsk; | 1677 | struct task_struct *tsk; |
1668 | int retval; | 1678 | int retval; |
1669 | 1679 | ||
1680 | trace_sched_process_wait(pid); | ||
1681 | |||
1670 | add_wait_queue(¤t->signal->wait_chldexit,&wait); | 1682 | add_wait_queue(¤t->signal->wait_chldexit,&wait); |
1671 | repeat: | 1683 | repeat: |
1672 | /* | 1684 | /* |