aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/fork.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/fork.c')
-rw-r--r--kernel/fork.c65
1 files changed, 43 insertions, 22 deletions
diff --git a/kernel/fork.c b/kernel/fork.c
index b77fd559c78e..26a7a6707fa7 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -66,6 +66,7 @@
66#include <linux/user-return-notifier.h> 66#include <linux/user-return-notifier.h>
67#include <linux/oom.h> 67#include <linux/oom.h>
68#include <linux/khugepaged.h> 68#include <linux/khugepaged.h>
69#include <linux/signalfd.h>
69 70
70#include <asm/pgtable.h> 71#include <asm/pgtable.h>
71#include <asm/pgalloc.h> 72#include <asm/pgalloc.h>
@@ -667,6 +668,38 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
667 return mm; 668 return mm;
668} 669}
669 670
671static void complete_vfork_done(struct task_struct *tsk)
672{
673 struct completion *vfork;
674
675 task_lock(tsk);
676 vfork = tsk->vfork_done;
677 if (likely(vfork)) {
678 tsk->vfork_done = NULL;
679 complete(vfork);
680 }
681 task_unlock(tsk);
682}
683
684static int wait_for_vfork_done(struct task_struct *child,
685 struct completion *vfork)
686{
687 int killed;
688
689 freezer_do_not_count();
690 killed = wait_for_completion_killable(vfork);
691 freezer_count();
692
693 if (killed) {
694 task_lock(child);
695 child->vfork_done = NULL;
696 task_unlock(child);
697 }
698
699 put_task_struct(child);
700 return killed;
701}
702
670/* Please note the differences between mmput and mm_release. 703/* Please note the differences between mmput and mm_release.
671 * mmput is called whenever we stop holding onto a mm_struct, 704 * mmput is called whenever we stop holding onto a mm_struct,
672 * error success whatever. 705 * error success whatever.
@@ -682,8 +715,6 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
682 */ 715 */
683void mm_release(struct task_struct *tsk, struct mm_struct *mm) 716void mm_release(struct task_struct *tsk, struct mm_struct *mm)
684{ 717{
685 struct completion *vfork_done = tsk->vfork_done;
686
687 /* Get rid of any futexes when releasing the mm */ 718 /* Get rid of any futexes when releasing the mm */
688#ifdef CONFIG_FUTEX 719#ifdef CONFIG_FUTEX
689 if (unlikely(tsk->robust_list)) { 720 if (unlikely(tsk->robust_list)) {
@@ -703,17 +734,15 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm)
703 /* Get rid of any cached register state */ 734 /* Get rid of any cached register state */
704 deactivate_mm(tsk, mm); 735 deactivate_mm(tsk, mm);
705 736
706 /* notify parent sleeping on vfork() */ 737 if (tsk->vfork_done)
707 if (vfork_done) { 738 complete_vfork_done(tsk);
708 tsk->vfork_done = NULL;
709 complete(vfork_done);
710 }
711 739
712 /* 740 /*
713 * If we're exiting normally, clear a user-space tid field if 741 * If we're exiting normally, clear a user-space tid field if
714 * requested. We leave this alone when dying by signal, to leave 742 * requested. We leave this alone when dying by signal, to leave
715 * the value intact in a core dump, and to save the unnecessary 743 * the value intact in a core dump, and to save the unnecessary
716 * trouble otherwise. Userland only wants this done for a sys_exit. 744 * trouble, say, a killed vfork parent shouldn't touch this mm.
745 * Userland only wants this done for a sys_exit.
717 */ 746 */
718 if (tsk->clear_child_tid) { 747 if (tsk->clear_child_tid) {
719 if (!(tsk->flags & PF_SIGNALED) && 748 if (!(tsk->flags & PF_SIGNALED) &&
@@ -935,8 +964,10 @@ static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)
935 964
936void __cleanup_sighand(struct sighand_struct *sighand) 965void __cleanup_sighand(struct sighand_struct *sighand)
937{ 966{
938 if (atomic_dec_and_test(&sighand->count)) 967 if (atomic_dec_and_test(&sighand->count)) {
968 signalfd_cleanup(sighand);
939 kmem_cache_free(sighand_cachep, sighand); 969 kmem_cache_free(sighand_cachep, sighand);
970 }
940} 971}
941 972
942 973
@@ -1015,7 +1046,6 @@ static void copy_flags(unsigned long clone_flags, struct task_struct *p)
1015 1046
1016 new_flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER); 1047 new_flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER);
1017 new_flags |= PF_FORKNOEXEC; 1048 new_flags |= PF_FORKNOEXEC;
1018 new_flags |= PF_STARTING;
1019 p->flags = new_flags; 1049 p->flags = new_flags;
1020} 1050}
1021 1051
@@ -1545,16 +1575,9 @@ long do_fork(unsigned long clone_flags,
1545 if (clone_flags & CLONE_VFORK) { 1575 if (clone_flags & CLONE_VFORK) {
1546 p->vfork_done = &vfork; 1576 p->vfork_done = &vfork;
1547 init_completion(&vfork); 1577 init_completion(&vfork);
1578 get_task_struct(p);
1548 } 1579 }
1549 1580
1550 /*
1551 * We set PF_STARTING at creation in case tracing wants to
1552 * use this to distinguish a fully live task from one that
1553 * hasn't finished SIGSTOP raising yet. Now we clear it
1554 * and set the child going.
1555 */
1556 p->flags &= ~PF_STARTING;
1557
1558 wake_up_new_task(p); 1581 wake_up_new_task(p);
1559 1582
1560 /* forking complete and child started to run, tell ptracer */ 1583 /* forking complete and child started to run, tell ptracer */
@@ -1562,10 +1585,8 @@ long do_fork(unsigned long clone_flags,
1562 ptrace_event(trace, nr); 1585 ptrace_event(trace, nr);
1563 1586
1564 if (clone_flags & CLONE_VFORK) { 1587 if (clone_flags & CLONE_VFORK) {
1565 freezer_do_not_count(); 1588 if (!wait_for_vfork_done(p, &vfork))
1566 wait_for_completion(&vfork); 1589 ptrace_event(PTRACE_EVENT_VFORK_DONE, nr);
1567 freezer_count();
1568 ptrace_event(PTRACE_EVENT_VFORK_DONE, nr);
1569 } 1590 }
1570 } else { 1591 } else {
1571 nr = PTR_ERR(p); 1592 nr = PTR_ERR(p);