aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/fork.c
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2012-03-15 11:19:05 -0400
committerArnd Bergmann <arnd@arndb.de>2012-03-15 11:20:07 -0400
commitf4e2467bad53023589cbff18dd1ab6e0aa3f004c (patch)
tree8d7abbf418eabd25bbcdc9b6de2f8216d2eaa616 /kernel/fork.c
parente3643b77de143c5548ec93abd8aa68f4123295ea (diff)
parenta6de3df4f172e124280d88e617ee7d29f7af970b (diff)
Merge branch 'ep93xx-for-arm-soc' of git://github.com/RyanMallon/linux-2.6 into next/cleanup
* 'ep93xx-for-arm-soc' of git://github.com/RyanMallon/linux-2.6: ep93xx: Remove unnecessary includes of ep93xx-regs.h ep93xx: Move EP93XX_SYSCON defines to SoC private header ep93xx: Move crunch code to mach-ep93xx directory ep93xx: Make syscon access functions private to SoC ep93xx: Configure GPIO ports in core code ep93xx: Move peripheral defines to local SoC header ep93xx: Convert the watchdog driver into a platform device. ep93xx: Use ioremap for backlight driver ep93xx: Move GPIO defines to gpio-ep93xx.h ep93xx: Don't use system controller defines in audio drivers ep93xx: Move PHYS_BASE defines to local SoC header file (update to v3.3-rc7) Conflicts: arch/arm/mach-s3c2440/common.h
Diffstat (limited to 'kernel/fork.c')
-rw-r--r--kernel/fork.c60
1 files changed, 39 insertions, 21 deletions
diff --git a/kernel/fork.c b/kernel/fork.c
index e2cd3e2a5ae8..26a7a6707fa7 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -668,6 +668,38 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
668 return mm; 668 return mm;
669} 669}
670 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
671/* Please note the differences between mmput and mm_release. 703/* Please note the differences between mmput and mm_release.
672 * mmput is called whenever we stop holding onto a mm_struct, 704 * mmput is called whenever we stop holding onto a mm_struct,
673 * error success whatever. 705 * error success whatever.
@@ -683,8 +715,6 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
683 */ 715 */
684void mm_release(struct task_struct *tsk, struct mm_struct *mm) 716void mm_release(struct task_struct *tsk, struct mm_struct *mm)
685{ 717{
686 struct completion *vfork_done = tsk->vfork_done;
687
688 /* Get rid of any futexes when releasing the mm */ 718 /* Get rid of any futexes when releasing the mm */
689#ifdef CONFIG_FUTEX 719#ifdef CONFIG_FUTEX
690 if (unlikely(tsk->robust_list)) { 720 if (unlikely(tsk->robust_list)) {
@@ -704,17 +734,15 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm)
704 /* Get rid of any cached register state */ 734 /* Get rid of any cached register state */
705 deactivate_mm(tsk, mm); 735 deactivate_mm(tsk, mm);
706 736
707 /* notify parent sleeping on vfork() */ 737 if (tsk->vfork_done)
708 if (vfork_done) { 738 complete_vfork_done(tsk);
709 tsk->vfork_done = NULL;
710 complete(vfork_done);
711 }
712 739
713 /* 740 /*
714 * 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
715 * requested. We leave this alone when dying by signal, to leave 742 * requested. We leave this alone when dying by signal, to leave
716 * 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
717 * 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.
718 */ 746 */
719 if (tsk->clear_child_tid) { 747 if (tsk->clear_child_tid) {
720 if (!(tsk->flags & PF_SIGNALED) && 748 if (!(tsk->flags & PF_SIGNALED) &&
@@ -1018,7 +1046,6 @@ static void copy_flags(unsigned long clone_flags, struct task_struct *p)
1018 1046
1019 new_flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER); 1047 new_flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER);
1020 new_flags |= PF_FORKNOEXEC; 1048 new_flags |= PF_FORKNOEXEC;
1021 new_flags |= PF_STARTING;
1022 p->flags = new_flags; 1049 p->flags = new_flags;
1023} 1050}
1024 1051
@@ -1548,16 +1575,9 @@ long do_fork(unsigned long clone_flags,
1548 if (clone_flags & CLONE_VFORK) { 1575 if (clone_flags & CLONE_VFORK) {
1549 p->vfork_done = &vfork; 1576 p->vfork_done = &vfork;
1550 init_completion(&vfork); 1577 init_completion(&vfork);
1578 get_task_struct(p);
1551 } 1579 }
1552 1580
1553 /*
1554 * We set PF_STARTING at creation in case tracing wants to
1555 * use this to distinguish a fully live task from one that
1556 * hasn't finished SIGSTOP raising yet. Now we clear it
1557 * and set the child going.
1558 */
1559 p->flags &= ~PF_STARTING;
1560
1561 wake_up_new_task(p); 1581 wake_up_new_task(p);
1562 1582
1563 /* forking complete and child started to run, tell ptracer */ 1583 /* forking complete and child started to run, tell ptracer */
@@ -1565,10 +1585,8 @@ long do_fork(unsigned long clone_flags,
1565 ptrace_event(trace, nr); 1585 ptrace_event(trace, nr);
1566 1586
1567 if (clone_flags & CLONE_VFORK) { 1587 if (clone_flags & CLONE_VFORK) {
1568 freezer_do_not_count(); 1588 if (!wait_for_vfork_done(p, &vfork))
1569 wait_for_completion(&vfork); 1589 ptrace_event(PTRACE_EVENT_VFORK_DONE, nr);
1570 freezer_count();
1571 ptrace_event(PTRACE_EVENT_VFORK_DONE, nr);
1572 } 1590 }
1573 } else { 1591 } else {
1574 nr = PTR_ERR(p); 1592 nr = PTR_ERR(p);