diff options
Diffstat (limited to 'kernel/fork.c')
-rw-r--r-- | kernel/fork.c | 93 |
1 files changed, 45 insertions, 48 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 6715ebc3761d..b9e2edd00726 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -60,6 +60,7 @@ | |||
60 | #include <linux/tty.h> | 60 | #include <linux/tty.h> |
61 | #include <linux/proc_fs.h> | 61 | #include <linux/proc_fs.h> |
62 | #include <linux/blkdev.h> | 62 | #include <linux/blkdev.h> |
63 | #include <linux/fs_struct.h> | ||
63 | #include <trace/sched.h> | 64 | #include <trace/sched.h> |
64 | #include <linux/magic.h> | 65 | #include <linux/magic.h> |
65 | 66 | ||
@@ -284,7 +285,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) | |||
284 | mm->free_area_cache = oldmm->mmap_base; | 285 | mm->free_area_cache = oldmm->mmap_base; |
285 | mm->cached_hole_size = ~0UL; | 286 | mm->cached_hole_size = ~0UL; |
286 | mm->map_count = 0; | 287 | mm->map_count = 0; |
287 | cpus_clear(mm->cpu_vm_mask); | 288 | cpumask_clear(mm_cpumask(mm)); |
288 | mm->mm_rb = RB_ROOT; | 289 | mm->mm_rb = RB_ROOT; |
289 | rb_link = &mm->mm_rb.rb_node; | 290 | rb_link = &mm->mm_rb.rb_node; |
290 | rb_parent = NULL; | 291 | rb_parent = NULL; |
@@ -644,6 +645,9 @@ static int copy_mm(unsigned long clone_flags, struct task_struct * tsk) | |||
644 | 645 | ||
645 | tsk->min_flt = tsk->maj_flt = 0; | 646 | tsk->min_flt = tsk->maj_flt = 0; |
646 | tsk->nvcsw = tsk->nivcsw = 0; | 647 | tsk->nvcsw = tsk->nivcsw = 0; |
648 | #ifdef CONFIG_DETECT_HUNG_TASK | ||
649 | tsk->last_switch_count = tsk->nvcsw + tsk->nivcsw; | ||
650 | #endif | ||
647 | 651 | ||
648 | tsk->mm = NULL; | 652 | tsk->mm = NULL; |
649 | tsk->active_mm = NULL; | 653 | tsk->active_mm = NULL; |
@@ -681,38 +685,21 @@ fail_nomem: | |||
681 | return retval; | 685 | return retval; |
682 | } | 686 | } |
683 | 687 | ||
684 | static struct fs_struct *__copy_fs_struct(struct fs_struct *old) | ||
685 | { | ||
686 | struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL); | ||
687 | /* We don't need to lock fs - think why ;-) */ | ||
688 | if (fs) { | ||
689 | atomic_set(&fs->count, 1); | ||
690 | rwlock_init(&fs->lock); | ||
691 | fs->umask = old->umask; | ||
692 | read_lock(&old->lock); | ||
693 | fs->root = old->root; | ||
694 | path_get(&old->root); | ||
695 | fs->pwd = old->pwd; | ||
696 | path_get(&old->pwd); | ||
697 | read_unlock(&old->lock); | ||
698 | } | ||
699 | return fs; | ||
700 | } | ||
701 | |||
702 | struct fs_struct *copy_fs_struct(struct fs_struct *old) | ||
703 | { | ||
704 | return __copy_fs_struct(old); | ||
705 | } | ||
706 | |||
707 | EXPORT_SYMBOL_GPL(copy_fs_struct); | ||
708 | |||
709 | static int copy_fs(unsigned long clone_flags, struct task_struct *tsk) | 688 | static int copy_fs(unsigned long clone_flags, struct task_struct *tsk) |
710 | { | 689 | { |
690 | struct fs_struct *fs = current->fs; | ||
711 | if (clone_flags & CLONE_FS) { | 691 | if (clone_flags & CLONE_FS) { |
712 | atomic_inc(¤t->fs->count); | 692 | /* tsk->fs is already what we want */ |
693 | write_lock(&fs->lock); | ||
694 | if (fs->in_exec) { | ||
695 | write_unlock(&fs->lock); | ||
696 | return -EAGAIN; | ||
697 | } | ||
698 | fs->users++; | ||
699 | write_unlock(&fs->lock); | ||
713 | return 0; | 700 | return 0; |
714 | } | 701 | } |
715 | tsk->fs = __copy_fs_struct(current->fs); | 702 | tsk->fs = copy_fs_struct(fs); |
716 | if (!tsk->fs) | 703 | if (!tsk->fs) |
717 | return -ENOMEM; | 704 | return -ENOMEM; |
718 | return 0; | 705 | return 0; |
@@ -813,6 +800,12 @@ static void posix_cpu_timers_init_group(struct signal_struct *sig) | |||
813 | sig->cputime_expires.virt_exp = cputime_zero; | 800 | sig->cputime_expires.virt_exp = cputime_zero; |
814 | sig->cputime_expires.sched_exp = 0; | 801 | sig->cputime_expires.sched_exp = 0; |
815 | 802 | ||
803 | if (sig->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) { | ||
804 | sig->cputime_expires.prof_exp = | ||
805 | secs_to_cputime(sig->rlim[RLIMIT_CPU].rlim_cur); | ||
806 | sig->cputimer.running = 1; | ||
807 | } | ||
808 | |||
816 | /* The timer lists. */ | 809 | /* The timer lists. */ |
817 | INIT_LIST_HEAD(&sig->cpu_timers[0]); | 810 | INIT_LIST_HEAD(&sig->cpu_timers[0]); |
818 | INIT_LIST_HEAD(&sig->cpu_timers[1]); | 811 | INIT_LIST_HEAD(&sig->cpu_timers[1]); |
@@ -828,11 +821,8 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) | |||
828 | atomic_inc(¤t->signal->live); | 821 | atomic_inc(¤t->signal->live); |
829 | return 0; | 822 | return 0; |
830 | } | 823 | } |
831 | sig = kmem_cache_alloc(signal_cachep, GFP_KERNEL); | ||
832 | |||
833 | if (sig) | ||
834 | posix_cpu_timers_init_group(sig); | ||
835 | 824 | ||
825 | sig = kmem_cache_alloc(signal_cachep, GFP_KERNEL); | ||
836 | tsk->signal = sig; | 826 | tsk->signal = sig; |
837 | if (!sig) | 827 | if (!sig) |
838 | return -ENOMEM; | 828 | return -ENOMEM; |
@@ -841,6 +831,8 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) | |||
841 | atomic_set(&sig->live, 1); | 831 | atomic_set(&sig->live, 1); |
842 | init_waitqueue_head(&sig->wait_chldexit); | 832 | init_waitqueue_head(&sig->wait_chldexit); |
843 | sig->flags = 0; | 833 | sig->flags = 0; |
834 | if (clone_flags & CLONE_NEWPID) | ||
835 | sig->flags |= SIGNAL_UNKILLABLE; | ||
844 | sig->group_exit_code = 0; | 836 | sig->group_exit_code = 0; |
845 | sig->group_exit_task = NULL; | 837 | sig->group_exit_task = NULL; |
846 | sig->group_stop_count = 0; | 838 | sig->group_stop_count = 0; |
@@ -870,6 +862,8 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) | |||
870 | memcpy(sig->rlim, current->signal->rlim, sizeof sig->rlim); | 862 | memcpy(sig->rlim, current->signal->rlim, sizeof sig->rlim); |
871 | task_unlock(current->group_leader); | 863 | task_unlock(current->group_leader); |
872 | 864 | ||
865 | posix_cpu_timers_init_group(sig); | ||
866 | |||
873 | acct_init_pacct(&sig->pacct); | 867 | acct_init_pacct(&sig->pacct); |
874 | 868 | ||
875 | tty_audit_fork(sig); | 869 | tty_audit_fork(sig); |
@@ -1046,11 +1040,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1046 | 1040 | ||
1047 | p->default_timer_slack_ns = current->timer_slack_ns; | 1041 | p->default_timer_slack_ns = current->timer_slack_ns; |
1048 | 1042 | ||
1049 | #ifdef CONFIG_DETECT_SOFTLOCKUP | ||
1050 | p->last_switch_count = 0; | ||
1051 | p->last_switch_timestamp = 0; | ||
1052 | #endif | ||
1053 | |||
1054 | task_io_accounting_init(&p->ioac); | 1043 | task_io_accounting_init(&p->ioac); |
1055 | acct_clear_integrals(p); | 1044 | acct_clear_integrals(p); |
1056 | 1045 | ||
@@ -1125,7 +1114,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1125 | goto bad_fork_cleanup_mm; | 1114 | goto bad_fork_cleanup_mm; |
1126 | if ((retval = copy_io(clone_flags, p))) | 1115 | if ((retval = copy_io(clone_flags, p))) |
1127 | goto bad_fork_cleanup_namespaces; | 1116 | goto bad_fork_cleanup_namespaces; |
1128 | retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); | 1117 | retval = copy_thread(clone_flags, stack_start, stack_size, p, regs); |
1129 | if (retval) | 1118 | if (retval) |
1130 | goto bad_fork_cleanup_io; | 1119 | goto bad_fork_cleanup_io; |
1131 | 1120 | ||
@@ -1263,8 +1252,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1263 | p->signal->leader_pid = pid; | 1252 | p->signal->leader_pid = pid; |
1264 | tty_kref_put(p->signal->tty); | 1253 | tty_kref_put(p->signal->tty); |
1265 | p->signal->tty = tty_kref_get(current->signal->tty); | 1254 | p->signal->tty = tty_kref_get(current->signal->tty); |
1266 | set_task_pgrp(p, task_pgrp_nr(current)); | ||
1267 | set_task_session(p, task_session_nr(current)); | ||
1268 | attach_pid(p, PIDTYPE_PGID, task_pgrp(current)); | 1255 | attach_pid(p, PIDTYPE_PGID, task_pgrp(current)); |
1269 | attach_pid(p, PIDTYPE_SID, task_session(current)); | 1256 | attach_pid(p, PIDTYPE_SID, task_session(current)); |
1270 | list_add_tail_rcu(&p->tasks, &init_task.tasks); | 1257 | list_add_tail_rcu(&p->tasks, &init_task.tasks); |
@@ -1488,6 +1475,7 @@ void __init proc_caches_init(void) | |||
1488 | mm_cachep = kmem_cache_create("mm_struct", | 1475 | mm_cachep = kmem_cache_create("mm_struct", |
1489 | sizeof(struct mm_struct), ARCH_MIN_MMSTRUCT_ALIGN, | 1476 | sizeof(struct mm_struct), ARCH_MIN_MMSTRUCT_ALIGN, |
1490 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); | 1477 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); |
1478 | vm_area_cachep = KMEM_CACHE(vm_area_struct, SLAB_PANIC); | ||
1491 | mmap_init(); | 1479 | mmap_init(); |
1492 | } | 1480 | } |
1493 | 1481 | ||
@@ -1543,12 +1531,16 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp) | |||
1543 | { | 1531 | { |
1544 | struct fs_struct *fs = current->fs; | 1532 | struct fs_struct *fs = current->fs; |
1545 | 1533 | ||
1546 | if ((unshare_flags & CLONE_FS) && | 1534 | if (!(unshare_flags & CLONE_FS) || !fs) |
1547 | (fs && atomic_read(&fs->count) > 1)) { | 1535 | return 0; |
1548 | *new_fsp = __copy_fs_struct(current->fs); | 1536 | |
1549 | if (!*new_fsp) | 1537 | /* don't need lock here; in the worst case we'll do useless copy */ |
1550 | return -ENOMEM; | 1538 | if (fs->users == 1) |
1551 | } | 1539 | return 0; |
1540 | |||
1541 | *new_fsp = copy_fs_struct(fs); | ||
1542 | if (!*new_fsp) | ||
1543 | return -ENOMEM; | ||
1552 | 1544 | ||
1553 | return 0; | 1545 | return 0; |
1554 | } | 1546 | } |
@@ -1664,8 +1656,13 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) | |||
1664 | 1656 | ||
1665 | if (new_fs) { | 1657 | if (new_fs) { |
1666 | fs = current->fs; | 1658 | fs = current->fs; |
1659 | write_lock(&fs->lock); | ||
1667 | current->fs = new_fs; | 1660 | current->fs = new_fs; |
1668 | new_fs = fs; | 1661 | if (--fs->users) |
1662 | new_fs = NULL; | ||
1663 | else | ||
1664 | new_fs = fs; | ||
1665 | write_unlock(&fs->lock); | ||
1669 | } | 1666 | } |
1670 | 1667 | ||
1671 | if (new_mm) { | 1668 | if (new_mm) { |
@@ -1704,7 +1701,7 @@ bad_unshare_cleanup_sigh: | |||
1704 | 1701 | ||
1705 | bad_unshare_cleanup_fs: | 1702 | bad_unshare_cleanup_fs: |
1706 | if (new_fs) | 1703 | if (new_fs) |
1707 | put_fs_struct(new_fs); | 1704 | free_fs_struct(new_fs); |
1708 | 1705 | ||
1709 | bad_unshare_cleanup_thread: | 1706 | bad_unshare_cleanup_thread: |
1710 | bad_unshare_out: | 1707 | bad_unshare_out: |